openyida 2026.7.19 → 2026.7.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/README.md +14 -0
  2. package/bin/yida.js +107 -18
  3. package/lib/app/create-app.js +12 -1
  4. package/lib/app/create-form/args.js +13 -0
  5. package/lib/app/create-form.js +154 -67
  6. package/lib/app/create-page.js +45 -9
  7. package/lib/app/get-schema.js +65 -14
  8. package/lib/app/import-app.js +92 -41
  9. package/lib/app/publish.js +289 -556
  10. package/lib/app/schema-field-resolution.js +370 -0
  11. package/lib/app/services/app-reader.js +85 -0
  12. package/lib/app/services/app-service.js +235 -0
  13. package/lib/app/services/canvas-page-compiler.js +91 -0
  14. package/lib/app/services/canvas-page-schema-builder.js +149 -0
  15. package/lib/app/services/field-bindings.js +68 -0
  16. package/lib/app/services/form-compiler.js +1922 -0
  17. package/lib/app/services/form-mode-service.js +182 -0
  18. package/lib/app/services/form-schema-patcher.js +333 -0
  19. package/lib/app/services/form-schema-reader.js +59 -0
  20. package/lib/app/services/form-service.js +379 -0
  21. package/lib/app/services/form-validation.js +562 -0
  22. package/lib/app/services/native-page-compiler.js +92 -0
  23. package/lib/app/services/native-page-schema-builder.js +428 -0
  24. package/lib/app/services/page-resource-service.js +185 -0
  25. package/lib/app/update-app.js +18 -6
  26. package/lib/auth/token-auth.js +34 -3
  27. package/lib/auth/token-store.js +22 -4
  28. package/lib/bridge/bridge.js +37 -5
  29. package/lib/core/agent-capabilities.js +5 -3
  30. package/lib/core/command-manifest.js +40 -0
  31. package/lib/core/doctor.js +15 -4
  32. package/lib/core/env-cmd.js +1 -1
  33. package/lib/core/env.js +7 -6
  34. package/lib/core/legacy-schema-guard.js +408 -0
  35. package/lib/core/locales/en.js +8 -46
  36. package/lib/core/locales/zh.js +8 -46
  37. package/lib/core/sample.js +1 -1
  38. package/lib/core/utils.js +334 -66
  39. package/lib/core/yida-client.js +104 -3
  40. package/lib/formula/evaluate.js +8 -66
  41. package/lib/formula/field-refs.js +83 -0
  42. package/lib/process/configure-process.js +44 -1992
  43. package/lib/process/create-process.js +54 -87
  44. package/lib/process/services/process-compiler.js +2056 -0
  45. package/lib/process/services/process-reader.js +232 -0
  46. package/lib/process/services/process-resource-service.js +571 -0
  47. package/lib/process/services/process-service.js +122 -0
  48. package/lib/process/services/process-stage-checkpoint.js +246 -0
  49. package/lib/report/append.js +7 -26
  50. package/lib/report/http.js +31 -5
  51. package/lib/report/index.js +10 -2
  52. package/lib/samples/yida-canvas-custom-page/business-list.canvas.jsx +63 -14
  53. package/lib/samples/yida-canvas-custom-page/dashboard-overview.canvas.jsx +176 -32
  54. package/lib/samples/yida-canvas-custom-page/data-management.canvas.jsx +228 -14
  55. package/lib/samples/yida-canvas-custom-page/split-pane-detail.canvas.jsx +204 -8
  56. package/lib/schema/adapters/app-adapter.js +210 -0
  57. package/lib/schema/adapters/form-adapter.js +1362 -0
  58. package/lib/schema/adapters/keys.js +19 -0
  59. package/lib/schema/adapters/page-adapter.js +566 -0
  60. package/lib/schema/adapters/process-adapter.js +519 -0
  61. package/lib/schema/applier.js +1878 -0
  62. package/lib/schema/apply-store.js +1083 -0
  63. package/lib/schema/command.js +645 -0
  64. package/lib/schema/dependency-graph.js +83 -0
  65. package/lib/schema/errors.js +481 -0
  66. package/lib/schema/hash.js +9 -0
  67. package/lib/schema/manifest-limits.js +177 -0
  68. package/lib/schema/manifest-loader.js +309 -0
  69. package/lib/schema/manifest-schema-v1.json +193 -0
  70. package/lib/schema/normalize-manifest.js +281 -0
  71. package/lib/schema/page-canvas-foundation.js +447 -0
  72. package/lib/schema/page-data-source-builder.js +561 -0
  73. package/lib/schema/page-foundation.js +556 -0
  74. package/lib/schema/page-source-loader.js +314 -0
  75. package/lib/schema/planner.js +691 -0
  76. package/lib/schema/remote-dispatch-boundary.js +39 -0
  77. package/lib/schema/remote-missing.js +21 -0
  78. package/lib/schema/remote-reader.js +189 -0
  79. package/lib/schema/resource-registry.js +157 -0
  80. package/lib/schema/server-revision.js +71 -0
  81. package/lib/schema/sort.js +28 -0
  82. package/lib/schema/state-store.js +589 -0
  83. package/package.json +2 -2
  84. package/scripts/postinstall.js +8 -12
  85. package/scripts/validate-package-size.js +1 -1
  86. package/yida-skills/SKILL.md +114 -29
  87. package/yida-skills/references/schema-as-code-phase1.md +99 -0
  88. package/yida-skills/references/setup-and-env.md +59 -59
  89. package/yida-skills/references/task-retrospective.md +6 -6
  90. package/yida-skills/skills/yida-app/SKILL.md +60 -14
  91. package/yida-skills/skills/yida-canvas-custom-page/SKILL.md +18 -7
  92. package/yida-skills/skills/yida-canvas-custom-page/references/data-bridge-guide.md +3 -3
  93. package/yida-skills/skills/yida-canvas-custom-page/references/page-generation-guide.md +7 -1
  94. package/yida-skills/skills/yida-create-app/SKILL.md +21 -3
  95. package/yida-skills/skills/yida-create-form-page/SKILL.md +19 -1
  96. package/yida-skills/skills/yida-create-page/SKILL.md +16 -3
  97. package/yida-skills/skills/yida-create-process/SKILL.md +100 -4
  98. package/yida-skills/skills/yida-custom-page/SKILL.md +19 -4
  99. package/yida-skills/skills/yida-dashboard/SKILL.md +1 -1
  100. package/yida-skills/skills/yida-dashboard/references/pitfalls.md +1 -1
  101. package/yida-skills/skills/yida-get-schema/SKILL.md +49 -5
  102. package/yida-skills/skills/yida-i18n/SKILL.md +1 -1
  103. package/yida-skills/skills/yida-integration/SKILL.md +7 -1
  104. package/yida-skills/skills/yida-login/SKILL.md +50 -99
  105. package/yida-skills/skills/yida-page-config/SKILL.md +7 -1
  106. package/yida-skills/skills/yida-page-uiux/references/app/blueprint.md +0 -1
  107. package/yida-skills/skills/yida-page-uiux/references/app/navigation-patterns.md +0 -1
  108. package/yida-skills/skills/yida-page-uiux/references/app/role-journey.md +0 -1
  109. package/yida-skills/skills/yida-page-uiux/references/dashboard/app-blueprint.md +0 -1
  110. package/yida-skills/skills/yida-page-uiux/references/dashboard/chart-contracts.md +0 -1
  111. package/yida-skills/skills/yida-page-uiux/references/dashboard/component-contracts.md +0 -1
  112. package/yida-skills/skills/yida-page-uiux/references/dashboard/layout-patterns.md +0 -1
  113. package/yida-skills/skills/yida-page-uiux/references/dashboard/theme-recipes.md +0 -1
  114. package/yida-skills/skills/yida-page-uiux/references/detail/object-narrative.md +0 -1
  115. package/yida-skills/skills/yida-page-uiux/references/detail/section-patterns.md +0 -1
  116. package/yida-skills/skills/yida-page-uiux/references/detail/timeline-and-related.md +0 -1
  117. package/yida-skills/skills/yida-page-uiux/references/landing/assets-workflow.md +0 -1
  118. package/yida-skills/skills/yida-page-uiux/references/landing/industry-playbooks.md +0 -1
  119. package/yida-skills/skills/yida-page-uiux/references/landing/research-levels.md +0 -1
  120. package/yida-skills/skills/yida-page-uiux/references/landing/section-patterns.md +0 -1
  121. package/yida-skills/skills/yida-page-uiux/references/list/drawer-detail.md +0 -1
  122. package/yida-skills/skills/yida-page-uiux/references/list/empty-loading-error.md +0 -1
  123. package/yida-skills/skills/yida-page-uiux/references/list/filter-patterns.md +0 -1
  124. package/yida-skills/skills/yida-page-uiux/references/list/table-patterns.md +0 -1
  125. package/yida-skills/skills/yida-page-uiux/references/scenes/screen.md +0 -1
  126. package/yida-skills/skills/yida-page-uiux/references/workbench/entry-patterns.md +0 -1
  127. package/yida-skills/skills/yida-page-uiux/references/workbench/portal-layouts.md +0 -1
  128. package/yida-skills/skills/yida-page-uiux/references/workbench/task-feed.md +0 -1
  129. package/yida-skills/skills/yida-page-uiux/workflow/output-decision-block.md +1 -1
  130. package/yida-skills/skills/yida-process-rule/SKILL.md +35 -1
  131. package/yida-skills/skills/yida-publish-page/SKILL.md +46 -4
  132. package/yida-skills/skills/yida-report/SKILL.md +7 -1
  133. package/yida-skills/skills-index.json +14 -46
  134. package/yida-skills/skills/large-file-write/SKILL.md +0 -93
  135. package/yida-skills/skills/large-file-write/references/write-patterns.md +0 -147
  136. package/yida-skills/skills/large-file-write/scripts/write.js +0 -157
  137. package/yida-skills/skills/sls-log-workbench/SKILL.md +0 -134
  138. package/yida-skills/skills/sls-log-workbench/references/workbench-reference.md +0 -130
  139. package/yida-skills/skills/sls-log-workbench/sls-query.js +0 -295
