openyida 2026.9.23-beta.2 → 2026.9.24-beta.0
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 +18 -34
- package/bin/yida.js +26 -34
- package/lib/app/app-entry.js +144 -0
- package/lib/app/app-list.js +1 -0
- package/lib/app/application-style.js +67 -0
- package/lib/app/canvas-compile.js +7 -1
- package/lib/app/canvas-theme-guard.js +127 -10
- package/lib/app/check-prd-completeness.js +4 -15
- package/lib/app/compile.js +12 -2
- package/lib/app/create-form/args.js +37 -12
- package/lib/app/create-form/batch.js +41 -35
- package/lib/app/create-form.js +94 -57
- package/lib/app/custom-theme.js +30 -37
- package/lib/app/fix-theme.js +34 -0
- package/lib/app/form-field-validator.js +0 -36
- package/lib/app/get-schema.js +1 -6
- package/lib/app/publish.js +49 -7
- package/lib/app/services/canvas-page-compiler.js +3 -1
- package/lib/app/services/form-compiler.js +0 -2
- package/lib/app/theme-from-design.js +77 -87
- package/lib/app/theme-scope.js +76 -0
- package/lib/app/update-app.js +64 -26
- package/lib/app/update-form-config.js +9 -19
- package/lib/auth/oauth-device.js +311 -0
- package/lib/auth/token-auth.js +81 -79
- package/lib/auth/token-store.js +2 -26
- package/lib/core/cli-error.js +1 -0
- package/lib/core/command-manifest.js +122 -49
- package/lib/core/locales/en.js +61 -54
- package/lib/core/locales/zh.js +61 -54
- package/lib/core/sample.js +36 -14
- package/lib/core/source-repair.js +38 -0
- package/lib/core/theme-brand-scale.js +133 -0
- package/lib/core/update.js +1 -3
- package/lib/core/utils.js +0 -29
- package/lib/design/check-design.js +16 -6
- package/lib/design/document.js +37 -15
- package/lib/design/icon-contrast.js +1 -1
- package/lib/design/palette-contrast.js +77 -0
- package/lib/design-plan/confirmation.js +13 -0
- package/lib/design-plan/design-plan.js +65 -8
- package/lib/design-plan/entry-navigation.js +10 -2
- package/lib/design-plan/init.js +17 -10
- package/lib/design-plan/materialize.js +88 -58
- 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/preview.js +4 -1
- package/lib/design-plan/rebase.js +69 -0
- package/lib/design-plan/themes.js +16 -1
- package/lib/design-plan/validate.js +18 -3
- package/lib/design-plan/visual-policy.js +29 -4
- package/lib/page-config/save-share-config.js +5 -16
- 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 +3 -11
- package/yida-skills/SKILL.md +3 -25
- package/yida-skills/references/official-example-schema-patterns.md +1 -1
- package/yida-skills/references/source-repair.md +10 -0
- 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 +3 -1
- package/yida-skills/skills/yida-app/workflow/plan/workflow.md +21 -5
- package/yida-skills/skills/yida-app/workflow/step-2-design.md +4 -4
- 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 +25 -2
- package/yida-skills/skills/yida-canvas-custom-page/SKILL.md +3 -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 +4 -2
- 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/references/waf-safe-authoring.md +45 -0
- package/yida-skills/skills/yida-canvas-custom-page/scripts/build-canvas-theme.js +2 -1
- package/yida-skills/skills/yida-canvas-custom-page/scripts/canvas-theme-provider.template.jsx +8 -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 +16 -8
- package/yida-skills/skills/yida-design/references/application-style-library.md +93 -0
- package/yida-skills/skills/yida-design/references/application-theme-consistency.md +92 -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 +8 -6
- package/yida-skills/skills/yida-design/references/theme/app-custom-theme-template.css +136 -113
- 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 +52 -7
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/SKILL.md +15 -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/design-themes/README.md +17 -10
- package/yida-skills/skills/yida-design/templates/design-themes/app-amber/app_theme.css +570 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-amber/design.md +238 -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 +570 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-editorial/design.md +239 -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 +570 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-executive/design.md +239 -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 +570 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-finance/design.md +238 -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 +570 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-glass/design.md +239 -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 +570 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-graphite/design.md +239 -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 +570 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-line/design.md +239 -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 +570 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-neon/design.md +237 -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 +570 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-nordic/design.md +239 -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 +570 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-paper/design.md +237 -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 +570 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-platinum/design.md +239 -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 +570 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-plum/design.md +239 -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 +570 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-pop/design.md +239 -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 +570 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-sage/design.md +239 -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 +570 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-teal/design.md +239 -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 +570 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-terminal/design.md +238 -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 +570 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-ticket/design.md +241 -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 +570 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-wire/design.md +238 -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 +1 -7
- package/yida-skills/skills/yida-design/templates/design-themes/dark-inset-hairline/app_theme.css +509 -0
- package/yida-skills/skills/yida-design/templates/design-themes/{dark-inset-hairline.md → dark-inset-hairline/design.md} +97 -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 +517 -0
- package/yida-skills/skills/yida-design/templates/design-themes/{dark-rail-fine-lines.md → dark-rail-fine-lines/design.md} +98 -51
- 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 +515 -0
- package/yida-skills/skills/yida-design/templates/design-themes/{dark-rail-signal-panels.md → dark-rail-signal-panels/design.md} +59 -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 +511 -0
- package/yida-skills/skills/yida-design/templates/design-themes/free-creative/design.md +202 -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 +511 -0
- package/yida-skills/skills/yida-design/templates/design-themes/{graphite-bevel-grid.md → graphite-bevel-grid/design.md} +55 -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 +510 -0
- package/yida-skills/skills/yida-design/templates/design-themes/{hairline-shared-bands.md → hairline-shared-bands/design.md} +57 -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 +510 -0
- package/yida-skills/skills/yida-design/templates/design-themes/{hairline-soft-blocks.md → hairline-soft-blocks/design.md} +52 -10
- 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 +520 -0
- package/yida-skills/skills/yida-design/templates/design-themes/{ink-glow-soft-panels.md → ink-glow-soft-panels/design.md} +53 -9
- 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 +510 -0
- package/yida-skills/skills/yida-design/templates/design-themes/{inset-frame-pixel-rhythm.md → inset-frame-pixel-rhythm/design.md} +55 -10
- 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 +517 -0
- package/yida-skills/skills/yida-design/templates/design-themes/{outlined-texture-duotone.md → outlined-texture-duotone/design.md} +56 -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 +510 -0
- package/yida-skills/skills/yida-design/templates/design-themes/{soft-inset-surfaces.md → soft-inset-surfaces/design.md} +54 -12
- 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 +509 -0
- package/yida-skills/skills/yida-design/templates/design-themes/{soft-outline-rhythm.md → soft-outline-rhythm/design.md} +54 -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 +517 -0
- package/yida-skills/skills/yida-design/templates/design-themes/{soft-rail-bold-band.md → soft-rail-bold-band/design.md} +94 -50
- 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 +511 -0
- package/yida-skills/skills/yida-design/templates/design-themes/{soft-spectral-panels.md → soft-spectral-panels/design.md} +59 -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 +530 -0
- package/yida-skills/skills/yida-design/templates/design-themes/{warm-canvas-contrast-panels.md → warm-canvas-contrast-panels/design.md} +55 -11
- 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 +511 -0
- package/yida-skills/skills/yida-design/templates/design-themes/{warm-rail-muted-panels.md → warm-rail-muted-panels/design.md} +94 -52
- package/yida-skills/skills/yida-design/templates/design-themes/warm-rail-muted-panels/form-layout.json +13 -0
- package/yida-skills/skills/yida-design/workflow/output-design.md +44 -8
- package/yida-skills/skills/yida-design/workflow/step-2-theme-system.md +18 -5
- package/yida-skills/skills/yida-design/workflow/step-6-handoff.md +3 -1
- package/yida-skills/skills/yida-document-markdown/SKILL.md +0 -6
- package/yida-skills/skills/yida-export-conversation/SKILL.md +0 -1
- package/yida-skills/skills/yida-form-permission/SKILL.md +6 -0
- package/yida-skills/skills/yida-nav-shell/SKILL.md +5 -3
- 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 +2 -1
- 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-publish-page/SKILL.md +22 -18
- package/yida-skills/skills/yida-requirement-analysis/references/experience-groups.md +45 -9
- package/yida-skills/skills/yida-requirement-analysis/references/handoff.md +6 -6
- package/yida-skills/skills/yida-requirement-analysis/workflow/prepare-brief.md +17 -4
- package/yida-skills/skills/yida-tingji/SKILL.md +0 -4
- package/yida-skills/skills-index.json +4 -4
- package/lib/agent/PROTOCOL.md +0 -165
- package/lib/agent/ask-human.js +0 -151
- package/lib/agent/cmd.js +0 -403
- package/lib/agent/command-receipt.js +0 -84
- package/lib/agent/connection-store.js +0 -148
- package/lib/agent/diagnostic-log.js +0 -133
- package/lib/agent/frozen-bundle.js +0 -286
- package/lib/agent/managed-command-map.js +0 -117
- package/lib/agent/managed-context.js +0 -40
- package/lib/agent/managed-run.js +0 -96
- package/lib/agent/mutation-receipt.js +0 -82
- package/lib/agent/private-directory.js +0 -63
- package/lib/agent/provider-preflight.js +0 -236
- package/lib/agent/providers.js +0 -4
- package/lib/agent/runtime-catalog.json +0 -42
- package/lib/agent/runtime-manifest.js +0 -96
- package/lib/agent/runtime-package.js +0 -155
- package/lib/agent/stdio.js +0 -265
- package/lib/auth/profile-lock.js +0 -89
- package/yida-skills/references/local-agent-diagnostics.md +0 -154
- package/yida-skills/references/local-agent-preflight.md +0 -56
package/README.md
CHANGED
|
@@ -74,10 +74,17 @@ openyida login
|
|
|
74
74
|
|
|
75
75
|
OpenYida login defaults to OAuth token mode. It opens the DingTalk OAuth authorization page, receives the local loopback callback, exchanges `code` / `authCode` with the Yida server, and stores `access_token` / `refresh_token` in the user auth store when available. If the user auth store is not writable, OpenYida explicitly falls back to the current project cache and reports that narrower persistence scope.
|
|
76
76
|
|
|
77
|
+
In a sandbox, headless shell, or CI dashboard where the loopback callback cannot complete, use the device authorization flow. Open the displayed verification URL on any device and enter the user code. `--env-hint` optionally pins the intended environment profile at authorization time:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
openyida login --device
|
|
81
|
+
openyida login --device --env-hint pre
|
|
82
|
+
```
|
|
83
|
+
|
|
77
84
|
When the user names a target Yida entry URL, pass it to the login command so OpenYida can select the matching environment and auth profile. For example:
|
|
78
85
|
|
|
79
86
|
```bash
|
|
80
|
-
openyida login https
|
|
87
|
+
openyida login https://<your-yida-entry-url>/
|
|
81
88
|
openyida login --alibaba
|
|
82
89
|
```
|
|
83
90
|
|
|
@@ -118,6 +125,7 @@ The agent can then call OpenYida commands to create the application, generate so
|
|
|
118
125
|
| [Codex](https://openai.com/codex/) | Full support |
|
|
119
126
|
| [Claude Code](https://claude.ai/code) | Full support |
|
|
120
127
|
| [MuleRun](https://mulerun.com) | Full support |
|
|
128
|
+
| [OpenCode](https://opencode.ai) | Full support |
|
|
121
129
|
| [Cursor](https://cursor.com/) | Full support |
|
|
122
130
|
| [Visual Studio Code](https://code.visualstudio.com/) | Full support |
|
|
123
131
|
| QwenWork(千问办公) | Full support |
|
|
@@ -182,7 +190,7 @@ openyida get-schema APP_XXX FORM_XXX --compact --resolve-fields "Customer Name,S
|
|
|
182
190
|
openyida get-schema APP_XXX --all --output-dir .cache/schemas
|
|
183
191
|
```
|
|
184
192
|
|
|
185
|
-
|
|
193
|
+
Native forms use a component tree: business fields capture data, tabs switch content, action groups trigger business actions, images establish visual focus, status areas provide feedback, and `Divider` plus `ColumnContainer` organize hierarchy and columns. `create-form` field definitions create 19 business field types plus `Divider` and `ColumnContainer` (mapped to `ColumnsLayout` + `Column`), while updates retain other existing components.
|
|
186
194
|
|
|
187
195
|
### Custom Page Development
|
|
188
196
|
|
|
@@ -382,7 +390,7 @@ Run `openyida --help` or `openyida <command> --help` for detailed usage.
|
|
|
382
390
|
|
|
383
391
|
| Command | Description |
|
|
384
392
|
|---------|-------------|
|
|
385
|
-
| `openyida login [target-url] [--env <name>\|--intl\|--overseas\|--global\|--yidaapps\|--alibaba] [--client-id <clientId>] [--endpoint <url>] [--no-browser]` | Login with OAuth token mode |
|
|
393
|
+
| `openyida login [target-url] [--env <name>\|--intl\|--overseas\|--global\|--yidaapps\|--alibaba] [--client-id <clientId>] [--endpoint <url>] [--no-browser] [--device] [--env-hint <name>]` | Login with OAuth token mode |
|
|
386
394
|
| `openyida logout` | Logout / unbind current project auth |
|
|
387
395
|
| `openyida auth <status\|login\|refresh\|logout\|profiles\|profile switch>` | Token login state and profile management |
|
|
388
396
|
| `openyida org <list\|switch> [--json] [--corp-id <corpId>]` | Organization management (list / switch existing profiles first) |
|
|
@@ -392,13 +400,15 @@ Run `openyida --help` or `openyida <command> --help` for detailed usage.
|
|
|
392
400
|
|
|
393
401
|
| Command | Description |
|
|
394
402
|
|---------|-------------|
|
|
403
|
+
| `openyida app-entry get <appType> [--json]` | Read frontend and management runtime entries |
|
|
404
|
+
| `openyida app-entry set <appType> [--frontend <url>\|--frontend-page <formUuid>] [--management <url>\|--management-page <formUuid>] [--clear-frontend] [--clear-management] [--json]` | Register application entries with partial update and readback |
|
|
395
405
|
| `openyida app-list [--type managed\|created] [--page N] [--size N]` | Page through apps I manage or created |
|
|
396
406
|
| `openyida corp-efficiency [overview\|details\|detail\|groups\|notify] [options] [--open\|--no-open]` | Query enterprise efficiency overview and detail reports |
|
|
397
407
|
| `openyida create-app "<name>"\|--name <name> [options] [--locale zh_CN\|en_US\|ja_JP] [--open\|--no-open]` | Create a Yida app |
|
|
398
408
|
| `openyida design-plan catalog [--json]` | List available planning themes and page patterns |
|
|
399
409
|
| `openyida design-plan init <requirement-brief.json> [--theme-id <id>] [--output-dir <dir>] [--json]` | Initialize a plan draft from confirmed requirements |
|
|
400
410
|
| `openyida design-plan preview <build-plan.json> --part-file <module.json> [--json]` | Update plan drafts by module |
|
|
401
|
-
| `openyida design-plan materialize <build-plan.json> [--from-preview \| --business-file <json> --visual-file <json>] [--output-dir <dir>] [--check] [--json]` | Generate or update plan documents and theme with consistency checks |
|
|
411
|
+
| `openyida design-plan materialize <build-plan.json> [--from-preview \| --business-file <json> --visual-file <json>] [--output-dir <dir>] [--rebase-parts] [--check] [--json]` | Generate or update plan documents and theme with consistency checks |
|
|
402
412
|
| `openyida design-plan patch <build-plan.json> --set <path=value> [--set <path=value> ...] [--materialize] [--output-dir <dir>] [--json]` | Patch plan fields and optionally sync documents and theme |
|
|
403
413
|
| `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 |
|
|
404
414
|
| `openyida app-online <appType> [--to-ding-app-center] [--show-app-center]` | Enable a Yida app |
|
|
@@ -414,7 +424,7 @@ Run `openyida --help` or `openyida <command> --help` for detailed usage.
|
|
|
414
424
|
| Command | Description |
|
|
415
425
|
|---------|-------------|
|
|
416
426
|
| `openyida create-form batch <appType> <plan.json> [--concurrency 1..4] [--check] [--json]` | Create forms concurrently by dependency |
|
|
417
|
-
| `openyida create-form create <appType> "<formTitle>" <fieldsJsonFile> [--icon auto\|<iconName>] [--locale zh_CN\|en_US\|ja_JP] [--open\|--no-open]` | Create a form page |
|
|
427
|
+
| `openyida create-form create <appType> "<formTitle>" <fieldsJsonFile> [--layout single\|double\|card\|section] [--theme default\|compact\|comfortable] [--label-align top\|left\|right] [--icon auto\|<iconName>] [--locale zh_CN\|en_US\|ja_JP] [--open\|--no-open]` | Create a form page |
|
|
418
428
|
| `openyida create-form icons [--json]` | List available form navigation icons |
|
|
419
429
|
| `openyida create-form validate-fields <fieldsJsonOrFile> [--json]` | Validate form field JSON locally |
|
|
420
430
|
| `openyida create-form update <appType> <formUuid> (<changesJsonOrFile> \| --data-file <changesJsonOrFile>) [--locale zh_CN\|en_US\|ja_JP] [--open\|--no-open]` | Update a form page |
|
|
@@ -434,8 +444,8 @@ Run `openyida --help` or `openyida <command> --help` for detailed usage.
|
|
|
434
444
|
| `openyida create-page <appType> "<name>" [--mode dashboard] [--hide-nav] [--locale zh_CN\|en_US\|ja_JP] [--open\|--no-open]` | Create a custom display page |
|
|
435
445
|
| `openyida build-page <sourceFile> [--output file\|--write]` | Build Yida-compatible page source |
|
|
436
446
|
| `openyida check-page <src> [--compat] [--json]` | Check custom page standards |
|
|
437
|
-
| `openyida compile <src> [--canvas] [--compat] [--skip-lint] [--json]` | Compile custom page locally |
|
|
438
|
-
| `openyida publish <src> <appType> <formUuid> [--health-check] [--force] [--canvas] [--compat] [--skip-lint] [--auto-nav-order] [--open\|--no-open] [--json]` | Compile and publish custom page |
|
|
447
|
+
| `openyida compile <src> [--canvas] [--compat] [--skip-lint] [--strict-theme\|--allow-fixed-brand] [--json]` | Compile custom page locally |
|
|
448
|
+
| `openyida publish <src> <appType> <formUuid> [--health-check] [--force] [--canvas] [--compat] [--skip-lint] [--fix-theme] [--strict-theme] [--allow-fixed-brand] [--auto-nav-order] [--open\|--no-open] [--json]` | Compile and publish custom page |
|
|
439
449
|
| `openyida update-form-config <appType> <formUuid> <true\|false\|keep> "<title>" [--locale zh_CN\|en_US\|ja_JP]` | Update form configuration |
|
|
440
450
|
| `openyida get-form-config <appType> <formUuid> [--json]` | Query form configuration |
|
|
441
451
|
|
|
@@ -519,11 +529,10 @@ Run `openyida --help` or `openyida <command> --help` for detailed usage.
|
|
|
519
529
|
|---------|-------------|
|
|
520
530
|
| `openyida commands [--json]` | Output machine-readable command manifest |
|
|
521
531
|
| `openyida agent-capabilities [--json] [--summary-json\|--compact]` | Output one-shot agent capability snapshot |
|
|
522
|
-
| `openyida agent <doctor\|diagnose\|status\|connect\|run\|disconnect\|logout> [options]` | Connect a local Agent (Go runtime, development preview) |
|
|
523
532
|
| `openyida a2a <serve\|agent-card> [options]` | Start local read-only A2A adapter or print Agent Card |
|
|
524
533
|
| `openyida bridge start [--token <pair-token>] [--port 6736] [--origin https://demo.aliwork.com] [--open\|--no-open]` | Start OpenYida local web bridge service |
|
|
525
534
|
| `openyida copy [--force]` | Copy project working directory |
|
|
526
|
-
| `openyida sample [--list] [<skill> <name>] [--output <file>] [--var KEY=VALUE ...] [--design-file <design.md>]` | Output code samples/templates |
|
|
535
|
+
| `openyida sample [--list] [<skill> <name>] [--output <file-or-directory>] [--var KEY=VALUE ...] [--design-file <design.md>] [--style-id <themeId\|free-creative>]` | Output code samples/templates |
|
|
527
536
|
| `openyida doctor [--fix]` | Environment diagnostics & auto-fix |
|
|
528
537
|
| `openyida db-seq-fix [--fix]` | Detect and repair PostgreSQL sequence drift |
|
|
529
538
|
| `openyida formula evaluate <formula\|file> [--schema file]` | Static-check Yida formula syntax and field refs |
|
|
@@ -588,31 +597,6 @@ Form field definitions can include `alias` or `componentAlias` to populate Yida
|
|
|
588
597
|
|
|
589
598
|
`openyida integration create` supports form events (`insert`, `update`, `delete`, `comment`) and approval events (`processFinish`, `activityTask`; aliases: `approval`, `approvalNode`). Approval events require `--approval-actions agree,disagree,terminated`; `activityTask` also requires `--approval-node-ids <nodeId,...>`. Passing `--process-code` selects a full graph replacement and now requires explicit `--replace`; it is not a safe update. `integration update` currently performs capability detection only: because full platform `processJson` + `viewJson` readback is unproven, it writes a redacted local probe artifact and returns `PLATFORM_PROBE_REQUIRED` before authentication, spec reading, or remote writes. It does not edit a flow.
|
|
590
599
|
|
|
591
|
-
### Local Agent development preview
|
|
592
|
-
|
|
593
|
-
`openyida agent` is a thin Node launcher for a separately supplied Go runtime. Node does not connect to the agent service or manage provider sessions. Platform runtime packages are **not published** in this preview; no Go executable is discovered on `PATH` and no provider is installed or invoked by Node.
|
|
594
|
-
|
|
595
|
-
The Local Agent Beta production allowlist contains macOS and Windows only. Linux remains supported by the ordinary OpenYida CLI and by the explicit development-runtime workflow below, but Linux Local Agent packages are not published and production `connect`/`run` are rejected until native acceptance is complete.
|
|
596
|
-
|
|
597
|
-
```bash
|
|
598
|
-
openyida agent doctor --json
|
|
599
|
-
openyida agent doctor --development-runtime --runtime-path /absolute/path/openyida-runtime --runtime-manifest /absolute/path/runtime-manifest.json
|
|
600
|
-
openyida agent connect --development-runtime --runtime-path /absolute/path/openyida-runtime --runtime-manifest /absolute/path/runtime-manifest.json --endpoint https://agent.example.test --endpoint-id configured-platform-id
|
|
601
|
-
openyida agent run --development-runtime --runtime-path /absolute/path/openyida-runtime --runtime-manifest /absolute/path/runtime-manifest.json --endpoint https://agent.example.test --endpoint-id configured-platform-id --provider qoder --provider-path /absolute/path/qodercli
|
|
602
|
-
```
|
|
603
|
-
|
|
604
|
-
Development manifest v1 specifies runtime version, protocol `1`, Node-style OS/architecture names, and `binary: {file, sha256}`; it requires the explicit `--development-runtime` flag. This is an integrity check, **not a publisher signature**. The production loader requires a strictly validated v2 manifest, exact approved platform-package version/digest, and an Ed25519 signature over the original manifest bytes using trust roots bundled in the Node host. The release catalog is currently empty: no production signing key or package is implied to exist. See the [launcher contract](lib/agent/PROTOCOL.md).
|
|
605
|
-
|
|
606
|
-
`connect` supports two equivalent enrollment entries. CLI-first opens the Yida browser approval page and returns through a state/PKCE-protected loopback callback. Web-first copies one five-minute command containing `--enroll`; the token is single-use and carries no business authority. Neither path reads or uploads an ordinary OpenYida login profile.
|
|
607
|
-
|
|
608
|
-
One installation may connect to multiple organizations. Node keeps only a shared Installation ID at the installation root; each organization authorization gets an isolated private Connection state directory, device credentials, journals, control socket, and frozen bundle. `agent connect` keeps the new Connection online in the foreground, while `agent run`, `status`, `disconnect`, and `logout` enumerate every valid Connection. Each Connection registers all locally discovered Qoder and Codex Runtimes, and the web UI selects computer, CLI, and model.
|
|
609
|
-
|
|
610
|
-
For each attempt, Go injects `OPENYIDA_MANAGED_RUN=1`, the cloud user/corp/app/run/attempt context, and a fixed-value Tianshu task grant with an initial 60-minute lease. The CLI uses that grant instead of local auth and sends scope-correlation headers. While the authenticated device connection and server-side Run remain active, yida-agent can renew the same bearer server-to-server; the CLI cannot renew it and never receives a task refresh token. Tianshu independently checks the grant against the requested app and rejects application creation, identity/environment changes, arbitrary batches, and cross-application requests. `formUuid` remains optional per-turn page-focus context, so one app-bound session can work across pages in that application. Without `OPENYIDA_MANAGED_RUN`, existing login, token refresh, and command behavior are unchanged.
|
|
611
|
-
|
|
612
|
-
Before `connect` or `run`, Node now freezes the verified runtime bytes, CLI, full production dependency closure, and packaged Skills into a private content-addressed bundle. Source changes during copying fail closed. Existing bundles are verified, never silently repaired or garbage-collected by Node, and survive replacement/removal of the original npm directory. Go owns active/session references and version activation; the external Node executable and provider installations are not copied or managed by npm. A separate parent-watch pipe and a 15-second stop grace prevent normal config EOF from being mistaken for parent death; an unconfirmed forced stop remains unknown.
|
|
613
|
-
|
|
614
|
-
This is not an OS sandbox or an authorization boundary against arbitrary shell code. Production signing/release infrastructure, full Go/provider recovery and upgrade acceptance, and OS/architecture-specific provider E2E are not claimed by these fake-process tests. Auto-update is disabled for `agent` and managed invocations; ordinary CLI commands neither spawn nor download the runtime.
|
|
615
|
-
|
|
616
600
|
## Agent Skills
|
|
617
601
|
|
|
618
602
|
The `yida-skills/` directory is the source skill library used by OpenYida during development and distributed with the npm package.
|
package/bin/yida.js
CHANGED
|
@@ -24,8 +24,6 @@ const { COMMAND_GROUPS, buildCommandManifest, findCommandSuggestion } = require(
|
|
|
24
24
|
const command = process.argv[2];
|
|
25
25
|
const args = process.argv.slice(3);
|
|
26
26
|
const rawArgs = process.argv.slice(3);
|
|
27
|
-
const { beginCommandReceipt } = require('../lib/agent/command-receipt');
|
|
28
|
-
let commandReceipt;
|
|
29
27
|
|
|
30
28
|
function shouldUseEnvManagement(argsList) {
|
|
31
29
|
const subCommand = argsList[0];
|
|
@@ -195,6 +193,7 @@ function printLoginResult(result) {
|
|
|
195
193
|
|
|
196
194
|
if (!result) {
|
|
197
195
|
console.log(JSON.stringify({
|
|
196
|
+
type: 'login_result',
|
|
198
197
|
ok: false,
|
|
199
198
|
status: 'login_failed',
|
|
200
199
|
can_auto_use: false,
|
|
@@ -207,6 +206,7 @@ function printLoginResult(result) {
|
|
|
207
206
|
? !!result.ok
|
|
208
207
|
: (result.can_auto_use !== false && !!result.access_token);
|
|
209
208
|
const summary = {
|
|
209
|
+
type: 'login_result',
|
|
210
210
|
ok: tokenUsable,
|
|
211
211
|
status: result.status || (tokenUsable ? 'ok' : 'token_not_issued'),
|
|
212
212
|
auth_mode: 'token',
|
|
@@ -281,6 +281,7 @@ function getFirstPositionalArg(cliArgs, startIndex = 0) {
|
|
|
281
281
|
'--login-url',
|
|
282
282
|
'--profile',
|
|
283
283
|
'--user-id',
|
|
284
|
+
'--env-hint',
|
|
284
285
|
]);
|
|
285
286
|
for (let index = startIndex; index < cliArgs.length; index++) {
|
|
286
287
|
const arg = cliArgs[index];
|
|
@@ -388,6 +389,7 @@ function applyLoginEnvironmentFlags(cliArgs, options = {}) {
|
|
|
388
389
|
'--client-id',
|
|
389
390
|
'--profile',
|
|
390
391
|
'--user-id',
|
|
392
|
+
'--env-hint',
|
|
391
393
|
]);
|
|
392
394
|
const targetUrlFlags = new Set([
|
|
393
395
|
'--endpoint',
|
|
@@ -539,13 +541,23 @@ function printLoginHelp() {
|
|
|
539
541
|
}
|
|
540
542
|
|
|
541
543
|
function buildTokenLoginOptions(loginArgs) {
|
|
544
|
+
const device = loginArgs.includes('--device');
|
|
542
545
|
return {
|
|
543
546
|
clientId: getArgValue(loginArgs, '--client-id'),
|
|
544
547
|
corpId: getArgValue(loginArgs, '--corp-id'),
|
|
545
548
|
userId: getArgValue(loginArgs, '--user-id'),
|
|
546
549
|
authProfile: getArgValue(loginArgs, '--profile'),
|
|
547
550
|
quiet: process.env.YIDA_QUIET === '1' || loginArgs.includes('--quiet'),
|
|
548
|
-
noBrowser: loginArgs.includes('--no-browser'),
|
|
551
|
+
noBrowser: device || loginArgs.includes('--no-browser'),
|
|
552
|
+
device,
|
|
553
|
+
envHint: getArgValue(loginArgs, '--env-hint'),
|
|
554
|
+
// Machine-readable progress events for agent runtimes (sandbox browsers,
|
|
555
|
+
// CI dashboards). Emits one JSON line per state transition.
|
|
556
|
+
onDeviceState: (state) => {
|
|
557
|
+
if (device) {
|
|
558
|
+
process.stdout.write(JSON.stringify({ type: 'device_login_state', ...state }) + '\n');
|
|
559
|
+
}
|
|
560
|
+
},
|
|
549
561
|
};
|
|
550
562
|
}
|
|
551
563
|
|
|
@@ -573,26 +585,6 @@ function assertNoUnsupportedLegacyLoginFlags(...argLists) {
|
|
|
573
585
|
}
|
|
574
586
|
|
|
575
587
|
async function main() {
|
|
576
|
-
const { assertManagedInvocation, resolveManagedHelp } = require('../lib/agent/managed-run');
|
|
577
|
-
const { readManagedContext } = require('../lib/agent/managed-context');
|
|
578
|
-
if (readManagedContext() && [command, ...rawArgs].some(arg => arg === '--help' || arg === '-h')) {
|
|
579
|
-
assertManagedInvocation(command, rawArgs);
|
|
580
|
-
const entries = resolveManagedHelp(command, rawArgs, { t, version: currentVersion });
|
|
581
|
-
// Managed help is static and local: no Receipt, auth, update, first-run
|
|
582
|
-
// guide or business command module may run on this path.
|
|
583
|
-
commandReceipt = { finish() {} };
|
|
584
|
-
if (rawArgs.includes('--json')) {
|
|
585
|
-
console.log(JSON.stringify({ name: 'openyida', version: currentVersion, commands: entries }, null, 2));
|
|
586
|
-
} else {
|
|
587
|
-
printCommandUsage(...entries.flatMap(entry => [entry.usage, entry.description, ...(entry.examples || [])]));
|
|
588
|
-
}
|
|
589
|
-
return;
|
|
590
|
-
}
|
|
591
|
-
commandReceipt = beginCommandReceipt({ command, args: rawArgs });
|
|
592
|
-
process.once('exit', code => {
|
|
593
|
-
try {commandReceipt.finish(code);} catch {process.exitCode = 1;}
|
|
594
|
-
});
|
|
595
|
-
assertManagedInvocation(command, rawArgs);
|
|
596
588
|
applyQuietFlag();
|
|
597
589
|
applyGlobalEnvironmentFlags();
|
|
598
590
|
|
|
@@ -641,12 +633,6 @@ async function main() {
|
|
|
641
633
|
break;
|
|
642
634
|
}
|
|
643
635
|
|
|
644
|
-
case 'agent': {
|
|
645
|
-
const { run } = require('../lib/agent/cmd');
|
|
646
|
-
await run(args);
|
|
647
|
-
break;
|
|
648
|
-
}
|
|
649
|
-
|
|
650
636
|
case 'mcp': {
|
|
651
637
|
const { runStdioServer } = require('../lib/mcp/server');
|
|
652
638
|
runStdioServer();
|
|
@@ -761,6 +747,12 @@ async function main() {
|
|
|
761
747
|
break;
|
|
762
748
|
}
|
|
763
749
|
|
|
750
|
+
case 'app-entry': {
|
|
751
|
+
const { run } = require('../lib/app/app-entry');
|
|
752
|
+
await run(args);
|
|
753
|
+
break;
|
|
754
|
+
}
|
|
755
|
+
|
|
764
756
|
case 'app-list': {
|
|
765
757
|
const { run } = require('../lib/app/app-list');
|
|
766
758
|
await run(args);
|
|
@@ -916,8 +908,8 @@ async function main() {
|
|
|
916
908
|
if (args.length < 4) {
|
|
917
909
|
throwCliUsage(t('cli.form_config_usage'), t('cli.form_config_example'));
|
|
918
910
|
}
|
|
919
|
-
|
|
920
|
-
|
|
911
|
+
process.argv = [process.argv[0], process.argv[1], ...args];
|
|
912
|
+
require('../lib/app/update-form-config');
|
|
921
913
|
break;
|
|
922
914
|
}
|
|
923
915
|
|
|
@@ -1303,9 +1295,7 @@ async function main() {
|
|
|
1303
1295
|
}
|
|
1304
1296
|
|
|
1305
1297
|
main()
|
|
1306
|
-
.then(() => { commandReceipt.finish(process.exitCode || 0); })
|
|
1307
1298
|
.catch((err) => {
|
|
1308
|
-
try {commandReceipt?.finish(err && err.exitCode ? err.exitCode : 1);} catch { /* Intent remains recoverable. */ }
|
|
1309
1299
|
if (shouldUseStructuredErrorOutput(err, args)) {
|
|
1310
1300
|
console.error(JSON.stringify(toErrorPayload(err), null, 2));
|
|
1311
1301
|
} else if (isCliError(err)) {
|
|
@@ -1316,5 +1306,7 @@ main()
|
|
|
1316
1306
|
} else {
|
|
1317
1307
|
warn(t('cli.exec_failed', err.message));
|
|
1318
1308
|
}
|
|
1319
|
-
|
|
1309
|
+
// Let pending stdout/stderr writes drain, especially large JSON diagnostics
|
|
1310
|
+
// sent through pipes on macOS/Linux. process.exit() can truncate them.
|
|
1311
|
+
process.exitCode = err && err.exitCode ? err.exitCode : 1;
|
|
1320
1312
|
});
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { createAuthRef, createYidaClient, unwrapYidaResponse } = require('../core/yida-client');
|
|
4
|
+
const { t } = require('../core/i18n');
|
|
5
|
+
const { throwUsage } = require('../core/command-errors');
|
|
6
|
+
const { fetchFormPageList } = require('./form-navigation');
|
|
7
|
+
|
|
8
|
+
/** Keep complete runtime URLs; the server verifies tenant and resource ownership. */
|
|
9
|
+
function normalizeUrl(value, appType) {
|
|
10
|
+
const input = String(value || '').trim();
|
|
11
|
+
if (!input) { throw new Error(t('app_entry.invalid_url')); }
|
|
12
|
+
// eslint-disable-next-line no-control-regex -- reject control characters in persisted URLs
|
|
13
|
+
if (input.length > 2048 || /[\\\s\x00-\x1f\x7f]/.test(input)) {
|
|
14
|
+
throw new Error(t('app_entry.invalid_url'));
|
|
15
|
+
}
|
|
16
|
+
const match = /^https?:\/\/[^/?#]+(\/[^?#]*)(?:\?([^#]*))?(?:#(.*))?$/i.exec(input);
|
|
17
|
+
if (!match) { throw new Error(t('app_entry.invalid_url')); }
|
|
18
|
+
const url = new URL(input);
|
|
19
|
+
const route = match[1];
|
|
20
|
+
const prefix = `/${appType}/`;
|
|
21
|
+
const parts = route.startsWith(prefix) ? route.slice(prefix.length).split('/') : [];
|
|
22
|
+
const short = /^\/(?:s\/[A-Za-z0-9_-]+|o\/[A-Za-z0-9_-]+(?:\/FORM-[A-Za-z0-9_-]+)?)$/.test(route);
|
|
23
|
+
const runtime = ['custom', 'workbench', 'submission', 'manage'].includes(parts[0]) &&
|
|
24
|
+
((parts.length === 1 && parts[0] === 'workbench') ||
|
|
25
|
+
(parts.length === 2 && /^[A-Za-z0-9_-]+$/.test(parts[1])));
|
|
26
|
+
if (url.username || url.password || url.pathname !== route || (!short && !runtime)) {
|
|
27
|
+
throw new Error(t('app_entry.invalid_url'));
|
|
28
|
+
}
|
|
29
|
+
if (match[2] !== undefined) {
|
|
30
|
+
const seen = new Set();
|
|
31
|
+
for (const parameter of match[2].split('&')) {
|
|
32
|
+
const pair = /^(corpid|locale|viewUuid|processCode|hideLeftNav|noShowTopBottom)=([A-Za-z0-9_-]+)$/.exec(parameter);
|
|
33
|
+
if (!pair || seen.has(pair[1]) ||
|
|
34
|
+
(['hideLeftNav', 'noShowTopBottom'].includes(pair[1]) && !/^(true|false|y|n|0|1)$/.test(pair[2]))) {
|
|
35
|
+
throw new Error(t('app_entry.invalid_url'));
|
|
36
|
+
}
|
|
37
|
+
seen.add(pair[1]);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (match[3] !== undefined && !/^[A-Za-z0-9_/-]+$/.test(match[3])) {
|
|
41
|
+
throw new Error(t('app_entry.invalid_url'));
|
|
42
|
+
}
|
|
43
|
+
return input;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Resolve a page identifier into the canonical entry URL the platform expects. */
|
|
47
|
+
async function resolveEntryUrl(authRef, appType, key, formUuid) {
|
|
48
|
+
if (!/^[A-Za-z0-9_-]+$/.test(String(formUuid || ''))) {
|
|
49
|
+
throw new Error(t('app_entry.invalid_url'));
|
|
50
|
+
}
|
|
51
|
+
const forms = await fetchFormPageList(appType, authRef);
|
|
52
|
+
const form = Array.isArray(forms) ? forms.find((item) => item.formUuid === formUuid) : null;
|
|
53
|
+
if (!form) { throw new Error(t('app_entry.page_not_in_app', formUuid)); }
|
|
54
|
+
if (key === 'frontend') {
|
|
55
|
+
if (String(form.formType).toLowerCase() !== 'display') { throw new Error(t('app_entry.frontend_display_required', formUuid)); }
|
|
56
|
+
if (!form.pathName) { throw new Error(t('app_entry.page_offline', formUuid)); }
|
|
57
|
+
return normalizeUrl(`${authRef.baseUrl}/${appType}/custom/${formUuid}`, appType);
|
|
58
|
+
}
|
|
59
|
+
return normalizeUrl(`${authRef.baseUrl}/${appType}/workbench/${formUuid}`, appType);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Reject duplicate or ambiguous flags; omissions never clear stored entries. */
|
|
63
|
+
function parseArgs(args) {
|
|
64
|
+
const [action, appType, ...flags] = args;
|
|
65
|
+
if (!['get', 'set'].includes(action) || !/^[A-Za-z0-9_-]+$/.test(appType || '')) {
|
|
66
|
+
throwUsage(t('app_entry.usage'));
|
|
67
|
+
}
|
|
68
|
+
const values = {};
|
|
69
|
+
for (let index = 0; index < flags.length; index++) {
|
|
70
|
+
const flag = flags[index];
|
|
71
|
+
if (flag === '--json') {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
const match = /^--(clear-)?(frontend|management)(-page)?$/.exec(flag);
|
|
75
|
+
if (action !== 'set' || !match || (match[1] && match[3]) ||
|
|
76
|
+
Object.prototype.hasOwnProperty.call(values, match[2])) {
|
|
77
|
+
throwUsage(t('app_entry.usage'));
|
|
78
|
+
}
|
|
79
|
+
const kind = match[1] ? 'clear' : (match[3] ? 'page' : 'url');
|
|
80
|
+
const value = kind === 'clear' ? null : flags[++index];
|
|
81
|
+
if (kind !== 'clear' && (!value || value.startsWith('--'))) {
|
|
82
|
+
throwUsage(t('app_entry.usage'));
|
|
83
|
+
}
|
|
84
|
+
values[match[2]] = { kind, value };
|
|
85
|
+
}
|
|
86
|
+
if (action === 'set' && !Object.keys(values).length) {
|
|
87
|
+
throwUsage(t('app_entry.usage'));
|
|
88
|
+
}
|
|
89
|
+
return { action, appType, values };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** Read the revision used for a conditional partial write. */
|
|
93
|
+
async function readEntries(client, appType) {
|
|
94
|
+
const result = unwrapYidaResponse(await client.get(`/${appType}/query/app/getAccessEntries.json`));
|
|
95
|
+
if (!result || typeof result.revision !== 'string' || !result.revision ||
|
|
96
|
+
!result.accessEntries || typeof result.accessEntries !== 'object' || Array.isArray(result.accessEntries)) {
|
|
97
|
+
throw new Error(t('app_entry.invalid_response'));
|
|
98
|
+
}
|
|
99
|
+
return result;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** Persist only supplied entries and verify them through a separate read. */
|
|
103
|
+
async function run(args = []) {
|
|
104
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
105
|
+
console.log(t('app_entry.usage'));
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const { action, appType, values } = parseArgs(args);
|
|
109
|
+
const authRef = createAuthRef();
|
|
110
|
+
const client = createYidaClient({ authRef });
|
|
111
|
+
const patch = {};
|
|
112
|
+
for (const [key, spec] of Object.entries(values)) {
|
|
113
|
+
if (spec.kind === 'clear') {
|
|
114
|
+
patch[key] = null;
|
|
115
|
+
} else if (spec.kind === 'page') {
|
|
116
|
+
patch[key] = { url: await resolveEntryUrl(authRef, appType, key, spec.value) };
|
|
117
|
+
} else {
|
|
118
|
+
const url = normalizeUrl(spec.value, appType);
|
|
119
|
+
patch[key] = { url };
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
let result = await readEntries(client, appType);
|
|
123
|
+
if (action === 'set') {
|
|
124
|
+
unwrapYidaResponse(await client.postForm(`/${appType}/query/app/saveAccessEntries.json`, {
|
|
125
|
+
accessEntries: JSON.stringify(patch), revision: result.revision,
|
|
126
|
+
}));
|
|
127
|
+
result = await readEntries(client, appType);
|
|
128
|
+
for (const [key, entry] of Object.entries(patch)) {
|
|
129
|
+
if ((result.accessEntries[key]?.url || '') !== (entry?.url || '')) {
|
|
130
|
+
throw new Error(t('app_entry.readback_failed'));
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
const urls = {};
|
|
135
|
+
for (const key of ['frontend', 'management']) {
|
|
136
|
+
if (result.accessEntries[key]?.url) {
|
|
137
|
+
urls[key] = normalizeUrl(result.accessEntries[key].url, appType);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
console.log(JSON.stringify({ appType, ...result, urls }, null, 2));
|
|
141
|
+
return result;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
module.exports = { run, parseArgs, normalizeUrl, resolveEntryUrl };
|
package/lib/app/app-list.js
CHANGED
|
@@ -84,6 +84,7 @@ function formatApp(app, baseUrl) {
|
|
|
84
84
|
appName: (app.appName && app.appName.zh_CN) || '',
|
|
85
85
|
appType: app.appType || '',
|
|
86
86
|
systemLink: app.systemLink || '',
|
|
87
|
+
...(app.accessEntries ? { accessEntries: app.accessEntries } : {}),
|
|
87
88
|
...buildApplicationEntryUrls({ appType: app.appType, systemLink: app.systemLink, baseUrl }),
|
|
88
89
|
};
|
|
89
90
|
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { CliError } = require('../core/cli-error');
|
|
6
|
+
const { t } = require('../core/i18n');
|
|
7
|
+
const { DESIGN_SKILL_ROOT, loadThemeIndex } = require('../design-plan/themes');
|
|
8
|
+
const START = '/* OPENYIDA APPLICATION STYLE RECIPES START';
|
|
9
|
+
const END = '/* OPENYIDA APPLICATION STYLE RECIPES END */';
|
|
10
|
+
const CREATIVE_TOKENS = [
|
|
11
|
+
'--pod-page-bg-color', '--pod-card-bg-color', '--color-text1-4',
|
|
12
|
+
'--form-element-medium-corner', '--form-element-medium-height',
|
|
13
|
+
'--pod-page-footer-bg-color', '--pod-sticky-footer-box-shadow',
|
|
14
|
+
'--oyd-content-width', '--oyd-content-padding', '--oyd-field-gap',
|
|
15
|
+
'--oyd-heading-font', '--oyd-heading-size', '--oyd-rule-style',
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
function validateCreativeDirection(direction, tokens) {
|
|
19
|
+
const missing = ['businessRationale', 'composition', 'typography', 'material', 'formLayout']
|
|
20
|
+
.filter(key => typeof direction?.[key] !== 'string' || !direction[key].trim());
|
|
21
|
+
missing.push(...CREATIVE_TOKENS.filter(key => typeof tokens?.[key] !== 'string' || !tokens[key].trim()));
|
|
22
|
+
if (missing.length) {
|
|
23
|
+
throw new CliError(t('design_document.invalid', 'creativeDirection', missing.join(', ')), {
|
|
24
|
+
code: 'APPLICATION_STYLE_CREATIVE_INCOMPLETE', details: { missing },
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function applyApplicationStyle(css, metadata, tokens) {
|
|
30
|
+
const style = metadata.applicationStyle;
|
|
31
|
+
if (style && (style.recipe !== 'application-style-v1' || !['template', 'creative'].includes(style.mode))) {
|
|
32
|
+
throw new CliError(t('design_document.invalid', 'applicationStyle', 'APPLICATION_STYLE_INVALID'), { code: 'APPLICATION_STYLE_INVALID' });
|
|
33
|
+
}
|
|
34
|
+
if (style?.mode === 'creative') {validateCreativeDirection(metadata.creativeDirection, tokens);}
|
|
35
|
+
const first = css.indexOf(START);
|
|
36
|
+
const last = css.indexOf(END);
|
|
37
|
+
if (first >= 0 && last < first) {
|
|
38
|
+
throw new CliError(t('design_document.invalid', 'app_theme.css', 'APPLICATION_STYLE_CSS_INVALID'), { code: 'APPLICATION_STYLE_CSS_INVALID' });
|
|
39
|
+
}
|
|
40
|
+
const recipe = style
|
|
41
|
+
? fs.readFileSync(path.join(DESIGN_SKILL_ROOT, 'references/theme/application-style-recipes.css'), 'utf8').trim()
|
|
42
|
+
: '';
|
|
43
|
+
// Only the managed recipe block is replaced. User-authored rules stay intact.
|
|
44
|
+
if (first >= 0) {return css.slice(0, first) + recipe + css.slice(last + END.length);}
|
|
45
|
+
return recipe ? `${css.trimEnd()}\n\n${recipe}\n` : css;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function exportApplicationStyle(id, outputDirectory) {
|
|
49
|
+
const theme = loadThemeIndex().themes.find(item => item.themeId === id);
|
|
50
|
+
if (!theme) {throw new CliError(t('design_document.invalid', id || '--style-id', 'APPLICATION_STYLE_UNKNOWN'), { code: 'APPLICATION_STYLE_UNKNOWN' });}
|
|
51
|
+
const directory = path.resolve(outputDirectory);
|
|
52
|
+
const assets = [['design.md', theme.templatePath], ['app_theme.css', theme.cssTemplatePath], ['form-layout.json', theme.formLayoutPath]];
|
|
53
|
+
const outputs = assets.map(([name, relative]) => {
|
|
54
|
+
const source = path.resolve(DESIGN_SKILL_ROOT, relative);
|
|
55
|
+
const target = path.join(directory, name);
|
|
56
|
+
const root = path.resolve(DESIGN_SKILL_ROOT, 'templates/design-themes') + path.sep;
|
|
57
|
+
if (!source.startsWith(root) || fs.existsSync(target)) {
|
|
58
|
+
throw new CliError(t('design_document.invalid', target, 'APPLICATION_STYLE_OUTPUT_CONFLICT'), { code: 'APPLICATION_STYLE_OUTPUT_CONFLICT' });
|
|
59
|
+
}
|
|
60
|
+
return { source, target, content: fs.readFileSync(source, 'utf8') };
|
|
61
|
+
});
|
|
62
|
+
fs.mkdirSync(directory, { recursive: true });
|
|
63
|
+
for (const item of outputs) {fs.writeFileSync(item.target, item.content, { flag: 'wx' });}
|
|
64
|
+
return { success: true, mode: theme.mode, themeId: id, authoringRequired: true, outputs: outputs.map(item => item.target) };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
module.exports = { applyApplicationStyle, validateCreativeDirection, CREATIVE_TOKENS, exportApplicationStyle };
|
|
@@ -976,7 +976,12 @@ function compileCanvasLocal(source, options = {}) {
|
|
|
976
976
|
assertCanvasNavigationStructure(source, options);
|
|
977
977
|
assertCanvasNavigationPaths(source, options);
|
|
978
978
|
assertInlineCssStructure(source, options);
|
|
979
|
-
|
|
979
|
+
const warnings = [];
|
|
980
|
+
assertCanvasThemeStructure(source, { ...options, onThemeWarning(message, details) {
|
|
981
|
+
warnings.push({ ...details, message });
|
|
982
|
+
if (options.onThemeWarning) { options.onThemeWarning(message, details); }
|
|
983
|
+
else { require('../core/chalk').warn(message); }
|
|
984
|
+
} });
|
|
980
985
|
|
|
981
986
|
const importedModules = extractImportedModules(source);
|
|
982
987
|
|
|
@@ -1036,6 +1041,7 @@ function compileCanvasLocal(source, options = {}) {
|
|
|
1036
1041
|
return {
|
|
1037
1042
|
runtimeCode,
|
|
1038
1043
|
importedModules: JSON.stringify(importedModules),
|
|
1044
|
+
warnings,
|
|
1039
1045
|
};
|
|
1040
1046
|
}
|
|
1041
1047
|
|