openyida 2026.7.19 → 2026.7.22

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 (143) hide show
  1. package/README.md +14 -0
  2. package/bin/yida.js +136 -20
  3. package/lib/app/canvas-compile.js +44 -12
  4. package/lib/app/create-app.js +12 -1
  5. package/lib/app/create-form/args.js +13 -0
  6. package/lib/app/create-form.js +154 -67
  7. package/lib/app/create-page.js +45 -9
  8. package/lib/app/get-schema.js +65 -14
  9. package/lib/app/import-app.js +92 -41
  10. package/lib/app/publish.js +307 -547
  11. package/lib/app/schema-field-resolution.js +370 -0
  12. package/lib/app/services/app-reader.js +85 -0
  13. package/lib/app/services/app-service.js +235 -0
  14. package/lib/app/services/canvas-page-compiler.js +91 -0
  15. package/lib/app/services/canvas-page-schema-builder.js +149 -0
  16. package/lib/app/services/field-bindings.js +68 -0
  17. package/lib/app/services/form-compiler.js +1922 -0
  18. package/lib/app/services/form-mode-service.js +182 -0
  19. package/lib/app/services/form-schema-patcher.js +333 -0
  20. package/lib/app/services/form-schema-reader.js +59 -0
  21. package/lib/app/services/form-service.js +379 -0
  22. package/lib/app/services/form-validation.js +562 -0
  23. package/lib/app/services/native-page-compiler.js +92 -0
  24. package/lib/app/services/native-page-schema-builder.js +428 -0
  25. package/lib/app/services/page-resource-service.js +185 -0
  26. package/lib/app/update-app.js +18 -6
  27. package/lib/auth/token-auth.js +34 -3
  28. package/lib/auth/token-store.js +22 -4
  29. package/lib/bridge/bridge.js +37 -5
  30. package/lib/core/agent-capabilities.js +263 -3
  31. package/lib/core/command-manifest.js +276 -0
  32. package/lib/core/doctor.js +15 -4
  33. package/lib/core/env-cmd.js +1 -1
  34. package/lib/core/env.js +7 -6
  35. package/lib/core/legacy-schema-guard.js +408 -0
  36. package/lib/core/locales/en.js +17 -46
  37. package/lib/core/locales/zh.js +17 -46
  38. package/lib/core/sample.js +1 -1
  39. package/lib/core/utils.js +334 -66
  40. package/lib/core/yida-client.js +104 -3
  41. package/lib/formula/evaluate.js +8 -66
  42. package/lib/formula/field-refs.js +83 -0
  43. package/lib/process/configure-process.js +44 -1992
  44. package/lib/process/create-process.js +54 -87
  45. package/lib/process/services/process-compiler.js +2056 -0
  46. package/lib/process/services/process-reader.js +232 -0
  47. package/lib/process/services/process-resource-service.js +571 -0
  48. package/lib/process/services/process-service.js +122 -0
  49. package/lib/process/services/process-stage-checkpoint.js +246 -0
  50. package/lib/report/append.js +7 -26
  51. package/lib/report/http.js +31 -5
  52. package/lib/report/index.js +10 -2
  53. package/lib/samples/yida-canvas-custom-page/business-list.canvas.jsx +63 -14
  54. package/lib/samples/yida-canvas-custom-page/dashboard-overview.canvas.jsx +176 -32
  55. package/lib/samples/yida-canvas-custom-page/data-management.canvas.jsx +228 -14
  56. package/lib/samples/yida-canvas-custom-page/split-pane-detail.canvas.jsx +204 -8
  57. package/lib/schema/adapters/app-adapter.js +210 -0
  58. package/lib/schema/adapters/form-adapter.js +1362 -0
  59. package/lib/schema/adapters/keys.js +19 -0
  60. package/lib/schema/adapters/page-adapter.js +566 -0
  61. package/lib/schema/adapters/process-adapter.js +519 -0
  62. package/lib/schema/applier.js +1878 -0
  63. package/lib/schema/apply-store.js +1083 -0
  64. package/lib/schema/command.js +645 -0
  65. package/lib/schema/dependency-graph.js +83 -0
  66. package/lib/schema/errors.js +481 -0
  67. package/lib/schema/hash.js +9 -0
  68. package/lib/schema/manifest-limits.js +177 -0
  69. package/lib/schema/manifest-loader.js +309 -0
  70. package/lib/schema/manifest-schema-v1.json +193 -0
  71. package/lib/schema/normalize-manifest.js +281 -0
  72. package/lib/schema/page-canvas-foundation.js +447 -0
  73. package/lib/schema/page-data-source-builder.js +561 -0
  74. package/lib/schema/page-foundation.js +556 -0
  75. package/lib/schema/page-source-loader.js +314 -0
  76. package/lib/schema/planner.js +691 -0
  77. package/lib/schema/remote-dispatch-boundary.js +39 -0
  78. package/lib/schema/remote-missing.js +21 -0
  79. package/lib/schema/remote-reader.js +189 -0
  80. package/lib/schema/resource-registry.js +157 -0
  81. package/lib/schema/server-revision.js +71 -0
  82. package/lib/schema/sort.js +28 -0
  83. package/lib/schema/state-store.js +589 -0
  84. package/package.json +2 -2
  85. package/scripts/postinstall.js +8 -12
  86. package/scripts/validate-command-manifest.js +72 -0
  87. package/scripts/validate-package-size.js +1 -1
  88. package/yida-skills/SKILL.md +116 -29
  89. package/yida-skills/references/schema-as-code-phase1.md +99 -0
  90. package/yida-skills/references/setup-and-env.md +61 -59
  91. package/yida-skills/references/task-retrospective.md +6 -6
  92. package/yida-skills/skills/yida-app/SKILL.md +73 -14
  93. package/yida-skills/skills/yida-canvas-custom-page/SKILL.md +21 -7
  94. package/yida-skills/skills/yida-canvas-custom-page/references/data-bridge-guide.md +3 -3
  95. package/yida-skills/skills/yida-canvas-custom-page/references/dependencies-and-cdn.md +5 -1
  96. package/yida-skills/skills/yida-canvas-custom-page/references/page-generation-guide.md +7 -1
  97. package/yida-skills/skills/yida-canvas-data-binding/SKILL.md +1 -0
  98. package/yida-skills/skills/yida-create-app/SKILL.md +21 -3
  99. package/yida-skills/skills/yida-create-form-page/SKILL.md +19 -1
  100. package/yida-skills/skills/yida-create-page/SKILL.md +16 -3
  101. package/yida-skills/skills/yida-create-process/SKILL.md +100 -4
  102. package/yida-skills/skills/yida-custom-page/SKILL.md +22 -4
  103. package/yida-skills/skills/yida-dashboard/SKILL.md +1 -1
  104. package/yida-skills/skills/yida-dashboard/references/pitfalls.md +1 -1
  105. package/yida-skills/skills/yida-get-schema/SKILL.md +49 -5
  106. package/yida-skills/skills/yida-i18n/SKILL.md +1 -1
  107. package/yida-skills/skills/yida-integration/SKILL.md +7 -1
  108. package/yida-skills/skills/yida-login/SKILL.md +52 -99
  109. package/yida-skills/skills/yida-page-config/SKILL.md +7 -1
  110. package/yida-skills/skills/yida-page-uiux/references/app/blueprint.md +0 -1
  111. package/yida-skills/skills/yida-page-uiux/references/app/navigation-patterns.md +0 -1
  112. package/yida-skills/skills/yida-page-uiux/references/app/role-journey.md +0 -1
  113. package/yida-skills/skills/yida-page-uiux/references/dashboard/app-blueprint.md +0 -1
  114. package/yida-skills/skills/yida-page-uiux/references/dashboard/chart-contracts.md +0 -1
  115. package/yida-skills/skills/yida-page-uiux/references/dashboard/component-contracts.md +0 -1
  116. package/yida-skills/skills/yida-page-uiux/references/dashboard/layout-patterns.md +0 -1
  117. package/yida-skills/skills/yida-page-uiux/references/dashboard/theme-recipes.md +0 -1
  118. package/yida-skills/skills/yida-page-uiux/references/detail/object-narrative.md +0 -1
  119. package/yida-skills/skills/yida-page-uiux/references/detail/section-patterns.md +0 -1
  120. package/yida-skills/skills/yida-page-uiux/references/detail/timeline-and-related.md +0 -1
  121. package/yida-skills/skills/yida-page-uiux/references/landing/assets-workflow.md +0 -1
  122. package/yida-skills/skills/yida-page-uiux/references/landing/industry-playbooks.md +0 -1
  123. package/yida-skills/skills/yida-page-uiux/references/landing/research-levels.md +0 -1
  124. package/yida-skills/skills/yida-page-uiux/references/landing/section-patterns.md +0 -1
  125. package/yida-skills/skills/yida-page-uiux/references/list/drawer-detail.md +0 -1
  126. package/yida-skills/skills/yida-page-uiux/references/list/empty-loading-error.md +0 -1
  127. package/yida-skills/skills/yida-page-uiux/references/list/filter-patterns.md +0 -1
  128. package/yida-skills/skills/yida-page-uiux/references/list/table-patterns.md +0 -1
  129. package/yida-skills/skills/yida-page-uiux/references/scenes/screen.md +0 -1
  130. package/yida-skills/skills/yida-page-uiux/references/workbench/entry-patterns.md +0 -1
  131. package/yida-skills/skills/yida-page-uiux/references/workbench/portal-layouts.md +0 -1
  132. package/yida-skills/skills/yida-page-uiux/references/workbench/task-feed.md +0 -1
  133. package/yida-skills/skills/yida-page-uiux/workflow/output-decision-block.md +1 -1
  134. package/yida-skills/skills/yida-process-rule/SKILL.md +35 -1
  135. package/yida-skills/skills/yida-publish-page/SKILL.md +48 -4
  136. package/yida-skills/skills/yida-report/SKILL.md +7 -1
  137. package/yida-skills/skills-index.json +14 -46
  138. package/yida-skills/skills/large-file-write/SKILL.md +0 -93
  139. package/yida-skills/skills/large-file-write/references/write-patterns.md +0 -147
  140. package/yida-skills/skills/large-file-write/scripts/write.js +0 -157
  141. package/yida-skills/skills/sls-log-workbench/SKILL.md +0 -134
  142. package/yida-skills/skills/sls-log-workbench/references/workbench-reference.md +0 -130
  143. package/yida-skills/skills/sls-log-workbench/sls-query.js +0 -295