@@ -13,8 +13,10 @@ const {
13
13
  const { runDingtalkLoopback } = require('./oauth-loopback');
14
14
  const {
15
15
  clearTokenSession,
16
+ isHostInjectedTokenMode,
16
17
  loadTokenSession,
17
18
  maskToken,
19
+ normalizeTokenSession,
18
20
  saveTokenSession,
19
21
  } = require('./token-store');
20
22
 
@@ -35,6 +37,7 @@ function appendPath(baseUrl, path) {
35
37
 
36
38
  function getArgEndpoint(options = {}) {
37
39
  return options.endpoint ||
40
+ (options.env && options.env.OPENYIDA_ENDPOINT) ||
38
41
  null;
39
42
  }
40
43
 
@@ -49,7 +52,8 @@ function resolveTokenBaseUrl(options = {}) {
49
52
  }
50
53
 
51
54
  const { config } = getCurrentEnvConfig(options.projectRoot);
52
- const baseUrl = normalizeBaseUrl(process.env.OPENYIDA_ENDPOINT || config.baseUrl, null);
55
+ const env = options.env || process.env;
56
+ const baseUrl = normalizeBaseUrl(env.OPENYIDA_ENDPOINT || config.baseUrl, null);
53
57
  if (!baseUrl) {
54
58
  throw new Error('missing base_url: pass --endpoint or set OPENYIDA_ENDPOINT');
55
59
  }
@@ -299,18 +303,29 @@ async function tokenLogin(options = {}) {
299
303
  function tokenStatus(options = {}) {
300
304
  const session = loadTokenSession(options);
301
305
  if (!session || (!session.access_token && !session.refresh_token)) {
302
- return {
306
+ const env = options.env || process.env;
307
+ const hostInjected = isHostInjectedTokenMode(env);
308
+ const status = {
303
309
  ok: false,
304
310
  auth_mode: 'token',
311
+ auth_source: hostInjected ? 'env' : undefined,
305
312
  status: 'not_logged_in',
306
313
  can_auto_use: false,
307
- token_file: require('./token-store').getTokenFilePath(options),
314
+ failure_reason: hostInjected ? 'env_token_missing' : undefined,
315
+ message: hostInjected
316
+ ? 'host-injected token is missing. Ask the host to inject OPENYIDA_ACCESS_TOKEN or OPENYIDA_REFRESH_TOKEN.'
317
+ : undefined,
308
318
  };
319
+ if (!hostInjected) {
320
+ status.token_file = require('./token-store').getTokenFilePath(options);
321
+ }
322
+ return status;
309
323
  }
310
324
  if (!session.access_token && session.refresh_token) {
311
325
  return {
312
326
  ok: true,
313
327
  auth_mode: 'token',
328
+ auth_source: session.auth_source,
314
329
  status: 'refresh_required',
315
330
  can_auto_use: true,
316
331
  refresh_token: maskToken(session.refresh_token),
@@ -324,6 +339,7 @@ function tokenStatus(options = {}) {
324
339
  // whether this access token must be refreshed.
325
340
  ok: true,
326
341
  auth_mode: 'token',
342
+ auth_source: session.auth_source,
327
343
  status: 'ok',
328
344
  can_auto_use: true,
329
345
  token_type: session.token_type,
@@ -343,6 +359,7 @@ async function tokenRefresh(options = {}) {
343
359
  return {
344
360
  ok: false,
345
361
  auth_mode: 'token',
362
+ auth_source: session && session.auth_source,
346
363
  status: 'missing_refresh_token',
347
364
  can_auto_use: false,
348
365
  };
@@ -380,6 +397,20 @@ async function tokenRefresh(options = {}) {
380
397
  message: normalized.message || 'auth service did not return access_token',
381
398
  };
382
399
  }
400
+ const env = options.env || process.env;
401
+ if (isHostInjectedTokenMode(env) && session.auth_source === 'env') {
402
+ env.OPENYIDA_ACCESS_TOKEN = normalized.access_token;
403
+ if (normalized.refresh_token) {
404
+ env.OPENYIDA_REFRESH_TOKEN = normalized.refresh_token;
405
+ }
406
+ if (normalized.expires_at) {
407
+ env.OPENYIDA_ACCESS_TOKEN_EXPIRES_AT = String(normalized.expires_at);
408
+ }
409
+ return normalizeTokenSession({
410
+ ...normalized,
411
+ auth_source: 'env',
412
+ });
413
+ }
383
414
  return saveTokenSession(normalized, options);
384
415
  }
385
416
 
@@ -119,17 +119,27 @@ function saveTokenSession(session, options = {}) {
119
119
  return normalized;
120
120
  }
121
121
 
122
+ function isHostInjectedTokenMode(env = process.env) {
123
+ const authEnabled = String(env.YIDA_AUTH_ENABLED || '').trim().toLowerCase();
124
+ return ['1', 'true', 'yes', 'on'].includes(authEnabled);
125
+ }
126
+
122
127
  function loadEnvTokenSession(env = process.env) {
128
+ const accessToken = String(env.OPENYIDA_ACCESS_TOKEN || '').trim();
123
129
  const refreshToken = String(env.OPENYIDA_REFRESH_TOKEN || '').trim();
124
- if (!refreshToken) {
130
+ if (!accessToken && !refreshToken) {
125
131
  return null;
126
132
  }
127
133
  return normalizeTokenSession({
134
+ access_token: accessToken,
128
135
  refresh_token: refreshToken,
129
136
  base_url: env.OPENYIDA_ENDPOINT,
130
137
  client_id: env.OPENYIDA_TOKEN_CLIENT_ID,
131
138
  corp_id: env.OPENYIDA_TOKEN_CORP_ID,
132
139
  user_id: env.OPENYIDA_TOKEN_USER_ID,
140
+ token_type: env.OPENYIDA_TOKEN_TYPE,
141
+ expires_at: env.OPENYIDA_ACCESS_TOKEN_EXPIRES_AT,
142
+ expires_in: env.OPENYIDA_ACCESS_TOKEN_EXPIRES_IN,
133
143
  auth_source: 'env',
134
144
  });
135
145
  }
@@ -147,24 +157,31 @@ function loadLocalTokenSession(options = {}) {
147
157
  }
148
158
 
149
159
  function loadTokenSession(options = {}) {
160
+ const env = options.env || process.env;
161
+ const envSession = loadEnvTokenSession(env);
162
+ if (isHostInjectedTokenMode(env)) {
163
+ return envSession;
164
+ }
165
+
150
166
  const localSession = loadLocalTokenSession(options);
151
- const envSession = loadEnvTokenSession(options.env || process.env);
152
167
  if (!localSession && !envSession) {
153
168
  return null;
154
169
  }
155
170
 
156
171
  const localAccessToken = localSession && localSession.access_token;
157
172
  const localRefreshToken = localSession && localSession.refresh_token;
173
+ const envAccessToken = envSession && envSession.access_token;
158
174
  const envRefreshToken = envSession && envSession.refresh_token;
159
175
  const usesLocal = Boolean(localAccessToken || localRefreshToken);
160
176
  const usesEnv = Boolean(
161
- !localRefreshToken && envRefreshToken
177
+ (!localAccessToken && !localRefreshToken && envAccessToken) ||
178
+ (!localRefreshToken && envRefreshToken)
162
179
  );
163
180
 
164
181
  return normalizeTokenSession({
165
182
  ...(envSession || {}),
166
183
  ...(localSession || {}),
167
- access_token: localAccessToken,
184
+ access_token: localAccessToken || (!localSession && envAccessToken),
168
185
  refresh_token: localRefreshToken || envRefreshToken,
169
186
  auth_source: usesLocal && usesEnv ? 'mixed' : (usesLocal ? 'local' : 'env'),
170
187
  });
@@ -210,6 +227,7 @@ module.exports = {
210
227
  normalizeTokenSession,
211
228
  loadEnvTokenSession,
212
229
  loadLocalTokenSession,
230
+ isHostInjectedTokenMode,
213
231
  isAccessTokenUsable,
214
232
  maskToken,
215
233
  resolveEnvName,
@@ -516,6 +516,7 @@ function sanitizeLoginResult(result = {}) {
516
516
  canAutoUse: !!(result.can_auto_use || result.canAutoUse),
517
517
  loggedIn: status === 'ok',
518
518
  authMode: result.auth_mode || result.authMode,
519
+ authSource: result.auth_source || result.authSource,
519
520
  baseUrlOrigin: originFromUrl(result.base_url || result.baseUrl),
520
521
  corpId: maskId(result.corp_id || result.corpId),
521
522
  userId: maskId(result.user_id || result.userId),
@@ -537,6 +538,36 @@ function sanitizeQrLoginStart(result = {}, loginSessionId) {
537
538
  };
538
539
  }
539
540
 
541
+ function isTokenLoginStartResult(result = {}) {
542
+ const authMode = result.auth_mode || result.authMode;
543
+ return authMode === 'token' || result.status === 'token_login_required';
544
+ }
545
+
546
+ function sanitizeTokenLoginStart(result = {}) {
547
+ const status = result.status || 'token_login_required';
548
+ return {
549
+ status,
550
+ canAutoUse: !!(result.can_auto_use || result.canAutoUse),
551
+ loggedIn: status === 'ok',
552
+ authMode: result.auth_mode || result.authMode || 'token',
553
+ authSource: result.auth_source || result.authSource,
554
+ baseUrlOrigin: originFromUrl(result.base_url || result.baseUrl),
555
+ corpId: maskId(result.corp_id || result.corpId),
556
+ userId: maskId(result.user_id || result.userId),
557
+ diagnostics: sanitizeDiagnostics(result.diagnostics || {}),
558
+ pollable: false,
559
+ loginSessionId: null,
560
+ message: result.message ? String(result.message).slice(0, 300) : undefined,
561
+ };
562
+ }
563
+
564
+ function sanitizeLoginStart(result = {}, loginSessionId) {
565
+ if (isTokenLoginStartResult(result)) {
566
+ return sanitizeTokenLoginStart(result);
567
+ }
568
+ return sanitizeQrLoginStart(result, loginSessionId);
569
+ }
570
+
540
571
  function getBridgeInfo(state) {
541
572
  return {
542
573
  ok: true,
@@ -560,8 +591,8 @@ function getBridgeInfo(state) {
560
591
  }
561
592
 
562
593
  function defaultCheckLogin() {
563
- const { tokenStatus } = require('../auth/token-auth');
564
- return tokenStatus({ includeSecrets: false });
594
+ const { getAuthStatus } = require('../core/utils');
595
+ return getAuthStatus({ includeSecrets: false });
565
596
  }
566
597
 
567
598
  async function defaultStartLogin() {
@@ -766,8 +797,9 @@ async function handleLoginStart(req, res, state) {
766
797
 
767
798
  const startLogin = getHandler(state, 'startLogin', defaultStartLogin);
768
799
  const result = await startLogin(body);
769
- const loginSessionId = randomToken();
770
- if (result.session_file) {
800
+ const tokenLoginStart = isTokenLoginStartResult(result);
801
+ const loginSessionId = tokenLoginStart ? null : randomToken();
802
+ if (!tokenLoginStart && result && result.session_file) {
771
803
  state.loginSessions.set(loginSessionId, {
772
804
  sessionFile: result.session_file,
773
805
  createdAt: new Date().toISOString(),
@@ -776,7 +808,7 @@ async function handleLoginStart(req, res, state) {
776
808
 
777
809
  respondJson(req, res, state, 200, {
778
810
  ok: true,
779
- login: sanitizeQrLoginStart(result, loginSessionId),
811
+ login: sanitizeLoginStart(result, loginSessionId),
780
812
  });
781
813
  }
782
814
 
@@ -6,7 +6,7 @@ const { version } = require('../../package.json');
6
6
  const { t } = require('./i18n');
7
7
  const { buildCommandManifest } = require('./command-manifest');
8
8
  const { buildEnvironmentSnapshot } = require('./env');
9
- const { tokenStatus } = require('../auth/token-auth');
9
+ const { getAuthStatus } = require('./utils');
10
10
 
11
11
  function redactLogin(login) {
12
12
  const redacted = { ...login };
@@ -18,6 +18,8 @@ function redactLogin(login) {
18
18
  function compactLogin(login) {
19
19
  return {
20
20
  status: login.status,
21
+ auth_mode: login.auth_mode,
22
+ auth_source: login.auth_source,
21
23
  can_auto_use: login.can_auto_use === true,
22
24
  };
23
25
  }
@@ -68,9 +70,9 @@ function buildCommandManifestDigest(manifest) {
68
70
 
69
71
  function buildAgentCapabilitiesSummary() {
70
72
  const envSnapshot = buildEnvironmentSnapshot();
71
- const loginStatus = tokenStatus({ includeSecrets: false });
72
73
  const manifest = buildCommandManifest({ t, version });
73
74
  const projectRoot = envSnapshot.active.projectRoot;
75
+ const loginStatus = getAuthStatus({ projectRoot, includeSecrets: false });
74
76
 
75
77
  return {
76
78
  schema_version: 1,
@@ -90,9 +92,9 @@ function buildAgentCapabilitiesSummary() {
90
92
 
91
93
  function buildAgentCapabilities() {
92
94
  const envSnapshot = buildEnvironmentSnapshot();
93
- const loginStatus = redactLogin(tokenStatus({ includeSecrets: false }));
94
95
  const manifest = buildCommandManifest({ t, version });
95
96
  const projectRoot = envSnapshot.active.projectRoot;
97
+ const loginStatus = redactLogin(getAuthStatus({ projectRoot, includeSecrets: false }));
96
98
 
97
99
  return {
98
100
  schema_version: 1,
@@ -193,8 +193,13 @@ const COMMAND_SIDE_EFFECTS = new Map([
193
193
  'dingtalk-link',
194
194
  'formula.evaluate',
195
195
  'integration.diagnose',
196
+ 'schema.validate',
196
197
  ], sideEffect('local_read')),
197
198
 
199
+ ...sideEffectEntries([
200
+ 'schema.plan',
201
+ ], sideEffect('remote_read')),
202
+
198
203
  ...sideEffectEntries([
199
204
  'build-page',
200
205
  'cdn-config',
@@ -286,6 +291,12 @@ const COMMAND_SIDE_EFFECTS = new Map([
286
291
  read_actions: ['text', 'image --image-url'],
287
292
  mutating_actions: ['image --file'],
288
293
  })],
294
+ ['schema.apply', sideEffect('mixed', {
295
+ mutates_yida: true,
296
+ mutates_local: true,
297
+ read_actions: [],
298
+ mutating_actions: ['apply'],
299
+ })],
289
300
  ['ai-form-setting', sideEffect('mixed', {
290
301
  mutates_yida: true,
291
302
  mutates_local: false,
@@ -452,6 +463,8 @@ const COMMAND_PERMISSIONS = new Map([
452
463
  'integration.list',
453
464
  'list-forms',
454
465
  'process.preview',
466
+ 'schema.plan',
467
+ 'schema.validate',
455
468
  'verify-short-url',
456
469
  ], permission('allow', 'read', {
457
470
  reason: 'Read-only, diagnostic, validation, or manifest discovery command.',
@@ -510,6 +523,17 @@ const COMMAND_PERMISSIONS = new Map([
510
523
  reason: ALLOW_WRITE_REASON,
511
524
  })),
512
525
 
526
+ ['schema.apply', permission('allow', 'write', {
527
+ reason: ALLOW_WRITE_REASON,
528
+ action_dependent: true,
529
+ read_actions: [],
530
+ preauthorized_actions: ['apply'],
531
+ preauthorized_patterns: [],
532
+ ask_actions: [],
533
+ ask_patterns: [],
534
+ unknown_action_mode: 'ask',
535
+ })],
536
+
513
537
  ...permissionEntries([
514
538
  'login',
515
539
  'logout',
@@ -799,6 +823,22 @@ const COMMAND_GROUPS = [
799
823
  command('get-form-config', ['get-form-config'], 'get-form-config <appType> <formUuid> [--json]', 'help.cmd_get_form_config', { output: 'json' }),
800
824
  ],
801
825
  },
826
+ {
827
+ id: 'schema',
828
+ titleKey: 'help.group_schema',
829
+ commands: [
830
+ command('schema.validate', ['schema', 'validate'], 'schema validate <manifest> --json --quiet', 'help.cmd_schema_validate', {
831
+ requiresLogin: false,
832
+ output: 'json',
833
+ }),
834
+ command('schema.plan', ['schema', 'plan'], 'schema plan <manifest> --state <path> --json --quiet', 'help.cmd_schema_plan', {
835
+ output: 'json',
836
+ }),
837
+ command('schema.apply', ['schema', 'apply'], 'schema apply <manifest> --state <path> --plan-id <planId> --json --quiet', 'help.cmd_schema_apply', {
838
+ output: 'json',
839
+ }),
840
+ ],
841
+ },
802
842
  {
803
843
  id: 'data',
804
844
  titleKey: 'help.group_data',
@@ -202,7 +202,7 @@ class EnvironmentChecker {
202
202
  label: '可选浏览器能力(Playwright 已安装)',
203
203
  passed: true,
204
204
  severity: Severity.INFO,
205
- message: '当前 CLI 默认使用 OAuth token 登录;Playwright 仅用于少量浏览器预览或兼容场景',
205
+ message: '当前 CLI 默认使用 OAuth token 登录;Playwright 仅用于少量浏览器预览或截图评测',
206
206
  fixType: null,
207
207
  };
208
208
  } catch {
@@ -254,10 +254,21 @@ class EnvironmentChecker {
254
254
  }
255
255
 
256
256
  checkLoginStatus() {
257
- const { tokenStatus } = require('../auth/token-auth');
258
- const status = tokenStatus({ projectRoot: this.projectRoot });
257
+ const { getAuthStatus, isEnvAuthMode } = require('./utils');
258
+ const status = getAuthStatus({ projectRoot: this.projectRoot });
259
259
 
260
- if (status.status !== 'ok') {
260
+ if (!status.ok) {
261
+ if (isEnvAuthMode()) {
262
+ return {
263
+ id: 'env-login',
264
+ label: '宜搭宿主 token 注入登录态',
265
+ passed: false,
266
+ severity: Severity.WARNING,
267
+ message: `宿主 token 注入不可用(${status.failure_reason || status.status}),请回到宿主环境注入 OPENYIDA_ACCESS_TOKEN 或 OPENYIDA_REFRESH_TOKEN`,
268
+ fixType: null,
269
+ fixCommand: null,
270
+ };
271
+ }
261
272
  return {
262
273
  id: 'env-login',
263
274
  label: '宜搭 token 登录态',
@@ -145,7 +145,7 @@ function switchToEnv(envName) {
145
145
  console.log(` 地址:${config.environments[resolvedEnvName].baseUrl}`);
146
146
  console.log(` 登录:${getLoginHost(config.environments[resolvedEnvName].loginUrl)}`);
147
147
  console.log('');
148
- console.log(`${DIM}下一步:运行 openyida login;在悟空中可运行 openyida login --wukong${RESET}`);
148
+ console.log(`${DIM}下一步:运行 openyida login;在宿主注入 token 模式中请先确认宿主已注入 OPENYIDA_ACCESS_TOKEN 或 OPENYIDA_REFRESH_TOKEN${RESET}`);
149
149
  console.log('');
150
150
  }
151
151
 
package/lib/core/env.js CHANGED
@@ -12,6 +12,7 @@ const os = require('os');
12
12
  const {
13
13
  detectActiveTool,
14
14
  findProjectRoot,
15
+ getAuthStatus,
15
16
  resolveWukongWorkspaceRoot,
16
17
  } = require('./utils');
17
18
  const { t } = require('./i18n');
@@ -98,29 +99,29 @@ function getTokenDiagnostics(projectRoot) {
98
99
  * 检测登录态信息。
99
100
  */
100
101
  function detectLoginStatus(projectRoot) {
101
- const tokenDiagnostics = getTokenDiagnostics(projectRoot);
102
- const { tokenStatus } = require('../auth/token-auth');
103
- const status = tokenStatus({ projectRoot });
102
+ const status = getAuthStatus({ projectRoot });
104
103
  const loggedIn = status.status === 'ok';
105
104
 
105
+ const tokenDiagnostics = getTokenDiagnostics(projectRoot);
106
106
  return {
107
107
  loggedIn,
108
108
  canAutoUse: !!status.can_auto_use,
109
109
  corpId: status.corp_id || null,
110
110
  userId: status.user_id || null,
111
111
  baseUrl: status.base_url || null,
112
- authSource: 'token',
112
+ authSource: status.auth_source || 'token',
113
113
  authMode: 'token',
114
114
  tokenFile: status.token_file || tokenDiagnostics.tokenFile,
115
115
  diagnostics: {
116
116
  ...tokenDiagnostics,
117
- authSource: 'token',
117
+ authSource: status.auth_source || 'token',
118
+ authMode: 'token',
118
119
  cacheReadable: tokenDiagnostics.tokenFileFound,
119
120
  tokenFound: loggedIn,
120
121
  corpIdFound: !!status.corp_id,
121
122
  userIdFound: !!status.user_id,
122
123
  baseUrlFound: !!status.base_url,
123
- failureReason: loggedIn ? null : status.status,
124
+ failureReason: loggedIn ? null : (status.failure_reason || status.status),
124
125
  },
125
126
  };
126
127
  }