openyida 2026.9.24-beta.0 → 2026.9.30
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 +2 -9
- package/bin/yida.js +1 -15
- package/lib/app/application-entry-urls.js +27 -1
- package/lib/app/create-page.js +5 -9
- package/lib/app/get-form-config.js +6 -0
- package/lib/app/publish.js +20 -1
- package/lib/auth/token-auth.js +22 -75
- package/lib/core/agent-capabilities.js +1 -0
- package/lib/core/command-manifest.js +32 -4
- package/lib/core/locales/en.js +2 -14
- package/lib/core/locales/zh.js +2 -14
- package/lib/design-plan/entry-navigation.js +10 -1
- package/lib/design-plan/init.js +2 -1
- package/lib/design-plan/materialize.js +6 -4
- package/package.json +1 -1
- package/yida-skills/skills/yida-app/SKILL.md +1 -1
- package/yida-skills/skills/yida-app/references/entry-navigation.md +2 -0
- package/yida-skills/skills/yida-app/workflow/step-6-main-page.md +1 -1
- package/yida-skills/skills/yida-app/workflow/step-7-page-code.md +1 -1
- package/yida-skills/skills/yida-app/workflow/step-8-publish-navigation.md +2 -2
- package/yida-skills/skills/yida-app/workflow/step-9-output-finish.md +3 -3
- package/yida-skills/skills/yida-canvas-custom-page/references/canvas-style-implementation-guide.md +5 -4
- package/yida-skills/skills/yida-canvas-custom-page/references/page-generation-guide.md +6 -6
- package/yida-skills/skills/yida-create-form-page/SKILL.md +3 -1
- package/yida-skills/skills/yida-create-form-page/references/field-definition-guide.md +16 -0
- package/yida-skills/skills/yida-create-form-page/references/form-field-properties.md +7 -5
- package/yida-skills/skills/yida-create-page/SKILL.md +1 -1
- package/yida-skills/skills/yida-dashboard/SKILL.md +1 -1
- package/yida-skills/skills/yida-design/SKILL.md +5 -3
- package/yida-skills/skills/yida-design/references/application-style-library.md +1 -1
- package/yida-skills/skills/yida-design/references/application-theme-consistency.md +4 -2
- package/yida-skills/skills/yida-design/references/native-form-styles.md +58 -0
- package/yida-skills/skills/yida-design/references/navigation-decision.md +2 -0
- package/yida-skills/skills/yida-design/references/page-quality-gates.md +6 -4
- package/yida-skills/skills/yida-design/references/theme/app-custom-theme-template.css +524 -186
- package/yida-skills/skills/yida-design/references/theme/theme-token-presets.md +3 -1
- package/yida-skills/skills/yida-design/references/visual-scaffold-recipes.md +13 -40
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/SKILL.md +1 -1
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/references/page-patterns.md +6 -4
- package/yida-skills/skills/yida-design/templates/design-themes/README.md +6 -3
- package/yida-skills/skills/yida-design/templates/design-themes/app-amber/app_theme.css +428 -189
- package/yida-skills/skills/yida-design/templates/design-themes/app-amber/design.md +12 -10
- package/yida-skills/skills/yida-design/templates/design-themes/app-editorial/app_theme.css +428 -189
- package/yida-skills/skills/yida-design/templates/design-themes/app-editorial/design.md +12 -10
- package/yida-skills/skills/yida-design/templates/design-themes/app-executive/app_theme.css +429 -190
- package/yida-skills/skills/yida-design/templates/design-themes/app-executive/design.md +13 -11
- package/yida-skills/skills/yida-design/templates/design-themes/app-finance/app_theme.css +427 -188
- package/yida-skills/skills/yida-design/templates/design-themes/app-finance/design.md +11 -9
- package/yida-skills/skills/yida-design/templates/design-themes/app-glass/app_theme.css +428 -189
- package/yida-skills/skills/yida-design/templates/design-themes/app-glass/design.md +12 -10
- package/yida-skills/skills/yida-design/templates/design-themes/app-graphite/app_theme.css +429 -190
- package/yida-skills/skills/yida-design/templates/design-themes/app-graphite/design.md +13 -11
- package/yida-skills/skills/yida-design/templates/design-themes/app-line/app_theme.css +427 -188
- package/yida-skills/skills/yida-design/templates/design-themes/app-line/design.md +11 -9
- package/yida-skills/skills/yida-design/templates/design-themes/app-neon/app_theme.css +430 -191
- package/yida-skills/skills/yida-design/templates/design-themes/app-neon/design.md +14 -12
- package/yida-skills/skills/yida-design/templates/design-themes/app-nordic/app_theme.css +427 -188
- package/yida-skills/skills/yida-design/templates/design-themes/app-nordic/design.md +11 -9
- package/yida-skills/skills/yida-design/templates/design-themes/app-paper/app_theme.css +428 -189
- package/yida-skills/skills/yida-design/templates/design-themes/app-paper/design.md +12 -10
- package/yida-skills/skills/yida-design/templates/design-themes/app-platinum/app_theme.css +427 -188
- package/yida-skills/skills/yida-design/templates/design-themes/app-platinum/design.md +11 -9
- package/yida-skills/skills/yida-design/templates/design-themes/app-plum/app_theme.css +428 -189
- package/yida-skills/skills/yida-design/templates/design-themes/app-plum/design.md +12 -10
- package/yida-skills/skills/yida-design/templates/design-themes/app-pop/app_theme.css +428 -189
- package/yida-skills/skills/yida-design/templates/design-themes/app-pop/design.md +12 -10
- package/yida-skills/skills/yida-design/templates/design-themes/app-sage/app_theme.css +428 -189
- package/yida-skills/skills/yida-design/templates/design-themes/app-sage/design.md +12 -10
- package/yida-skills/skills/yida-design/templates/design-themes/app-teal/app_theme.css +427 -188
- package/yida-skills/skills/yida-design/templates/design-themes/app-teal/design.md +11 -9
- package/yida-skills/skills/yida-design/templates/design-themes/app-terminal/app_theme.css +429 -190
- package/yida-skills/skills/yida-design/templates/design-themes/app-terminal/design.md +13 -11
- package/yida-skills/skills/yida-design/templates/design-themes/app-ticket/app_theme.css +428 -189
- package/yida-skills/skills/yida-design/templates/design-themes/app-ticket/design.md +12 -10
- package/yida-skills/skills/yida-design/templates/design-themes/app-wire/app_theme.css +427 -188
- package/yida-skills/skills/yida-design/templates/design-themes/app-wire/design.md +11 -9
- package/yida-skills/skills/yida-design/templates/design-themes/basic-tokens.json +1 -0
- package/yida-skills/skills/yida-design/templates/design-themes/dark-inset-hairline/app_theme.css +422 -183
- package/yida-skills/skills/yida-design/templates/design-themes/dark-inset-hairline/design.md +3 -1
- package/yida-skills/skills/yida-design/templates/design-themes/dark-rail-fine-lines/app_theme.css +422 -183
- package/yida-skills/skills/yida-design/templates/design-themes/dark-rail-fine-lines/design.md +4 -2
- package/yida-skills/skills/yida-design/templates/design-themes/dark-rail-signal-panels/app_theme.css +422 -183
- package/yida-skills/skills/yida-design/templates/design-themes/dark-rail-signal-panels/design.md +3 -1
- package/yida-skills/skills/yida-design/templates/design-themes/free-creative/app_theme.css +419 -180
- package/yida-skills/skills/yida-design/templates/design-themes/free-creative/design.md +3 -1
- package/yida-skills/skills/yida-design/templates/design-themes/graphite-bevel-grid/app_theme.css +422 -183
- package/yida-skills/skills/yida-design/templates/design-themes/graphite-bevel-grid/design.md +3 -1
- package/yida-skills/skills/yida-design/templates/design-themes/hairline-shared-bands/app_theme.css +422 -183
- package/yida-skills/skills/yida-design/templates/design-themes/hairline-shared-bands/design.md +3 -1
- package/yida-skills/skills/yida-design/templates/design-themes/hairline-soft-blocks/app_theme.css +422 -183
- package/yida-skills/skills/yida-design/templates/design-themes/hairline-soft-blocks/design.md +5 -3
- package/yida-skills/skills/yida-design/templates/design-themes/index.json +0 -13
- package/yida-skills/skills/yida-design/templates/design-themes/ink-glow-soft-panels/app_theme.css +421 -182
- package/yida-skills/skills/yida-design/templates/design-themes/ink-glow-soft-panels/design.md +2 -0
- package/yida-skills/skills/yida-design/templates/design-themes/inset-frame-pixel-rhythm/app_theme.css +421 -182
- package/yida-skills/skills/yida-design/templates/design-themes/inset-frame-pixel-rhythm/design.md +2 -0
- package/yida-skills/skills/yida-design/templates/design-themes/outlined-texture-duotone/app_theme.css +422 -183
- package/yida-skills/skills/yida-design/templates/design-themes/outlined-texture-duotone/design.md +3 -1
- package/yida-skills/skills/yida-design/templates/design-themes/soft-inset-surfaces/app_theme.css +421 -182
- package/yida-skills/skills/yida-design/templates/design-themes/soft-inset-surfaces/design.md +2 -0
- package/yida-skills/skills/yida-design/templates/design-themes/soft-outline-rhythm/app_theme.css +421 -182
- package/yida-skills/skills/yida-design/templates/design-themes/soft-outline-rhythm/design.md +2 -0
- package/yida-skills/skills/yida-design/templates/design-themes/soft-rail-bold-band/app_theme.css +422 -183
- package/yida-skills/skills/yida-design/templates/design-themes/soft-rail-bold-band/design.md +6 -4
- package/yida-skills/skills/yida-design/templates/design-themes/warm-canvas-contrast-panels/app_theme.css +422 -183
- package/yida-skills/skills/yida-design/templates/design-themes/warm-canvas-contrast-panels/design.md +5 -3
- package/yida-skills/skills/yida-design/templates/design-themes/warm-rail-muted-panels/app_theme.css +422 -183
- package/yida-skills/skills/yida-design/templates/design-themes/warm-rail-muted-panels/design.md +4 -2
- package/yida-skills/skills/yida-design/workflow/step-2-theme-system.md +3 -1
- package/yida-skills/skills/yida-design/workflow/step-4-wireframe-interaction.md +5 -5
- package/yida-skills/skills/yida-page-config/SKILL.md +2 -2
- package/yida-skills/skills/yida-prd/references/app/role-journey.md +1 -1
- package/yida-skills/skills/yida-prd/references/plan-content.md +1 -1
- package/yida-skills/skills/yida-prd/workflow/output-prd.md +5 -5
- package/yida-skills/skills/yida-prd/workflow/plan-business.md +2 -0
- package/yida-skills/skills/yida-prd/workflow/step-2-information-architecture.md +12 -3
- package/yida-skills/skills/yida-publish-page/SKILL.md +8 -1
- package/yida-skills/skills/yida-requirement-analysis/references/experience-groups.md +3 -3
- package/lib/auth/oauth-device.js +0 -311
- package/yida-skills/skills/yida-design/templates/design-themes/soft-spectral-panels/app_theme.css +0 -511
- package/yida-skills/skills/yida-design/templates/design-themes/soft-spectral-panels/design.md +0 -383
- package/yida-skills/skills/yida-design/templates/design-themes/soft-spectral-panels/form-layout.json +0 -13
package/README.md
CHANGED
|
@@ -74,17 +74,10 @@ 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
|
-
|
|
84
77
|
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:
|
|
85
78
|
|
|
86
79
|
```bash
|
|
87
|
-
openyida login https
|
|
80
|
+
openyida login https://yida-group.alibaba-inc.com/
|
|
88
81
|
openyida login --alibaba
|
|
89
82
|
```
|
|
90
83
|
|
|
@@ -390,7 +383,7 @@ Run `openyida --help` or `openyida <command> --help` for detailed usage.
|
|
|
390
383
|
|
|
391
384
|
| Command | Description |
|
|
392
385
|
|---------|-------------|
|
|
393
|
-
| `openyida login [target-url] [--env <name>\|--intl\|--overseas\|--global\|--yidaapps\|--alibaba] [--client-id <clientId>] [--endpoint <url>] [--no-browser]
|
|
386
|
+
| `openyida login [target-url] [--env <name>\|--intl\|--overseas\|--global\|--yidaapps\|--alibaba] [--client-id <clientId>] [--endpoint <url>] [--no-browser]` | Login with OAuth token mode |
|
|
394
387
|
| `openyida logout` | Logout / unbind current project auth |
|
|
395
388
|
| `openyida auth <status\|login\|refresh\|logout\|profiles\|profile switch>` | Token login state and profile management |
|
|
396
389
|
| `openyida org <list\|switch> [--json] [--corp-id <corpId>]` | Organization management (list / switch existing profiles first) |
|
package/bin/yida.js
CHANGED
|
@@ -193,7 +193,6 @@ function printLoginResult(result) {
|
|
|
193
193
|
|
|
194
194
|
if (!result) {
|
|
195
195
|
console.log(JSON.stringify({
|
|
196
|
-
type: 'login_result',
|
|
197
196
|
ok: false,
|
|
198
197
|
status: 'login_failed',
|
|
199
198
|
can_auto_use: false,
|
|
@@ -206,7 +205,6 @@ function printLoginResult(result) {
|
|
|
206
205
|
? !!result.ok
|
|
207
206
|
: (result.can_auto_use !== false && !!result.access_token);
|
|
208
207
|
const summary = {
|
|
209
|
-
type: 'login_result',
|
|
210
208
|
ok: tokenUsable,
|
|
211
209
|
status: result.status || (tokenUsable ? 'ok' : 'token_not_issued'),
|
|
212
210
|
auth_mode: 'token',
|
|
@@ -281,7 +279,6 @@ function getFirstPositionalArg(cliArgs, startIndex = 0) {
|
|
|
281
279
|
'--login-url',
|
|
282
280
|
'--profile',
|
|
283
281
|
'--user-id',
|
|
284
|
-
'--env-hint',
|
|
285
282
|
]);
|
|
286
283
|
for (let index = startIndex; index < cliArgs.length; index++) {
|
|
287
284
|
const arg = cliArgs[index];
|
|
@@ -389,7 +386,6 @@ function applyLoginEnvironmentFlags(cliArgs, options = {}) {
|
|
|
389
386
|
'--client-id',
|
|
390
387
|
'--profile',
|
|
391
388
|
'--user-id',
|
|
392
|
-
'--env-hint',
|
|
393
389
|
]);
|
|
394
390
|
const targetUrlFlags = new Set([
|
|
395
391
|
'--endpoint',
|
|
@@ -541,23 +537,13 @@ function printLoginHelp() {
|
|
|
541
537
|
}
|
|
542
538
|
|
|
543
539
|
function buildTokenLoginOptions(loginArgs) {
|
|
544
|
-
const device = loginArgs.includes('--device');
|
|
545
540
|
return {
|
|
546
541
|
clientId: getArgValue(loginArgs, '--client-id'),
|
|
547
542
|
corpId: getArgValue(loginArgs, '--corp-id'),
|
|
548
543
|
userId: getArgValue(loginArgs, '--user-id'),
|
|
549
544
|
authProfile: getArgValue(loginArgs, '--profile'),
|
|
550
545
|
quiet: process.env.YIDA_QUIET === '1' || loginArgs.includes('--quiet'),
|
|
551
|
-
noBrowser:
|
|
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
|
-
},
|
|
546
|
+
noBrowser: loginArgs.includes('--no-browser'),
|
|
561
547
|
};
|
|
562
548
|
}
|
|
563
549
|
|
|
@@ -28,4 +28,30 @@ function buildApplicationEntryUrls({ appType, baseUrl, systemLink }) {
|
|
|
28
28
|
return { appUrl: workbenchUrl, workbenchUrl, adminUrl: `${origin}/${appType}/admin${suffix}` };
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
function readRenderNav(config) {
|
|
32
|
+
const value = config && Object.prototype.hasOwnProperty.call(config, 'renderNav')
|
|
33
|
+
? config.renderNav : config?.isRenderNav;
|
|
34
|
+
if (value === false || value === 'false') {return false;}
|
|
35
|
+
if (value === true || value === 'true') {return true;}
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function buildDisplayPageEntryUrls({ appType, formUuid, baseUrl, config, formType = config?.formType }) {
|
|
40
|
+
if (formType !== 'display' || !/^FORM[-_][A-Za-z0-9_-]+$/.test(formUuid || '')) {return {};}
|
|
41
|
+
if (config?.formType && config.formType !== 'display') {return {};}
|
|
42
|
+
if ((config?.appType && config.appType !== appType) || (config?.formUuid && config.formUuid !== formUuid)) {return {};}
|
|
43
|
+
const appUrls = buildApplicationEntryUrls({ appType, baseUrl });
|
|
44
|
+
if (!appUrls.workbenchUrl) {return {};}
|
|
45
|
+
const origin = new URL(appUrls.workbenchUrl).origin;
|
|
46
|
+
const renderNav = readRenderNav(config);
|
|
47
|
+
const workbenchUrl = `${origin}/${appType}/workbench/${formUuid}`;
|
|
48
|
+
const standaloneUrl = renderNav === false ? `${origin}/${appType}/custom/${formUuid}` : null;
|
|
49
|
+
return {
|
|
50
|
+
url: standaloneUrl || workbenchUrl,
|
|
51
|
+
workbenchUrl,
|
|
52
|
+
standaloneUrl,
|
|
53
|
+
navigationVerification: { renderNav, verified: renderNav !== null },
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
module.exports = { buildApplicationEntryUrls, buildDisplayPageEntryUrls, readRenderNav };
|
package/lib/app/create-page.js
CHANGED
|
@@ -20,6 +20,7 @@ const { parseOpenOption, withBrowserHandoff } = require('../core/browser-handoff
|
|
|
20
20
|
const { throwCommandError } = require('../core/command-errors');
|
|
21
21
|
const { buildApiPath } = require('./create-form/api-path');
|
|
22
22
|
const { fetchFormSchemaInfo } = require('./get-form-config');
|
|
23
|
+
const { readRenderNav, buildDisplayPageEntryUrls } = require('./application-entry-urls');
|
|
23
24
|
|
|
24
25
|
function parseArgs(args) {
|
|
25
26
|
const openOption = parseOpenOption(args);
|
|
@@ -138,14 +139,6 @@ function buildPageInfoPostData(formUuid, pageName, isRenderNav, csrfToken, curre
|
|
|
138
139
|
return querystring.stringify(payload);
|
|
139
140
|
}
|
|
140
141
|
|
|
141
|
-
function readRenderNav(config) {
|
|
142
|
-
const value = config && Object.prototype.hasOwnProperty.call(config, 'renderNav')
|
|
143
|
-
? config.renderNav : config?.isRenderNav;
|
|
144
|
-
if (value === false || value === 'false') {return false;}
|
|
145
|
-
if (value === true || value === 'true') {return true;}
|
|
146
|
-
return null;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
142
|
async function configureNavigationVisibility(authRef, appType, pageId, pageName, isRenderNav) {
|
|
150
143
|
const verification = { requestedRenderNav: isRenderNav, renderNav: null, verified: false, attempts: 0 };
|
|
151
144
|
let currentConfig = null;
|
|
@@ -268,7 +261,10 @@ async function run(args) {
|
|
|
268
261
|
navigationVerification = await configureNavigationVisibility(authRef, appType, pageId, pageName, false);
|
|
269
262
|
if (navigationVerification.verified) {
|
|
270
263
|
chalkSuccess(t('create_page.dashboard_config_ok'));
|
|
271
|
-
pageUrl =
|
|
264
|
+
pageUrl = buildDisplayPageEntryUrls({
|
|
265
|
+
appType, formUuid: pageId, baseUrl: authRef.baseUrl,
|
|
266
|
+
config: { formType: 'display', renderNav: navigationVerification.renderNav },
|
|
267
|
+
}).standaloneUrl;
|
|
272
268
|
} else {
|
|
273
269
|
dashboardConfigWarning = navigationVerification.error;
|
|
274
270
|
warn(t('create_page.dashboard_config_failed', dashboardConfigWarning));
|
|
@@ -21,6 +21,7 @@ const {
|
|
|
21
21
|
const { t } = require('../core/i18n');
|
|
22
22
|
const { banner, step, label, info, success, error, result } = require('../core/chalk');
|
|
23
23
|
const { throwCommandError } = require('../core/command-errors');
|
|
24
|
+
const { buildDisplayPageEntryUrls } = require('./application-entry-urls');
|
|
24
25
|
|
|
25
26
|
// 常用配置字段白名单(人读摘要),--json 会输出完整对象
|
|
26
27
|
const SUMMARY_FIELDS = [
|
|
@@ -121,6 +122,9 @@ async function run(args) {
|
|
|
121
122
|
}
|
|
122
123
|
|
|
123
124
|
const cfg = resp.content || resp.result || resp.data || {};
|
|
125
|
+
const entryUrls = buildDisplayPageEntryUrls({
|
|
126
|
+
appType: parsed.appType, formUuid: parsed.formUuid, baseUrl: authRef.baseUrl, config: cfg,
|
|
127
|
+
});
|
|
124
128
|
success(t('get_form_config.read_ok'));
|
|
125
129
|
|
|
126
130
|
if (parsed.json) {
|
|
@@ -129,6 +133,7 @@ async function run(args) {
|
|
|
129
133
|
appType: parsed.appType,
|
|
130
134
|
formUuid: parsed.formUuid,
|
|
131
135
|
config: cfg,
|
|
136
|
+
...entryUrls,
|
|
132
137
|
}, null, 2));
|
|
133
138
|
return;
|
|
134
139
|
}
|
|
@@ -138,6 +143,7 @@ async function run(args) {
|
|
|
138
143
|
appType: parsed.appType,
|
|
139
144
|
formUuid: parsed.formUuid,
|
|
140
145
|
title: extractTitle(cfg.title),
|
|
146
|
+
...entryUrls,
|
|
141
147
|
};
|
|
142
148
|
SUMMARY_FIELDS.forEach((key) => {
|
|
143
149
|
if (cfg[key] !== undefined) {
|
package/lib/app/publish.js
CHANGED
|
@@ -37,6 +37,8 @@ const { buildPageFile, shouldBuildPageSource } = require('./page-compat');
|
|
|
37
37
|
const { warnLargePageSource } = require('./page-size-guard');
|
|
38
38
|
const { assertPageTemplateCustomized } = require('./page-template-guard');
|
|
39
39
|
const { fetchFormPageList } = require('./form-navigation');
|
|
40
|
+
const { fetchFormSchemaInfo } = require('./get-form-config');
|
|
41
|
+
const { buildDisplayPageEntryUrls } = require('./application-entry-urls');
|
|
40
42
|
const { parseOpenOption, withBrowserHandoff } = require('../core/browser-handoff');
|
|
41
43
|
const { assertNoEmojiInValue } = require('../core/no-emoji-guard');
|
|
42
44
|
const { loadPageSource } = require('./services/page-source-loader');
|
|
@@ -834,7 +836,22 @@ async function runMain(argv) {
|
|
|
834
836
|
|
|
835
837
|
baseUrl = authRef.baseUrl || baseUrl;
|
|
836
838
|
|
|
837
|
-
|
|
839
|
+
let pageConfig = null;
|
|
840
|
+
let navigationWarning = null;
|
|
841
|
+
try {
|
|
842
|
+
const configResponse = await fetchFormSchemaInfo(authRef, appType, savedFormUuid);
|
|
843
|
+
if (!configResponse || configResponse.success === false || configResponse.__needLogin || configResponse.__csrfExpired) {
|
|
844
|
+
throw new Error(configResponse?.errorMsg || t('common.request_failed'));
|
|
845
|
+
}
|
|
846
|
+
pageConfig = configResponse.content || configResponse.result || configResponse.data || {};
|
|
847
|
+
} catch (configError) {
|
|
848
|
+
navigationWarning = configError.message || t('common.request_failed');
|
|
849
|
+
}
|
|
850
|
+
const entryUrls = buildDisplayPageEntryUrls({
|
|
851
|
+
appType, formUuid: savedFormUuid, baseUrl: authRef.baseUrl || baseUrl,
|
|
852
|
+
config: pageConfig, formType: 'display',
|
|
853
|
+
});
|
|
854
|
+
const pageUrl = entryUrls.url || `${baseUrl}/${appType}/workbench/${savedFormUuid}`;
|
|
838
855
|
const publishMode = isCanvas ? 'canvas' : 'native';
|
|
839
856
|
let healthCheckResult = null;
|
|
840
857
|
let navOrderResult = null;
|
|
@@ -911,6 +928,8 @@ async function runMain(argv) {
|
|
|
911
928
|
formUuid: savedFormUuid,
|
|
912
929
|
version,
|
|
913
930
|
url: pageUrl,
|
|
931
|
+
...entryUrls,
|
|
932
|
+
navigationWarning,
|
|
914
933
|
publishMode,
|
|
915
934
|
storageMode,
|
|
916
935
|
bundleId,
|
package/lib/auth/token-auth.js
CHANGED
|
@@ -83,27 +83,11 @@ function resolveDingtalkLoginOrigin(options = {}) {
|
|
|
83
83
|
return DINGTALK_LOGIN_ORIGIN;
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
function requestJson(method, url, body, headers = {}
|
|
86
|
+
function requestJson(method, url, body, headers = {}) {
|
|
87
87
|
return new Promise((resolve, reject) => {
|
|
88
88
|
const parsedUrl = new URL(url);
|
|
89
89
|
const data = body === undefined || body === null ? null : Buffer.from(JSON.stringify(body));
|
|
90
90
|
const transport = parsedUrl.protocol === 'https:' ? https : http;
|
|
91
|
-
const socketTimeoutMs = positiveNumber(options.timeoutMs, 0);
|
|
92
|
-
let timeoutId = null;
|
|
93
|
-
let settled = false;
|
|
94
|
-
const finish = (callback, value) => {
|
|
95
|
-
if (settled) {
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
settled = true;
|
|
99
|
-
if (timeoutId) {
|
|
100
|
-
clearTimeout(timeoutId);
|
|
101
|
-
}
|
|
102
|
-
callback(value);
|
|
103
|
-
};
|
|
104
|
-
const resolveOnce = value => finish(resolve, value);
|
|
105
|
-
const rejectOnce = error => finish(reject, error);
|
|
106
|
-
|
|
107
91
|
const request = transport.request({
|
|
108
92
|
method,
|
|
109
93
|
protocol: parsedUrl.protocol,
|
|
@@ -121,7 +105,6 @@ function requestJson(method, url, body, headers = {}, options = {}) {
|
|
|
121
105
|
}, (response) => {
|
|
122
106
|
const chunks = [];
|
|
123
107
|
response.on('data', (chunk) => chunks.push(chunk));
|
|
124
|
-
response.on('error', rejectOnce);
|
|
125
108
|
response.on('end', () => {
|
|
126
109
|
const text = Buffer.concat(chunks).toString('utf8');
|
|
127
110
|
let payload = null;
|
|
@@ -142,26 +125,14 @@ function requestJson(method, url, body, headers = {}, options = {}) {
|
|
|
142
125
|
error.payload = payload;
|
|
143
126
|
error.headers = response.headers;
|
|
144
127
|
error.location = location;
|
|
145
|
-
|
|
128
|
+
reject(error);
|
|
146
129
|
return;
|
|
147
130
|
}
|
|
148
|
-
|
|
131
|
+
resolve(payload || {});
|
|
149
132
|
});
|
|
150
133
|
});
|
|
151
134
|
|
|
152
|
-
|
|
153
|
-
// Node's socket timeout is reset by network activity, so it cannot enforce
|
|
154
|
-
// the caller's wall-clock budget. Use an independent timer that also
|
|
155
|
-
// covers response bodies which trickle data without ever completing.
|
|
156
|
-
timeoutId = setTimeout(() => {
|
|
157
|
-
const error = new Error('request timed out');
|
|
158
|
-
error.code = 'request_timeout';
|
|
159
|
-
rejectOnce(error);
|
|
160
|
-
request.destroy(error);
|
|
161
|
-
}, socketTimeoutMs);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
request.on('error', rejectOnce);
|
|
135
|
+
request.on('error', reject);
|
|
165
136
|
if (data) {
|
|
166
137
|
request.write(data);
|
|
167
138
|
}
|
|
@@ -169,11 +140,6 @@ function requestJson(method, url, body, headers = {}, options = {}) {
|
|
|
169
140
|
});
|
|
170
141
|
}
|
|
171
142
|
|
|
172
|
-
function positiveNumber(value, fallback) {
|
|
173
|
-
const parsed = Number(value);
|
|
174
|
-
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
143
|
function sanitizeRawTokenResponse(response) {
|
|
178
144
|
if (!response || typeof response !== 'object') {
|
|
179
145
|
return response;
|
|
@@ -336,43 +302,25 @@ async function tokenLogin(options = {}) {
|
|
|
336
302
|
const baseUrl = resolveTokenBaseUrl(options);
|
|
337
303
|
const authBaseUrl = appendPath(baseUrl, DEFAULT_AUTH_PATH_PREFIX);
|
|
338
304
|
const clientId = options.clientId || process.env.OPENYIDA_DINGTALK_CLIENT_ID || DINGTALK_OAUTH_CLIENT_ID;
|
|
339
|
-
const
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
envHint: options.envHint,
|
|
350
|
-
quiet: options.quiet,
|
|
351
|
-
onState: options.onDeviceState,
|
|
352
|
-
timeoutMs: options.timeoutMs || env.OPENYIDA_OAUTH_TIMEOUT_MS,
|
|
353
|
-
});
|
|
354
|
-
requireOkResponse(response);
|
|
355
|
-
} else {
|
|
356
|
-
const callback = await runDingtalkLoopback({
|
|
357
|
-
clientId,
|
|
358
|
-
loginOrigin: resolveDingtalkLoginOrigin(options),
|
|
359
|
-
scope,
|
|
360
|
-
prompt: options.prompt,
|
|
361
|
-
port: options.port,
|
|
362
|
-
quiet: options.quiet,
|
|
363
|
-
noBrowser: options.noBrowser,
|
|
364
|
-
timeoutMs: options.timeoutMs,
|
|
365
|
-
});
|
|
305
|
+
const callback = await runDingtalkLoopback({
|
|
306
|
+
clientId,
|
|
307
|
+
loginOrigin: resolveDingtalkLoginOrigin(options),
|
|
308
|
+
scope: options.scope || process.env.OPENYIDA_DINGTALK_SCOPE || 'openid corpid',
|
|
309
|
+
prompt: options.prompt,
|
|
310
|
+
port: options.port,
|
|
311
|
+
quiet: options.quiet,
|
|
312
|
+
noBrowser: options.noBrowser,
|
|
313
|
+
timeoutMs: options.timeoutMs,
|
|
314
|
+
});
|
|
366
315
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
}
|
|
316
|
+
const response = await requestJson('POST', appendPath(authBaseUrl, '/dingtalk/token'), {
|
|
317
|
+
code: callback.code,
|
|
318
|
+
authCode: callback.authCode,
|
|
319
|
+
redirectUri: callback.redirectUri,
|
|
320
|
+
state: callback.state,
|
|
321
|
+
clientId,
|
|
322
|
+
});
|
|
323
|
+
requireOkResponse(response);
|
|
376
324
|
|
|
377
325
|
const normalized = normalizeTokenResponse(response, baseUrl, clientId);
|
|
378
326
|
if (!normalized.access_token) {
|
|
@@ -676,5 +624,4 @@ module.exports = {
|
|
|
676
624
|
resolveTokenBaseUrl,
|
|
677
625
|
isRefreshAuthRequired,
|
|
678
626
|
createTokenRefreshFailedError,
|
|
679
|
-
getTokenPayload,
|
|
680
627
|
};
|
|
@@ -499,6 +499,7 @@ function buildApplicationEntryPolicy(builderPath, env = process.env) {
|
|
|
499
499
|
delivery_unit: 'single_application_entry_group',
|
|
500
500
|
resource_delivery: 'summary_only',
|
|
501
501
|
internal_artifact_delivery: 'never',
|
|
502
|
+
frontend_delivery: 'Infer standalone for a scoped service frontend, persist page navigation hiding and return the verified publish/get-form-config standaloneUrl. No extra flag or navigation URL parameter. Missing verification is incomplete delivery; never silently omit the frontend or replace it with workbench/admin.',
|
|
502
503
|
entries: {
|
|
503
504
|
workbench: 'when_workspace_in_scope',
|
|
504
505
|
custom: 'when_entry_mode_standalone_and_is_render_nav_false_readback',
|
|
@@ -1035,7 +1035,7 @@ const COMMAND_GROUPS = [
|
|
|
1035
1035
|
id: 'auth',
|
|
1036
1036
|
titleKey: 'help.group_auth',
|
|
1037
1037
|
commands: [
|
|
1038
|
-
command('login', ['login'], 'login [target-url] [--env <name>|--intl|--overseas|--global|--yidaapps|--alibaba] [--client-id <clientId>] [--endpoint <url>] [--no-browser]
|
|
1038
|
+
command('login', ['login'], 'login [target-url] [--env <name>|--intl|--overseas|--global|--yidaapps|--alibaba] [--client-id <clientId>] [--endpoint <url>] [--no-browser]', 'help.cmd_login', {
|
|
1039
1039
|
requiresLogin: false,
|
|
1040
1040
|
output: 'json',
|
|
1041
1041
|
}),
|
|
@@ -1311,7 +1311,10 @@ const COMMAND_GROUPS = [
|
|
|
1311
1311
|
'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',
|
|
1312
1312
|
'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',
|
|
1313
1313
|
],
|
|
1314
|
-
notes: [
|
|
1314
|
+
notes: [
|
|
1315
|
+
'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.',
|
|
1316
|
+
'Divider colorType defaults to theme. If default bindings are unsuitable for the current theme, use custom with backgroundColor, secondaryColor and titleColor designed together; explicit user color values are not required. These are field JSON properties, not CLI flags. Dark-content and composite-title guidance is advisory, not a new validation or upload/save gate.',
|
|
1317
|
+
],
|
|
1315
1318
|
}),
|
|
1316
1319
|
command('create-form.icons', ['create-form', 'icons'], 'create-form icons [--json]', 'help.cmd_list_form_icons', {
|
|
1317
1320
|
requiresLogin: false,
|
|
@@ -1437,7 +1440,7 @@ const COMMAND_GROUPS = [
|
|
|
1437
1440
|
{ name: 'noOpen', type: 'boolean', source: 'option', builder_options: ['--no-open'] },
|
|
1438
1441
|
{ name: 'json', type: 'boolean', source: 'option', builder_options: ['--json'] },
|
|
1439
1442
|
],
|
|
1440
|
-
notes: ['Canvas publishing runs the same theme and form-open-container structure checks as compile before login or remote writes. --force does not bypass Canvas compilation checks. --health-check verifies saved content; inspect the actual page for runtime behavior. Fixed brand overrides are preserved with structured warnings by default. --strict-theme blocks them; --allow-fixed-brand conflicts with --strict-theme and --fix-theme. --fix-theme requires the migrated controls to be inside a mounted CanvasThemeProvider and compiles before writing. Unproven dynamic render paths require manual migration. No stdin prompts.'],
|
|
1443
|
+
notes: ['Canvas publishing runs the same theme and form-open-container structure checks as compile before login or remote writes. --force does not bypass Canvas compilation checks. --health-check verifies saved content; inspect the actual page for runtime behavior. Fixed brand overrides are preserved with structured warnings by default. --strict-theme blocks them; --allow-fixed-brand conflicts with --strict-theme and --fix-theme. --fix-theme requires the migrated controls to be inside a mounted CanvasThemeProvider and compiles before writing. Unproven dynamic render paths require manual migration. No stdin prompts.', 'Publishing reads persisted page navigation by default without a new flag. With renderNav=false, url and standaloneUrl use the clean /custom/<formUuid> route, with no navigation query parameters; workbenchUrl remains available. Unknown or visible navigation returns standaloneUrl=null; inspect navigationVerification and navigationWarning. A navigation read failure does not undo publication or prove standalone readiness. Configure scoped service frontend pages persistently before publishing; get-form-config can recover the verified URL without republishing.'],
|
|
1441
1444
|
}),
|
|
1442
1445
|
command('update-form-config', ['update-form-config'], 'update-form-config <appType> <formUuid> <true|false|keep> "<title>" [--locale zh_CN|en_US|ja_JP]', 'help.cmd_update_form_config', {
|
|
1443
1446
|
args: [
|
|
@@ -1456,7 +1459,7 @@ const COMMAND_GROUPS = [
|
|
|
1456
1459
|
{ name: 'formUuid', type: 'string', source: 'positional', position: 1, required: true },
|
|
1457
1460
|
{ name: 'json', type: 'boolean', source: 'option', builder_options: ['--json'] },
|
|
1458
1461
|
],
|
|
1459
|
-
notes: ['Navigation readback uses renderNav first, falling back to isRenderNav only when renderNav is absent. true/false booleans and strings are recognized; missing or invalid values remain unknown. --json includes the raw configuration; the default summary preserves both navigation fields when present.'],
|
|
1462
|
+
notes: ['Navigation readback uses renderNav first, falling back to isRenderNav only when renderNav is absent. true/false booleans and strings are recognized; missing or invalid values remain unknown. --json includes the raw configuration; the default summary preserves both navigation fields when present. For a confirmed display page, both outputs include url, workbenchUrl, standaloneUrl and navigationVerification. Only persisted renderNav=false returns a clean custom standaloneUrl; visible or unknown navigation returns standaloneUrl=null. Route construction does not verify publication or viewer permissions.'],
|
|
1460
1463
|
}),
|
|
1461
1464
|
],
|
|
1462
1465
|
},
|
|
@@ -1829,6 +1832,29 @@ function summarizeLocalizedCommands(commands) {
|
|
|
1829
1832
|
fallback: DEFAULT_DIVIDER_TYPE,
|
|
1830
1833
|
selection: 'Choose by each page business task and visual weight; keep same-level sections consistent within a page. Prefer suitable variation across different business pages. If the scene is unclear or suitable candidates tie, shuffle compatible candidates and rotate across pages, preferring unused styles until exhausted. Record one choice per page in design.md and dividerType before compilation; retries reuse it. Preserve existing supported styles for local edits.',
|
|
1831
1834
|
invalid_input: 'INVALID_DIVIDER_TYPE diagnostics; create rejects with CREATE_FORM_INVALID_DIVIDER_TYPE. Never silently replace a supplied unsupported style.',
|
|
1835
|
+
color_guidance: {
|
|
1836
|
+
reference: 'yida-skills/skills/yida-design/references/native-form-styles.md#分割线弱背景',
|
|
1837
|
+
mode: 'agent_design_guidance_only',
|
|
1838
|
+
default_mode: 'theme',
|
|
1839
|
+
custom_mode: 'custom',
|
|
1840
|
+
inputs: ['colorType', 'backgroundColor', 'secondaryColor', 'titleColor'],
|
|
1841
|
+
input_location: 'Field JSON for create/batch; changes for update; props in field-props operations for patch. Not CLI flags.',
|
|
1842
|
+
schema_paths: ['Divider.props.colorType', 'Divider.props.backgroundColor', 'Divider.props.secondaryColor', 'Divider.props.titleColor'],
|
|
1843
|
+
default_bindings: {
|
|
1844
|
+
primary: 'var(--color-brand1-6)',
|
|
1845
|
+
secondary: 'var(--color-brand1-2)',
|
|
1846
|
+
text: 'var(--color-text1-4, #171a1d)',
|
|
1847
|
+
},
|
|
1848
|
+
custom_when: 'The user requests colors, or default bindings do not suit the current theme, visual weight or readability. Design all three colors together; do not require user-specified values for each color. Reuse colors across peer sections.',
|
|
1849
|
+
dark_content: 'Distinguish dark content from dark navigation with light content. Treat brand1-2 as a weak brand surface, not permanently near-white. Root secondary overrides may lose to inline component bindings. For local repairs, prefer component colors when global changes would affect other consumers.',
|
|
1850
|
+
composite_titles: 'Consider outer decoration, the actual title surface and the title separately. In inner-ellipse-title the inner ellipse carries the text. Preserve existing supported shapes; do not dim the whole component to fix its background.',
|
|
1851
|
+
solid_title_surfaces: 'For dark-bar and light-left-title/light-center-title/light-house-title/light-hexagon-title, distinguish the primary-colored title block from the secondary strip. Prefer white or near-white on sufficiently dark primary surfaces; if a bright saturated fill weakens white text, deepen the component backgroundColor while preserving its hue. Do not force white onto pale surfaces. Set titleColor explicitly in custom mode instead of retaining its dark default; do not change global body text to fix a local title.',
|
|
1852
|
+
label_coordination: 'Design the divider title, first field label and input as a group. Share font family; use modest title weight/size emphasis, readable neutral labels, coordinated alignment and spacing. Preserve centered decorative headings without centering field labels. Keep the section gap larger than the title-to-first-field gap, and label-to-input spacing compact. Do not dim labels to create hierarchy or repeat excessive saturated decoration. The label role pod-form-label-color is separate from divider titleColor; record choices in existing design.md without new flags or blocking checks.',
|
|
1853
|
+
picker_icons: '--color-fill1-6 is a weak foreground for picker icons; choose a readable auxiliary foreground against the actual input surface, for example the current theme color-text1-3.',
|
|
1854
|
+
lifecycle: 'Record the choice in existing design.md. Revisit custom colors when changing themes; they do not automatically follow theme switching. Do not claim visual verification from a successful command or when preview is unavailable.',
|
|
1855
|
+
new_cli_flags: false,
|
|
1856
|
+
adds_validation_or_blocking: false,
|
|
1857
|
+
},
|
|
1832
1858
|
},
|
|
1833
1859
|
page_skill_policy: 'Use YidaCodeCanvas by default for new primary custom pages. Choose yida-custom-page only when the current target has been identified as existing .oyd.jsx/.oyb.jsx/renderJsx/platform Jsx component maintenance; do not switch to yida-custom-page merely because a page needs data, forms, uploads, this.utils.yida.*, or dataSourceMap-like capabilities.',
|
|
1834
1860
|
form_entry_policy: {
|
|
@@ -1904,6 +1930,8 @@ function summarizeLocalizedCommands(commands) {
|
|
|
1904
1930
|
custom: {
|
|
1905
1931
|
include: 'when_entry_mode_standalone_and_is_render_nav_false_readback',
|
|
1906
1932
|
url: '{base_url}/{appType}/custom/{formUuid}',
|
|
1933
|
+
default_policy: 'A scoped service frontend is a standalone display page even when entryMode was omitted. Plan derives it from role=service and sceneKey; Fast follows the same business intent. Persist page navigation hiding and read it back, without a new flag or navigation URL query. Preserve explicit user choices and backend navigation. Missing verification is incomplete frontend delivery, not permission to silently omit it.',
|
|
1934
|
+
url_source: 'publish.standaloneUrl or post-publish get-form-config.standaloneUrl; require navigationVerification.renderNav=false and verified=true',
|
|
1907
1935
|
},
|
|
1908
1936
|
admin: {
|
|
1909
1937
|
include: 'default_for_complete_application',
|
package/lib/core/locales/en.js
CHANGED
|
@@ -382,8 +382,8 @@ Examples:
|
|
|
382
382
|
save_permission_usage: 'Usage: openyida save-permission <appType> <formUuid> [--package-uuid <packageUuid>] [--data-permission <json>] [--action-permission <json>]',
|
|
383
383
|
save_permission_example: "Example: openyida save-permission APP_XXX FORM-XXX --data-permission '{\"role\":\"DEFAULT\",\"dataRange\":\"SELF\"}'",
|
|
384
384
|
exec_failed: '\n❌ Execution failed: {0}',
|
|
385
|
-
login_usage: 'Usage: openyida login [entryUrl|--public|--alibaba|--intl] [--no-browser] [--
|
|
386
|
-
login_example: 'Examples:\n openyida login # Automatically open the browser via OAuth loopback login\n openyida login --
|
|
385
|
+
login_usage: 'Usage: openyida login [entryUrl|--public|--alibaba|--intl] [--no-browser] [--check-only] [--json] [--client-id <clientId>]',
|
|
386
|
+
login_example: 'Examples:\n openyida login # Automatically open the browser via OAuth loopback login\n openyida login --no-browser # Let the caller handle the authorization URL\n openyida login --check-only --json # Check token auth status only\n openyida login --intl # Login against the international environment\n OPENYIDA_NO_BROWSER=1 openyida login # Suppress auto-opening the browser with an environment variable\n openyida auth login # Login alias',
|
|
387
387
|
login_unsupported_option: 'Removed legacy login option is no longer supported: {0}. Use token/OAuth login; env token mode reads only OPENYIDA_* tokens.',
|
|
388
388
|
auth_usage: 'Usage: openyida auth <status|login|refresh|logout|profiles|profile switch>',
|
|
389
389
|
auth_example: 'Examples:\n openyida auth status # View login status\n openyida auth profiles # List existing login profiles\n openyida auth profile switch <auth_profile> # Switch current project to an existing profile\n openyida auth login # Add a profile when the target does not exist\n openyida auth refresh # Refresh login session\n openyida auth logout # Unbind current project auth\n openyida auth logout --profile <auth_profile> # Delete a shared profile explicitly',
|
|
@@ -655,18 +655,6 @@ Examples:
|
|
|
655
655
|
oauth_success_message: 'Sign-in is complete. Return to the previous window to continue.',
|
|
656
656
|
oauth_closing: 'Closing this window automatically…',
|
|
657
657
|
oauth_manual_close: 'This window could not close automatically. Close it manually, then return to the previous window to continue.',
|
|
658
|
-
device_title: 'Device code login:',
|
|
659
|
-
device_open: 'Open',
|
|
660
|
-
device_enter_code: 'Enter code:',
|
|
661
|
-
device_or_direct: 'Or open directly:',
|
|
662
|
-
device_completed: 'Device authorization completed.',
|
|
663
|
-
device_timeout: 'device authorization timed out; device code may still be pending',
|
|
664
|
-
device_missing_params: 'device code flow requires authBaseUrl and clientId',
|
|
665
|
-
device_poll_missing_params: 'device token polling requires authBaseUrl, clientId and deviceCode',
|
|
666
|
-
device_invalid_code_response: 'auth service did not return a usable device code',
|
|
667
|
-
device_code_expired: 'device code expired; run login --device again',
|
|
668
|
-
device_access_denied: 'authorization was denied on the verification page',
|
|
669
|
-
device_2xx_no_token: 'auth service returned 2xx without accessToken',
|
|
670
658
|
oauth_failure_title: 'Sign-in not completed',
|
|
671
659
|
oauth_invalid_state: 'The sign-in request could not be verified. Return to the terminal and try again.',
|
|
672
660
|
oauth_missing_code: 'No authorization information was received. Return to the terminal and try again.',
|
package/lib/core/locales/zh.js
CHANGED
|
@@ -382,8 +382,8 @@ openyida - 宜搭命令行工具
|
|
|
382
382
|
save_permission_usage: '用法: openyida save-permission <appType> <formUuid> [--package-uuid <packageUuid>] [--data-permission <json>] [--action-permission <json>]',
|
|
383
383
|
save_permission_example: "示例: openyida save-permission APP_XXX FORM-XXX --data-permission '{\"role\":\"DEFAULT\",\"dataRange\":\"SELF\"}'",
|
|
384
384
|
exec_failed: '\n❌ 执行失败: {0}',
|
|
385
|
-
login_usage: '用法: openyida login [entryUrl|--public|--alibaba|--intl] [--no-browser] [--
|
|
386
|
-
login_example: '示例:\n openyida login # 通过 OAuth loopback 自动打开浏览器登录\n openyida login --
|
|
385
|
+
login_usage: '用法: openyida login [entryUrl|--public|--alibaba|--intl] [--no-browser] [--check-only] [--json] [--client-id <clientId>]',
|
|
386
|
+
login_example: '示例:\n openyida login # 通过 OAuth loopback 自动打开浏览器登录\n openyida login --no-browser # 不自动打开浏览器,由调用方接管授权链接\n openyida login --check-only --json # 只检查 token 登录态\n openyida login --intl # 使用国际站环境登录\n OPENYIDA_NO_BROWSER=1 openyida login # 通过环境变量抑制自动打开浏览器\n openyida auth login # 登录入口别名',
|
|
387
387
|
login_unsupported_option: '已删除的旧登录参数不再支持: {0}。请使用 token/OAuth 登录;env token 模式下只读取 OPENYIDA_* token。',
|
|
388
388
|
first_run_title: ' 🤖 OpenYida - AI 问答模式已开启! ',
|
|
389
389
|
first_run_welcome: ' {0}欢迎首次使用 OpenYida!{1} 以下是快速上手指南:',
|
|
@@ -626,18 +626,6 @@ openyida - 宜搭命令行工具
|
|
|
626
626
|
oauth_success_message: '登录已完成,请返回刚才的窗口继续操作。',
|
|
627
627
|
oauth_closing: '正在自动关闭此窗口…',
|
|
628
628
|
oauth_manual_close: '此窗口未能自动关闭,请手动关闭后返回刚才的窗口继续操作。',
|
|
629
|
-
device_title: '设备码登录:',
|
|
630
|
-
device_open: '打开',
|
|
631
|
-
device_enter_code: '输入验证码:',
|
|
632
|
-
device_or_direct: '或直接打开:',
|
|
633
|
-
device_completed: '设备授权完成。',
|
|
634
|
-
device_timeout: '设备授权超时;设备码可能仍在等待验证',
|
|
635
|
-
device_missing_params: '设备码流程需要 authBaseUrl 和 clientId',
|
|
636
|
-
device_poll_missing_params: '设备令牌轮询需要 authBaseUrl、clientId 和 deviceCode',
|
|
637
|
-
device_invalid_code_response: '认证服务未返回可用的设备码',
|
|
638
|
-
device_code_expired: '设备码已过期;请重新执行 login --device',
|
|
639
|
-
device_access_denied: '授权已在验证页面被拒绝',
|
|
640
|
-
device_2xx_no_token: '认证服务返回 2xx 但未包含 accessToken',
|
|
641
629
|
oauth_failure_title: '登录未完成',
|
|
642
630
|
oauth_invalid_state: '登录验证信息无效,请返回终端重新发起登录。',
|
|
643
631
|
oauth_missing_code: '未收到登录授权信息,请返回终端重新发起登录。',
|
|
@@ -16,6 +16,15 @@ const assert = (condition, message, details) => {
|
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
// Resource names are planning references. Runtime IDs and permissions are resolved after creation.
|
|
19
|
+
function resolvePageEntryMode(page, plan, { sceneKey, customNavigation }) {
|
|
20
|
+
const supplied = page.pageSpecHandoff || {};
|
|
21
|
+
const entries = plan.execution?.entryRecommendation?.entries;
|
|
22
|
+
const servicePage = Array.isArray(entries) && entries.some(entry =>
|
|
23
|
+
entry?.role === 'service' && filled(entry.sceneKey) && entry.sceneKey === sceneKey);
|
|
24
|
+
return supplied.entryMode || page.entryMode ||
|
|
25
|
+
(servicePage || customNavigation || supplied.navigation ? 'standalone' : 'platform-shell');
|
|
26
|
+
}
|
|
27
|
+
|
|
19
28
|
function buildEntryNavigation(plan, resources, pages) {
|
|
20
29
|
const recommendation = plan.execution?.entryRecommendation;
|
|
21
30
|
if (recommendation === undefined) {return null;}
|
|
@@ -94,4 +103,4 @@ function buildEntryNavigation(plan, resources, pages) {
|
|
|
94
103
|
return { recommendation: JSON.parse(JSON.stringify(recommendation)), platformOrder: [...new Set(platformOrder)] };
|
|
95
104
|
}
|
|
96
105
|
|
|
97
|
-
module.exports = { buildEntryNavigation, ENTRY_MODES, ENTRY_MODE_SUMMARIES };
|
|
106
|
+
module.exports = { buildEntryNavigation, resolvePageEntryMode, ENTRY_MODES, ENTRY_MODE_SUMMARIES };
|
package/lib/design-plan/init.js
CHANGED
|
@@ -233,7 +233,8 @@ function initialize(inputPath, options = {}) {
|
|
|
233
233
|
'# 计划编写上下文', '', `需求事实:${input}`, `计划目录:${outputDir}`, '',
|
|
234
234
|
`读取本上下文、编写契约和 business.json;按 authoring.pendingFields 补齐事实,保留 base 与已有需求。business facts 填写 overview、dataModels、businessFlows、pages 和可选 execution;视觉填写 visual.json。复核业务覆盖后设置片段 ready=true,再执行:${materializeCommand}。使用成功结果中的 HTML 路径展示“当前方案”,revision 仅放在内部确认字段,不写入用户可见标题、摘要或问题。视觉片段按每页实际任务补齐焦点、布局、主操作、响应式与验收;已完成的选择直接复用。`, '',
|
|
235
235
|
'## 本轮编写重点', '设计功能范围、数据与规则、页面组织、关键交互和业务验收。页面 blocks 按优先顺序填写 {name,purpose};CLI 派生默认内容优先级与内容层次,保留明确填写的独立设计。通用状态和验收检查由 CLI 补齐,interactionStates 与 acceptanceCriteria 填写项目差异。', '',
|
|
236
|
-
'首页按使用者的主要任务选择:集中办事可用门户式工作台(workbench),单项任务可直达原生业务页;只有已确认的指标分析或投屏监控任务才规划 dashboard/screen
|
|
236
|
+
'首页按使用者的主要任务选择:集中办事可用门户式工作台(workbench),单项任务可直达原生业务页;只有已确认的指标分析或投屏监控任务才规划 dashboard/screen。工作台是围绕应用核心业务,把全局概况、业务管理、分析判断、异常处理和常用快捷入口组织在一起的综合工作空间;包含分析区块不自动改变整页主任务。不得从后台身份、系统名称或暗色风格自动增加驾驶舱。完整规则见 yida-requirement-analysis/references/experience-groups.md 的“首页按任务选择”。', '',
|
|
237
|
+
'工作台按角色与业务关系规划,参考 8-10 个有独立价值的区块;采用适合信息特点的表现形式,数据和洞察有依据,操作与快捷入口可用,不套固定列表组合。', '',
|
|
237
238
|
'无论是否分前后台,每个业务入口都要确定默认页面、菜单及分组顺序、打开后的首屏任务。menu 数组记录展示顺序,defaultMenuKey 记录默认任务;按角色需求决定,不按资源创建先后排列。平台导航通过排序命令落实,自定义导航通过页面菜单落实,frontend-only 也必须完成入口排序与首页验收。', '',
|
|
238
239
|
'入口方案沿用 execution.entryRecommendation:unified 表示不分前后台,service-management 表示分前后台,frontend-only 表示只有访问前台,backend-only 表示只有访问后台。向用户说明谁使用、看到什么、能做什么;只有前台且提交后需要处理时,在 reason 和业务流程中说明承接方式;逐入口补齐 role、menu 和 defaultMenuKey,前台关联独立页面 sceneKey。任何身份的入口含 local 菜单时,entry.sceneKey 必须关联承载页面,menu.resource 等于页面 name,viewKey 非空。管理端可直接落到原生业务视图,不强制创建首页。所有叶子菜单按资源、视图和操作记录 access 权限依赖,平台导航排序从管理菜单派生。详见 yida-app/references/entry-navigation.md。', '',
|
|
239
240
|
theme.mode === 'creative'
|
|
@@ -9,7 +9,7 @@ const { normalizePlan, assertThemeProfile } = require('./normalize');
|
|
|
9
9
|
const { readJson, writeFiles } = require('./files');
|
|
10
10
|
const { prepareUpdates } = require('./artifact-updates');
|
|
11
11
|
const { validateAuthoring } = require('./validate');
|
|
12
|
-
const { buildEntryNavigation, ENTRY_MODE_SUMMARIES } = require('./entry-navigation');
|
|
12
|
+
const { buildEntryNavigation, resolvePageEntryMode, ENTRY_MODE_SUMMARIES } = require('./entry-navigation');
|
|
13
13
|
const { buildPageNavigationPolicy } = require('./navigation-policy');
|
|
14
14
|
const { buildAssetTasks } = require('../asset/asset-plan');
|
|
15
15
|
const { mergeParts } = require('./parallel');
|
|
@@ -216,7 +216,7 @@ function pageHandoff(page, plan) {
|
|
|
216
216
|
detail: 'detail-profile', landing: 'official-homepage', screen: 'data-screen',
|
|
217
217
|
};
|
|
218
218
|
const customNavigation = navigationConfig(plan).navigationType === 'custom';
|
|
219
|
-
const entryMode =
|
|
219
|
+
const entryMode = resolvePageEntryMode(page, plan, { sceneKey: page.sceneKey || scene, customNavigation });
|
|
220
220
|
requireFact(!customNavigation || entryMode === 'standalone', `自定义导航的页面 ${page.name} 必须使用 standalone 入口`);
|
|
221
221
|
if (supplied.navigation !== undefined) {
|
|
222
222
|
const nav = supplied.navigation;
|
|
@@ -277,7 +277,9 @@ function pageNavigationRows(page, plan) {
|
|
|
277
277
|
const handoff = page.pageSpecHandoff || {};
|
|
278
278
|
const applicationCustom = navigationConfig(plan).navigationType === 'custom';
|
|
279
279
|
const menu = handoff.navigation;
|
|
280
|
-
const entryMode =
|
|
280
|
+
const entryMode = resolvePageEntryMode(page, plan, {
|
|
281
|
+
sceneKey: page.sceneKey || sceneForPage(page), customNavigation: applicationCustom,
|
|
282
|
+
});
|
|
281
283
|
const variants = { top: '顶部', side: '侧边', mixed: '顶部与侧边', dock: '底部' };
|
|
282
284
|
return [
|
|
283
285
|
['访问方式', entryMode === 'standalone' ? '独立页面入口' : '应用工作区入口'],
|
|
@@ -613,7 +615,7 @@ function renderProjectApplications(plan, tokens, color, chapter) {
|
|
|
613
615
|
'--color-brand1-6': '主色与主要品牌操作', '--color-brand1-1': '品牌悬停',
|
|
614
616
|
'--color-brand1-9': '品牌按下', '--color-brand1-10': '品牌禁用',
|
|
615
617
|
'--pod-page-bg-color': '页面画布', '--pod-card-bg-color': '内容容器',
|
|
616
|
-
'--color-fill1-5': '独立浮层', '--color-fill1-10': 'Tooltip背景', '--color-text1-5': 'Tooltip前景',
|
|
618
|
+
'--color-fill1-5': '独立浮层', '--color-fill1-6': '弱图标与辅助操作', '--color-fill1-10': 'Tooltip背景', '--color-text1-5': 'Tooltip前景',
|
|
617
619
|
};
|
|
618
620
|
return [
|
|
619
621
|
'## 5. 项目应用与调整规则', '',
|
package/package.json
CHANGED
|
@@ -108,7 +108,7 @@ Plan 规划阶段的工作流入口只读取 `workflow/step-1-resource-context.m
|
|
|
108
108
|
- 需要收集或存储数据:先创建或复用核心普通表单,再生成页面;纯展示或静态内容可跳过表单创建。
|
|
109
109
|
- 需要审批、申请、审核、工单流转:先创建或复用流程表单,再生成页面。
|
|
110
110
|
- 需要标准统计:优先创建原生报表;明确高级图表或大屏时,再选择 `yida-rechart` / `yida-chart`。
|
|
111
|
-
- 按页面主任务选技能:经营分析、指标判断或投屏监控页面加载 `yida-dashboard
|
|
111
|
+
- 按页面主任务选技能:经营分析、指标判断或投屏监控页面加载 `yida-dashboard`;综合工作台由 `yida-canvas-custom-page` 实现,按 PRD 组织内容;其中的分析、洞察及快捷操作按实际需要实现,不能仅凭“工作台”或“看板”名称加载经营看板技能。页面读取任何表单业务数据时继续加载 `yida-canvas-data-binding`。
|
|
112
112
|
- PRD 明确包含报表或集成自动化时,它们属于 Step 4 主流程资源,不得推迟到 final 后置建议;自动化动作必须按通知、数据新增/更新、审批完成、定时或手动触发分别建模,不得统一退化成新增通知。
|
|
113
113
|
|
|
114
114
|
## 页面数据契约
|