package/README.md CHANGED
@@ -174,6 +174,7 @@ openyida corp-efficiency
174
174
  openyida create-form create APP_XXX "Customer" .cache/openyida/forms/customer-fields.json
175
175
  openyida create-form update APP_XXX FORM_XXX .cache/openyida/forms/customer-changes.json
176
176
  openyida get-schema APP_XXX FORM_XXX
177
+ openyida get-schema APP_XXX FORM_XXX --compact --resolve-fields "Customer Name,Status"
177
178
  openyida get-schema APP_XXX --all --output-dir .cache/schemas
178
179
  ```
179
180
 
@@ -240,6 +241,7 @@ Most checks should stay offline, but OpenYida also includes an explicit real-env
240
241
  OPENYIDA_E2E=1 npm run test:e2e:real
241
242
  OPENYIDA_E2E=1 npm run test:e2e:real:full
242
243
  OPENYIDA_E2E=1 OPENYIDA_E2E_FULL_STAGES=auth,app,form,process npm run test:e2e:real:full
244
+ npm run test:e2e:real:schema-source
243
245
  npm run test:e2e:real:skills
244
246
  ```
245
247
 
@@ -249,6 +251,8 @@ The runner creates a disposable app, form, and custom page with an `OY_E2E_*` pr
249
251
 
