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.
- package/README.md +14 -0
- package/bin/yida.js +136 -20
- package/lib/app/canvas-compile.js +44 -12
- package/lib/app/create-app.js +12 -1
- package/lib/app/create-form/args.js +13 -0
- package/lib/app/create-form.js +154 -67
- package/lib/app/create-page.js +45 -9
- package/lib/app/get-schema.js +65 -14
- package/lib/app/import-app.js +92 -41
- package/lib/app/publish.js +307 -547
- package/lib/app/schema-field-resolution.js +370 -0
- package/lib/app/services/app-reader.js +85 -0
- package/lib/app/services/app-service.js +235 -0
- package/lib/app/services/canvas-page-compiler.js +91 -0
- package/lib/app/services/canvas-page-schema-builder.js +149 -0
- package/lib/app/services/field-bindings.js +68 -0
- package/lib/app/services/form-compiler.js +1922 -0
- package/lib/app/services/form-mode-service.js +182 -0
- package/lib/app/services/form-schema-patcher.js +333 -0
- package/lib/app/services/form-schema-reader.js +59 -0
- package/lib/app/services/form-service.js +379 -0
- package/lib/app/services/form-validation.js +562 -0
- package/lib/app/services/native-page-compiler.js +92 -0
- package/lib/app/services/native-page-schema-builder.js +428 -0
- package/lib/app/services/page-resource-service.js +185 -0
- package/lib/app/update-app.js +18 -6
- package/lib/auth/token-auth.js +34 -3
- package/lib/auth/token-store.js +22 -4
- package/lib/bridge/bridge.js +37 -5
- package/lib/core/agent-capabilities.js +263 -3
- package/lib/core/command-manifest.js +276 -0
- package/lib/core/doctor.js +15 -4
- package/lib/core/env-cmd.js +1 -1
- package/lib/core/env.js +7 -6
- package/lib/core/legacy-schema-guard.js +408 -0
- package/lib/core/locales/en.js +17 -46
- package/lib/core/locales/zh.js +17 -46
- package/lib/core/sample.js +1 -1
- package/lib/core/utils.js +334 -66
- package/lib/core/yida-client.js +104 -3
- package/lib/formula/evaluate.js +8 -66
- package/lib/formula/field-refs.js +83 -0
- package/lib/process/configure-process.js +44 -1992
- package/lib/process/create-process.js +54 -87
- package/lib/process/services/process-compiler.js +2056 -0
- package/lib/process/services/process-reader.js +232 -0
- package/lib/process/services/process-resource-service.js +571 -0
- package/lib/process/services/process-service.js +122 -0
- package/lib/process/services/process-stage-checkpoint.js +246 -0
- package/lib/report/append.js +7 -26
- package/lib/report/http.js +31 -5
- package/lib/report/index.js +10 -2
- package/lib/samples/yida-canvas-custom-page/business-list.canvas.jsx +63 -14
- package/lib/samples/yida-canvas-custom-page/dashboard-overview.canvas.jsx +176 -32
- package/lib/samples/yida-canvas-custom-page/data-management.canvas.jsx +228 -14
- package/lib/samples/yida-canvas-custom-page/split-pane-detail.canvas.jsx +204 -8
- package/lib/schema/adapters/app-adapter.js +210 -0
- package/lib/schema/adapters/form-adapter.js +1362 -0
- package/lib/schema/adapters/keys.js +19 -0
- package/lib/schema/adapters/page-adapter.js +566 -0
- package/lib/schema/adapters/process-adapter.js +519 -0
- package/lib/schema/applier.js +1878 -0
- package/lib/schema/apply-store.js +1083 -0
- package/lib/schema/command.js +645 -0
- package/lib/schema/dependency-graph.js +83 -0
- package/lib/schema/errors.js +481 -0
- package/lib/schema/hash.js +9 -0
- package/lib/schema/manifest-limits.js +177 -0
- package/lib/schema/manifest-loader.js +309 -0
- package/lib/schema/manifest-schema-v1.json +193 -0
- package/lib/schema/normalize-manifest.js +281 -0
- package/lib/schema/page-canvas-foundation.js +447 -0
- package/lib/schema/page-data-source-builder.js +561 -0
- package/lib/schema/page-foundation.js +556 -0
- package/lib/schema/page-source-loader.js +314 -0
- package/lib/schema/planner.js +691 -0
- package/lib/schema/remote-dispatch-boundary.js +39 -0
- package/lib/schema/remote-missing.js +21 -0
- package/lib/schema/remote-reader.js +189 -0
- package/lib/schema/resource-registry.js +157 -0
- package/lib/schema/server-revision.js +71 -0
- package/lib/schema/sort.js +28 -0
- package/lib/schema/state-store.js +589 -0
- package/package.json +2 -2
- package/scripts/postinstall.js +8 -12
- package/scripts/validate-command-manifest.js +72 -0
- package/scripts/validate-package-size.js +1 -1
- package/yida-skills/SKILL.md +116 -29
- package/yida-skills/references/schema-as-code-phase1.md +99 -0
- package/yida-skills/references/setup-and-env.md +61 -59
- package/yida-skills/references/task-retrospective.md +6 -6
- package/yida-skills/skills/yida-app/SKILL.md +73 -14
- package/yida-skills/skills/yida-canvas-custom-page/SKILL.md +21 -7
- package/yida-skills/skills/yida-canvas-custom-page/references/data-bridge-guide.md +3 -3
- package/yida-skills/skills/yida-canvas-custom-page/references/dependencies-and-cdn.md +5 -1
- package/yida-skills/skills/yida-canvas-custom-page/references/page-generation-guide.md +7 -1
- package/yida-skills/skills/yida-canvas-data-binding/SKILL.md +1 -0
- package/yida-skills/skills/yida-create-app/SKILL.md +21 -3
- package/yida-skills/skills/yida-create-form-page/SKILL.md +19 -1
- package/yida-skills/skills/yida-create-page/SKILL.md +16 -3
- package/yida-skills/skills/yida-create-process/SKILL.md +100 -4
- package/yida-skills/skills/yida-custom-page/SKILL.md +22 -4
- package/yida-skills/skills/yida-dashboard/SKILL.md +1 -1
- package/yida-skills/skills/yida-dashboard/references/pitfalls.md +1 -1
- package/yida-skills/skills/yida-get-schema/SKILL.md +49 -5
- package/yida-skills/skills/yida-i18n/SKILL.md +1 -1
- package/yida-skills/skills/yida-integration/SKILL.md +7 -1
- package/yida-skills/skills/yida-login/SKILL.md +52 -99
- package/yida-skills/skills/yida-page-config/SKILL.md +7 -1
- package/yida-skills/skills/yida-page-uiux/references/app/blueprint.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/app/navigation-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/app/role-journey.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/dashboard/app-blueprint.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/dashboard/chart-contracts.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/dashboard/component-contracts.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/dashboard/layout-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/dashboard/theme-recipes.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/detail/object-narrative.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/detail/section-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/detail/timeline-and-related.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/landing/assets-workflow.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/landing/industry-playbooks.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/landing/research-levels.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/landing/section-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/list/drawer-detail.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/list/empty-loading-error.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/list/filter-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/list/table-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/scenes/screen.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/workbench/entry-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/workbench/portal-layouts.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/workbench/task-feed.md +0 -1
- package/yida-skills/skills/yida-page-uiux/workflow/output-decision-block.md +1 -1
- package/yida-skills/skills/yida-process-rule/SKILL.md +35 -1
- package/yida-skills/skills/yida-publish-page/SKILL.md +48 -4
- package/yida-skills/skills/yida-report/SKILL.md +7 -1
- package/yida-skills/skills-index.json +14 -46
- package/yida-skills/skills/large-file-write/SKILL.md +0 -93
- package/yida-skills/skills/large-file-write/references/write-patterns.md +0 -147
- package/yida-skills/skills/large-file-write/scripts/write.js +0 -157
- package/yida-skills/skills/sls-log-workbench/SKILL.md +0 -134
- package/yida-skills/skills/sls-log-workbench/references/workbench-reference.md +0 -130
- 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.
|
|
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
|
-
|
|
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 {
|
|
520
|
-
if (loginArgs
|
|
521
|
-
|
|
606
|
+
const { getAuthStatus, isEnvAuthMode } = require('../lib/core/utils');
|
|
607
|
+
if (hasHelpFlag(loginArgs)) {
|
|
608
|
+
printLoginHelp();
|
|
522
609
|
} else {
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
})
|
|
527
|
-
|
|
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 {
|
|
542
|
-
|
|
543
|
-
|
|
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
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
118
|
-
|
|
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(
|
|
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 = {}) {
|
|
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
|
};
|
package/lib/app/create-app.js
CHANGED
|
@@ -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
|
-
|
|
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') {
|