250
252
  `test:e2e:real:skills` enforces coverage for every directory under `yida-skills/skills/`. Each skill must be classified as real E2E, offline/unit, opt-in, or deprecated with an explicit reason. This prevents new skills from quietly bypassing the real-environment test plan.
251
253
 
254
+ `test:e2e:real:schema-source` is a local process-level Schema-as-Code E2E for agent/source checkout validation. It reads `yida-skills/` in place, creates a temporary `openyida` launcher that executes the current checkout `bin/yida.js`, and runs CRM app/form/page/process create, managed-update, and noop scenarios through `schema validate -> plan -> apply -> noop` against a mock Yida service, including customer field updates and approval-flow/page changes. Report and integration automation manifests remain compatibility-boundary scenarios and must return unsupported.
255
+
252
256
  Each successful full run leaves a human-inspectable result app in the target organization. The final step publishes a dedicated `Full E2E Dashboard` custom page, renames the app to `OY_E2E_*_PASSED` by default, and prints direct links for the app, form, dashboard page, and report; the same links are saved under `resultApp` in the registry JSON.
253
257
 
254
258
  Useful options:
@@ -354,6 +358,8 @@ openyida append-chart APP_XXX REPORT_XXX .cache/openyida/reports/chart.json
354
358
 
355
359
  Run `openyida --help` or `openyida <command> --help` for detailed usage.
356
360
 
361
+ Schema-as-Code Phase 1 manages app, form, process, and native/default display page resources. Use the single [Phase 1 Manifest guide](yida-skills/references/schema-as-code-phase1.md): create any referenced page source first, run `validate`, run the read-only `plan`, review its current `planId`, then explicitly approve and run `apply`. Error `nextAction`/`ask_human` never grants the first write; `stale_replanned` only returns a replacement plan for another explicit review. State is the only persisted bindings authority; report, automation, and page config/delete/pull remain outside Phase 1.
362
+
357
363
  <!-- OPENYIDA_COMMANDS_START -->
358
364
  <!-- This section is generated by `npm run docs:commands`. Do not edit command rows by hand. -->
359
365
 
@@ -406,6 +412,14 @@ Run `openyida --help` or `openyida <command> --help` for detailed usage.
406
412
  | `openyida update-form-config <appType> ...` | Update form configuration |
407
413
  | `openyida get-form-config <appType> <formUuid> [--json]` | Query form configuration |
408
414
 
415
+ ### Schema-as-Code
416
+
417
+ | Command | Description |
418
+ |---------|-------------|
419
+ | `openyida schema validate <manifest> --json --quiet` | Validate Schema-as-Code manifest locally |
420
+ | `openyida schema plan <manifest> --state <path> --json --quiet` | Plan Schema-as-Code changes with read-only remote observation |
421
+ | `openyida schema apply <manifest> --state <path> --plan-id <planId> --json --quiet` | Apply a reviewed Schema-as-Code plan with checkpoints and recovery guards |
422
+
409
423
  ### Data & Permissions
410
424
 
411
425
  | Command | Description |
package/bin/yida.js CHANGED
@@ -14,10 +14,11 @@ const { version: currentVersion } = require('../package.json');
14
14
  const { t } = require('../lib/core/i18n');
15
15
  const { warn } = require('../lib/core/chalk');
16
16
  const { CliError, isCliError, toErrorPayload } = require('../lib/core/cli-error');
17
- const { COMMAND_GROUPS, buildCommandManifest } = require('../lib/core/command-manifest');
17
+ const { COMMAND_GROUPS, buildCommandManifest, findCommandSuggestion } = require('../lib/core/command-manifest');
18
18
 
19
19
  const command = process.argv[2];
20
20
  const args = process.argv.slice(3);
21
+ const rawArgs = process.argv.slice(3);
21
22
 
22
23
  function isAgentEnvironment(env) {
23
24
  return !!(
@@ -55,6 +56,9 @@ function shouldRunUpdateCheck() {
55
56
  if (!command || command === '--help' || command === '-h' || command === '--version' || command === '-v') {
56
57
  return false;
57
58
  }
59
+ if (args.includes('--help') || args.includes('-h')) {
60
+ return false;
61
+ }
58
62
  if (command === 'commands' || command === 'agent-capabilities' || command === 'mcp') {
59
63
  return false;
60
64
  }
@@ -250,12 +254,15 @@ function printLoginResult(result) {
250
254
  return;
251
255
  }
252
256
 
253
- const tokenUsable = result.can_auto_use !== false && !!result.access_token;
257
+ const tokenUsable = result.ok !== undefined
258
+ ? !!result.ok
259
+ : (result.can_auto_use !== false && !!result.access_token);
254
260
  const summary = {
255
261
  ok: tokenUsable,
256
262
  status: result.status || (tokenUsable ? 'ok' : 'token_not_issued'),
257
263
  auth_mode: 'token',
258
- can_auto_use: tokenUsable,
264
+ auth_source: result.auth_source || result.authSource,
265
+ can_auto_use: result.can_auto_use !== undefined ? !!result.can_auto_use : tokenUsable,
259
266
  token_type: result.token_type || 'Bearer',
260
267
  access_token: maskSensitiveAuthOutput({ access_token: result.access_token }).access_token,
261
268
  expires_at: result.expires_at ? new Date(result.expires_at).toISOString() : undefined,
@@ -263,6 +270,7 @@ function printLoginResult(result) {
263
270
  corp_id: result.corp_id,
264
271
  user_id: result.user_id,
265
272
  user_name: result.user_name,
273
+ failure_reason: result.failure_reason,
266
274
  message: result.message,
267
275
  raw: tokenUsable ? undefined : result.raw,
268
276
  };
@@ -308,6 +316,30 @@ function getArgValue(cliArgs, name) {
308
316
  return cliArgs[index + 1];
309
317
  }
310
318
 
319
+ const UNSUPPORTED_LEGACY_LOGIN_FLAGS = new Set([
320
+ '--qr',
321
+ '--qr-code',
322
+ '--agent-qr',
323
+ '--codex-qr',
324
+ '--agent-poll',
325
+ '--codex-poll',
326
+ '--browser',
327
+ '--codex',
328
+ '--qoder',
329
+ '--wukong',
330
+ ]);
331
+
332
+ function findUnsupportedLegacyLoginFlag(...argLists) {
333
+ for (const argList of argLists) {
334
+ for (const arg of argList || []) {
335
+ if (UNSUPPORTED_LEGACY_LOGIN_FLAGS.has(arg)) {
336
+ return arg;
337
+ }
338
+ }
339
+ }
340
+ return null;
341
+ }
342
+
311
343
  function parseLoginTargetArg(value) {
312
344
  const raw = String(value || '').trim();
313
345
  if (!raw) {return null;}
@@ -445,6 +477,61 @@ function throwCliUsage(...lines) {
445
477
  });
446
478
  }
447
479
 
480
+ function formatSuggestionMessage(suggestion) {
481
+ if (!suggestion) {
482
+ return '';
483
+ }
484
+ if (suggestion.message_key) {
485
+ return t(suggestion.message_key, ...(suggestion.message_args || []));
486
+ }
487
+ return '';
488
+ }
489
+
490
+ function throwUnknownCommand(commandName, commandArgs = []) {
491
+ const suggestion = findCommandSuggestion([commandName, ...commandArgs]);
492
+ const lines = [t('cli.unknown_command', commandName)];
493
+ if (suggestion) {
494
+ lines.push(t('cli.command_suggestion', suggestion.suggested_usage));
495
+ const suggestionMessage = formatSuggestionMessage(suggestion);
496
+ if (suggestionMessage) {
497
+ lines.push(suggestionMessage);
498
+ }
499
+ }
500
+ lines.push(t('cli.run_help'));
501
+ throw new CliError(lines.filter(Boolean).join('\n'), {
502
+ code: 'INVALID_ARGUMENTS',
503
+ details: suggestion ? { suggestion } : undefined,
504
+ });
505
+ }
506
+
507
+ function hasHelpFlag(cliArgs = []) {
508
+ return cliArgs.includes('--help') || cliArgs.includes('-h');
509
+ }
510
+
511
+ function printCommandUsage(...lines) {
512
+ console.log(lines.filter(Boolean).join('\n'));
513
+ }
514
+
515
+ function printLoginHelp() {
516
+ printCommandUsage(t('cli.login_usage'), t('cli.login_example'));
517
+ }
518
+
519
+ function printAuthHelp() {
520
+ printCommandUsage(t('cli.auth_usage'), t('cli.auth_example'));
521
+ }
522
+
523
+ function assertNoUnsupportedLegacyLoginFlags(...argLists) {
524
+ const flag = findUnsupportedLegacyLoginFlag(...argLists);
525
+ if (!flag) {
526
+ return;
527
+ }
528
+ throwCliUsage(
529
+ t('cli.login_unsupported_option', flag),
530
+ t('cli.login_usage'),
531
+ t('cli.login_example')
532
+ );
533
+ }
534
+
448
535
  async function main() {
449
536
  applyQuietFlag();
450
537
  applyGlobalEnvironmentFlags();
@@ -516,15 +603,23 @@ async function main() {
516
603
 
517
604
  case 'login': {
518
605
  const loginArgs = applyLoginEnvironmentFlags(args, { inferTargetUrl: true });
519
- const { tokenLogin, tokenStatus } = require('../lib/auth/token-auth');
520
- if (loginArgs.includes('--check-only')) {
521
- console.log(JSON.stringify(tokenStatus(), null, 2));
606
+ const { getAuthStatus, isEnvAuthMode } = require('../lib/core/utils');
607
+ if (hasHelpFlag(loginArgs)) {
608
+ printLoginHelp();
522
609
  } else {
523
- const result = await tokenLogin({
524
- clientId: getArgValue(loginArgs, '--client-id'),
525
- quiet: loginArgs.includes('--quiet'),
526
- });
527
- printLoginResult(result);
610
+ assertNoUnsupportedLegacyLoginFlags(rawArgs, loginArgs);
611
+ if (loginArgs.includes('--check-only')) {
612
+ console.log(JSON.stringify(getAuthStatus(), null, 2));
613
+ } else if (isEnvAuthMode()) {
614
+ printLoginResult(getAuthStatus());
615
+ } else {
616
+ const { tokenLogin } = require('../lib/auth/token-auth');
617
+ const result = await tokenLogin({
618
+ clientId: getArgValue(loginArgs, '--client-id'),
619
+ quiet: loginArgs.includes('--quiet'),
620
+ });
621
+ printLoginResult(result);
622
+ }
528
623
  }
529
624
  break;
530
625
  }
@@ -538,15 +633,25 @@ async function main() {
538
633
  case 'auth': {
539
634
  const subCommand = args[0];
540
635
  const authArgs = applyLoginEnvironmentFlags(args.slice(1), { inferTargetUrl: true });
541
- const { tokenLogin, tokenLogout, tokenRefresh, tokenStatus } = require('../lib/auth/token-auth');
542
- if (subCommand === 'status') {
543
- console.log(JSON.stringify(tokenStatus(), null, 2));
636
+ const { getAuthStatus, isEnvAuthMode } = require('../lib/core/utils');
637
+ const { tokenLogin, tokenLogout, tokenRefresh } = require('../lib/auth/token-auth');
638
+ if (!subCommand || subCommand === '--help' || subCommand === '-h') {
639
+ printAuthHelp();
640
+ } else if (subCommand === 'status') {
641
+ console.log(JSON.stringify(getAuthStatus(), null, 2));
544
642
  } else if (subCommand === 'login') {
545
- const result = await tokenLogin({
546
- clientId: getArgValue(authArgs, '--client-id'),
547
- quiet: authArgs.includes('--quiet'),
548
- });
549
- printLoginResult(result);
643
+ if (hasHelpFlag(authArgs)) {
644
+ printLoginHelp();
645
+ } else {
646
+ assertNoUnsupportedLegacyLoginFlags(rawArgs.slice(1), authArgs);
647
+ const result = isEnvAuthMode()
648
+ ? getAuthStatus()
649
+ : await tokenLogin({
650
+ clientId: getArgValue(authArgs, '--client-id'),
651
+ quiet: authArgs.includes('--quiet'),
652
+ });
653
+ printLoginResult(result);
654
+ }
550
655
  } else if (subCommand === 'refresh') {
551
656
  console.log(JSON.stringify(maskSensitiveAuthOutput(await tokenRefresh()), null, 2));
552
657
  } else if (subCommand === 'logout') {
@@ -624,6 +729,12 @@ async function main() {
624
729
  break;
625
730
  }
626
731
 
732
+ case 'schema': {
733
+ const { run } = require('../lib/schema/command');
734
+ await run(args);
735
+ break;
736
+ }
737
+
627
738
  case 'formula': {
628
739
  const subCommand = args[0];
629
740
  const subArgs = args.slice(1);
@@ -664,6 +775,11 @@ async function main() {
664
775
  }
665
776
 
666
777
  case 'publish': {
778
+ if (args.includes('--help') || args.includes('-h')) {
779
+ const publishMain = require('../lib/app/publish');
780
+ await publishMain(args);
781
+ break;
782
+ }
667
783
  const passThroughFlags = new Set(['--skip-lint', '--health-check', '--check', '--open', '--no-open', '--compat', '--modern', '--force', '--canvas']);
668
784
  const filteredArgs = args.filter(arg => !passThroughFlags.has(arg));
669
785
  if (filteredArgs.length < 3) {
@@ -1058,7 +1174,7 @@ async function main() {
1058
1174
  }
1059
1175
 
1060
1176
  default: {
1061
- throwCliUsage(t('cli.unknown_command', command), t('cli.run_help'));
1177
+ throwUnknownCommand(command, args);
1062
1178
  }
1063
1179
  }
1064
1180
  }
@@ -35,8 +35,9 @@ const Babel = require('@babel/standalone');
35
35
  * 逐条镜像自 @ali/vc-deep-yida 的
36
36
  * src/components/yida-code-canvas/dependencies.ts → getModuleAliasMap()
37
37
  * 只保留运行时真正用到的 windowAlias(资源 URL 由画布运行时按别名注入,
38
- * 本地编译不关心 CDN 地址)。若此处与物料白名单漂移,编译产物仍可运行,
39
- * 只是未收录的包会在浏览器端 `${name} is not found in dependencies map` 告警。
38
+ * 本地编译不关心 CDN 地址)。默认拒绝未收录依赖;如果宜搭物料依赖表已经
39
+ * 先于 CLI 升级,可临时设置 OPENYIDA_CANVAS_ALLOW_UNSUPPORTED_IMPORTS=1
40
+ * 退回旧的 window["pkg"] 映射,避免白名单漂移阻断发布。
40
41
  * @type {Record<string, string>}
41
42
  */
42
43
  const MODULE_ALIAS_MAP = {
@@ -59,6 +60,19 @@ const IMPORT_SIDE_EFFECT_PATTERN = /import\s+['"]([^'"]+)['"]/g;
59
60
  const REQUIRE_PATTERN = /require\(\s*['"]([^'"]+)['"]\s*\)/g;
60
61
  const DYNAMIC_IMPORT_PATTERN = /import\(\s*['"]([^'"]+)['"]\s*\)/g;
61
62
 
63
+ function isTruthy(value) {
64
+ return ['1', 'true', 'yes', 'on'].includes(String(value || '').trim().toLowerCase());
65
+ }
66
+
67
+ function shouldAllowUnsupportedBareImports(options = {}, env = process.env) {
68
+ return options.allowUnsupportedBareImports === true ||
69
+ isTruthy(env.OPENYIDA_CANVAS_ALLOW_UNSUPPORTED_IMPORTS);
70
+ }
71
+
72
+ function packageTempName(pkg) {
73
+ return String(pkg || 'module').replace(/[^A-Za-z0-9_$]+/g, '_') || 'module';
74
+ }
75
+
62
76
  function stripJsComments(code) {
63
77
  return String(code || '')
64
78
  .replace(/\/\*[\s\S]*?\*\//g, '')
@@ -113,16 +127,27 @@ function resolveWindowAlias(pkg) {
113
127
  * export const x = ... → const x = ...(去掉 export 关键字)
114
128
  * @param {{ types: import('@babel/types') }} babel
115
129
  */
116
- function esmToWindowPlugin({ types: t }) {
117
- function moduleExpr(pkg) {
118
- const alias = resolveWindowAlias(pkg);
130
+ function esmToWindowPlugin({ types: t }, options = {}) {
131
+ const allowUnsupportedBareImports = options.allowUnsupportedBareImports === true;
132
+
133
+ function moduleExpr(pkg, alias) {
119
134
  if (alias) {
120
135
  return t.memberExpression(t.identifier('window'), t.identifier(alias));
121
136
  }
122
- // 未收录包:退化为 window["pkg"],运行时若未注入会自然报错(与线上一致)。
123
137
  return t.memberExpression(t.identifier('window'), t.stringLiteral(pkg), true);
124
138
  }
125
139
 
140
+ function buildUnsupportedBareImportError(path, pkg) {
141
+ return path.buildCodeFrameError(
142
+ `Code Canvas 不支持从裸包 "${pkg}" 导入绑定。`
143
+ + '只允许 MODULE_ALIAS_MAP 白名单依赖;'
144
+ + '宜搭平台运行态全局对象请显式使用 window.* 访问'
145
+ + '(例如 window.Deep、window.DeepYida、window.YidaNativeComponents),不要从包中 import。'
146
+ + '若已确认宜搭物料运行态已注入该包且 CLI 白名单滞后,可临时设置 '
147
+ + 'OPENYIDA_CANVAS_ALLOW_UNSUPPORTED_IMPORTS=1 退回 legacy window["pkg"] 映射。'
148
+ );
149
+ }
150
+
126
151
  return {
127
152
  name: 'yida-esm-to-window',
128
153
  visitor: {
@@ -140,10 +165,14 @@ function esmToWindowPlugin({ types: t }) {
140
165
  path.remove();
141
166
  return;
142
167
  }
168
+ const alias = resolveWindowAlias(pkg);
169
+ if (!alias && !allowUnsupportedBareImports) {
170
+ throw buildUnsupportedBareImportError(path, pkg);
171
+ }
143
172
 
144
173
  const decls = [];
145
- const tmp = path.scope.generateUidIdentifier(resolveWindowAlias(pkg) || 'mod');
146
- decls.push(t.variableDeclarator(t.cloneNode(tmp), moduleExpr(pkg)));
174
+ const tmp = path.scope.generateUidIdentifier(alias || packageTempName(pkg));
175
+ decls.push(t.variableDeclarator(t.cloneNode(tmp), moduleExpr(pkg, alias)));
147
176
 
148
177
  const namedProps = [];
149
178
  for (const spec of specifiers) {
@@ -230,7 +259,7 @@ function esmToWindowPlugin({ types: t }) {
230
259
  * @param {string} source 原始 React/JSX/TSX 源码
231
260
  * @returns {{ runtimeCode: string, importedModules: string }}
232
261
  */
233
- function compileCanvasLocal(source) {
262
+ function compileCanvasLocal(source, options = {}) {
234
263
  const importedModules = extractImportedModules(source);
235
264
 
236
265
  // 第一步:剥类型 + 转 JSX(classic runtime,产出 React.createElement,
@@ -265,7 +294,9 @@ function compileCanvasLocal(source) {
265
294
  // 第二步:把 import/export 改写成 window 别名 + YidaComp。
266
295
  const stage2 = Babel.transform(intermediate, {
267
296
  filename: 'canvas.js',
268
- plugins: [esmToWindowPlugin],
297
+ plugins: [[esmToWindowPlugin, {
298
+ allowUnsupportedBareImports: shouldAllowUnsupportedBareImports(options),
299
+ }]],
269
300
  sourceType: 'module',
270
301
  compact: false,
271
302
  babelrc: false,
@@ -286,14 +317,14 @@ function compileCanvasLocal(source) {
286
317
  * @param {object} [options] 兼容占位,未使用
287
318
  * @returns {Promise<{ runtimeCode: string, importedModules: string }>}
288
319
  */
289
- function compileCanvas(source, options = {}) { // eslint-disable-line no-unused-vars
320
+ function compileCanvas(source, options = {}) {
290
321
  return new Promise((resolve, reject) => {
291
322
  if (typeof source !== 'string' || source.trim() === '') {
292
323
  reject(new Error('canvas 编译源码为空'));
293
324
  return;
294
325
  }
295
326
  try {
296
- resolve(compileCanvasLocal(source));
327
+ resolve(compileCanvasLocal(source, options));
297
328
  } catch (compileError) {
298
329
  const detail = compileError && compileError.message ? compileError.message : String(compileError);
299
330
  reject(new Error(`Code Canvas 本地编译失败: ${detail}`));
@@ -306,5 +337,6 @@ module.exports = {
306
337
  compileCanvasLocal,
307
338
  extractImportedModules,
308
339
  resolveWindowAlias,
340
+ shouldAllowUnsupportedBareImports,
309
341
  MODULE_ALIAS_MAP,
310
342
  };
@@ -18,6 +18,10 @@ const { t } = require('../core/i18n');
18
18
  const { buildYidaI18n, normalizeYidaLocale, resolveContentLocale } = require('../core/yida-i18n');
19
19
  const { parseOpenOption, withBrowserHandoff } = require('../core/browser-handoff');
20
20
  const { throwCommandError } = require('../core/command-errors');
21
+ const {
22
+ assertLegacyDirectWriteAllowed,
23
+ extractLegacyGuardArgs,
24
+ } = require('../core/legacy-schema-guard');
21
25
  const { assertPresetThemeKey } = require('./theme-presets');
22
26
 
23
27
  const DEFAULT_APP_OPTIONS = {
@@ -281,7 +285,8 @@ function buildCreateAppPayload(params, auth, contentLocale, openExclusive, openP
281
285
 
282
286
  async function run(args) {
283
287
  const openOption = parseOpenOption(args);
284
- args = openOption.args;
288
+ const guardSplit = extractLegacyGuardArgs(openOption.args);
289
+ args = guardSplit.args;
285
290
 
286
291
  if (hasHelpFlag(args)) {
287
292
  printUsage();
@@ -301,6 +306,12 @@ async function run(args) {
301
306
  chalkError(t('create_app.usage'), { hint: t('create_app.example') });
302
307
  }
303
308
 
309
+ assertLegacyDirectWriteAllowed({
310
+ command: 'create-app',
311
+ resourceType: 'app',
312
+ action: 'create',
313
+ }, { guardOptions: guardSplit.guardOptions });
314
+
304
315
  const { appName, description, icon, iconColor, colour, navTheme, layoutDirection } = params;
305
316
 
306
317
  const { c, banner, step, label, success: chalkSuccess, result: chalkResult } = require('../core/chalk');
@@ -85,6 +85,7 @@ function createParseArgs(dependencies) {
85
85
  labelAlign: 'top',
86
86
  contentLocale: null,
87
87
  browserOpenMode: openOption.mode,
88
+ legacyGuardOptions: openOption.legacyGuardOptions || null,
88
89
  };
89
90
 
90
91
  const args = [...rawArgs];
@@ -118,6 +119,18 @@ function createParseArgs(dependencies) {
118
119
  }
119
120
  }
120
121
 
122
+ if (args.includes('--help') || args.includes('-h')) {
123
+ usage(t('create_form.usage_create_short'));
124
+ hint(t('create_form.usage_update_short'));
125
+ hint(t('create_form.example_create'));
126
+ hint(t('create_form.example_update'));
127
+ return {
128
+ mode: 'help',
129
+ help: true,
130
+ ...options
131
+ };
132
+ }
133
+
121
134
  const mode = args[0];
122
135
 
123
136
  if (mode === 'create') {