openyida 2026.6.22-beta.1 → 2026.7.6

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 (100) hide show
  1. package/README.md +56 -2
  2. package/bin/yida.js +39 -21
  3. package/lib/app/create-form.js +34 -4
  4. package/lib/app/er.js +679 -0
  5. package/lib/app/nav-group.js +85 -0
  6. package/lib/app/page-compat.js +241 -2
  7. package/lib/app/page-linter.js +101 -6
  8. package/lib/app/publish.js +11 -0
  9. package/lib/auth/auth.js +25 -14
  10. package/lib/auth/login.js +63 -7
  11. package/lib/auth/qr-login.js +12 -0
  12. package/lib/core/command-manifest.js +5 -2
  13. package/lib/core/env.js +4 -1
  14. package/lib/core/locales/ar.js +29 -22
  15. package/lib/core/locales/de.js +29 -22
  16. package/lib/core/locales/en.js +28 -1
  17. package/lib/core/locales/es.js +29 -22
  18. package/lib/core/locales/fr.js +29 -22
  19. package/lib/core/locales/hi.js +29 -22
  20. package/lib/core/locales/ja.js +30 -22
  21. package/lib/core/locales/ko.js +29 -22
  22. package/lib/core/locales/pt.js +29 -22
  23. package/lib/core/locales/vi.js +29 -22
  24. package/lib/core/locales/zh-HK.js +9 -1
  25. package/lib/core/locales/zh.js +28 -1
  26. package/lib/core/utils.js +83 -15
  27. package/lib/formula/evaluate.js +75 -0
  28. package/lib/integration/integration-api.js +11 -7
  29. package/lib/integration/integration-create.js +303 -67
  30. package/lib/integration/integration-process-builder.js +106 -24
  31. package/lib/integration/integration-spec-builder.js +977 -0
  32. package/lib/integration/integration-view-builder.js +53 -11
  33. package/package.json +6 -1
  34. package/scripts/build-skills-package.js +47 -3
  35. package/scripts/e2e-real/skill-coverage.js +1 -0
  36. package/scripts/eval/VERIFY.md +169 -0
  37. package/scripts/eval/agent.js +148 -0
  38. package/scripts/eval/config.js +276 -0
  39. package/scripts/eval/dashboard/index.html +389 -0
  40. package/scripts/eval/dashboard/server.js +344 -0
  41. package/scripts/eval/eval.config.json +8 -0
  42. package/scripts/eval/generate.js +362 -0
  43. package/scripts/eval/guardrail.js +130 -0
  44. package/scripts/eval/manifest.js +117 -0
  45. package/scripts/eval/report.js +262 -0
  46. package/scripts/eval/routing.js +190 -0
  47. package/scripts/eval/runner.js +318 -0
  48. package/scripts/eval/scenarios/generation/generation-core.json +32 -0
  49. package/scripts/eval/scenarios/routing-core.json +86 -0
  50. package/scripts/eval/score.js +197 -0
  51. package/scripts/eval/screenshot.js +193 -0
  52. package/scripts/validate-package-size.js +1 -1
  53. package/scripts/validate-skills.js +14 -2
  54. package/yida-skills/SKILL.md +128 -308
  55. package/yida-skills/references/development-rules.md +80 -0
  56. package/yida-skills/references/field-and-url-reference.md +42 -0
  57. package/yida-skills/references/setup-and-env.md +90 -0
  58. package/yida-skills/skills/large-file-write/SKILL.md +1 -1
  59. package/yida-skills/skills/yida-agent-center/SKILL.md +1 -7
  60. package/yida-skills/skills/yida-app/SKILL.md +47 -10
  61. package/yida-skills/skills/yida-app-permission/SKILL.md +1 -8
  62. package/yida-skills/skills/yida-basic-info/SKILL.md +1 -1
  63. package/yida-skills/skills/yida-business-rule/SKILL.md +1 -1
  64. package/yida-skills/skills/yida-chart/SKILL.md +114 -1509
  65. package/yida-skills/skills/yida-connector/SKILL.md +1 -6
  66. package/yida-skills/skills/yida-connector-safe-actions/SKILL.md +1 -1
  67. package/yida-skills/skills/yida-corp-efficiency/SKILL.md +2 -3
  68. package/yida-skills/skills/yida-corp-manager/SKILL.md +1 -7
  69. package/yida-skills/skills/yida-create-app/SKILL.md +1 -1
  70. package/yida-skills/skills/yida-create-form-page/SKILL.md +69 -7
  71. package/yida-skills/skills/yida-create-page/SKILL.md +1 -6
  72. package/yida-skills/skills/yida-create-process/SKILL.md +1 -5
  73. package/yida-skills/skills/yida-custom-page/SKILL.md +21 -321
  74. package/yida-skills/skills/yida-custom-page/references/coding-guide.md +38 -0
  75. package/yida-skills/skills/yida-custom-page/references/runtime-guardrails.md +55 -0
  76. package/yida-skills/skills/yida-dashboard/SKILL.md +5 -1
  77. package/yida-skills/skills/yida-data-management/SKILL.md +1 -6
  78. package/yida-skills/skills/yida-data-source-connectors/SKILL.md +2 -6
  79. package/yida-skills/skills/yida-density/SKILL.md +1 -1
  80. package/yida-skills/skills/yida-export-conversation/SKILL.md +2 -5
  81. package/yida-skills/skills/yida-flash-note-to-prd/SKILL.md +2 -5
  82. package/yida-skills/skills/yida-form-detail/SKILL.md +1 -3
  83. package/yida-skills/skills/yida-form-permission/SKILL.md +1 -6
  84. package/yida-skills/skills/yida-formula/SKILL.md +1 -19
  85. package/yida-skills/skills/yida-formula-evaluate/SKILL.md +1 -9
  86. package/yida-skills/skills/yida-get-schema/SKILL.md +1 -5
  87. package/yida-skills/skills/yida-integration/SKILL.md +93 -7
  88. package/yida-skills/skills/yida-login/SKILL.md +6 -5
  89. package/yida-skills/skills/yida-logout/SKILL.md +1 -1
  90. package/yida-skills/skills/yida-nav-group/SKILL.md +26 -1
  91. package/yida-skills/skills/yida-openyida-publish-guard/SKILL.md +88 -0
  92. package/yida-skills/skills/yida-page-config/SKILL.md +1 -5
  93. package/yida-skills/skills/yida-ppt-slider/SKILL.md +98 -1400
  94. package/yida-skills/skills/yida-ppt-slider/references/dark-tech-theme.md +204 -0
  95. package/yida-skills/skills/yida-ppt-slider/references/echarts-race-example.md +330 -0
  96. package/yida-skills/skills/yida-process-rule/SKILL.md +1 -5
  97. package/yida-skills/skills/yida-publish-page/SKILL.md +2 -4
  98. package/yida-skills/skills/yida-report/SKILL.md +3 -6
  99. package/yida-skills/skills/yida-table-form/SKILL.md +2 -6
  100. package/yida-skills/skills/yida-voc/SKILL.md +1 -9
package/README.md CHANGED
@@ -264,6 +264,59 @@ Useful options:
264
264
 
265
265
  Use `npm run test:e2e:real:cleanup` to list recorded disposable resources. OpenYida does not yet expose a safe app/form deletion command, so cleanup is intentionally a registry-backed audit step rather than an automatic destructive action.
266
266
 
267
+ ### Skill Evaluation Harness
268
+
269
+ The E2E paths above prove the *CLI* works. The eval harness under `scripts/eval/` measures whether the *agent* still routes natural-language requests to the right sub-skill and produces good output after you edit `yida-skills/SKILL.md`. It is the feedback loop for harness engineering.
270
+
271
+ ```bash
272
+ # Routing eval — "did it pick the right sub-skill?" No real resources, no login.
273
+ # Drives a headless `claude -p` agent with each scenario prompt and checks
274
+ # the selected sub-skill against the golden set.
275
+ npm run eval:routing
276
+
277
+ # Tool-pipeline baseline (end-to-end) — wraps the real-environment runner for one
278
+ # sub-skill, adds guardrail assertions, screenshots the published page, and writes a
279
+ # human scoring template. Runs deterministic CLI commands (no agent) so it serves as
280
+ # a control that proves the build→publish→screenshot→score plumbing itself works.
281
+ # Requires OPENYIDA_E2E=1 and a valid cookie cache.
282
+ OPENYIDA_E2E=1 npm run eval:e2e -- --skill yida-dashboard --screenshot
283
+
284
+ # Same, plus automatic screenshot scoring via the local multimodal `claude -p`.
285
+ OPENYIDA_E2E=1 npm run eval:e2e -- --skill yida-dashboard --screenshot --auto-score
286
+
287
+ # Real-generation eval — "can one sentence really build a usable app?" Feeds a
288
+ # natural-language request ("帮我创建一个订单管理系统") to a headless `claude -p`
289
+ # that actually reads the openyida skill and runs the CLI to build a real app, then
290
+ # reuses the screenshot + scoring + report pipeline. Creates real 宜搭 resources, so
291
+ # it needs OPENYIDA_E2E=1 + an authenticated agent. Unlike the deterministic baseline
292
+ # above, here the agent self-orchestrates.
293
+ OPENYIDA_E2E=1 npm run eval:generate -- --screenshot
294
+
295
+ # Run all three in one pass (routing + tool-pipeline baseline + real generation).
296
+ OPENYIDA_E2E=1 npm run eval:all -- --skill yida-dashboard --screenshot
297
+
298
+ # Optional: a zero-dependency local web console (buttons + live streamed output)
299
+ # that runs the tasks above on click. Binds to 127.0.0.1 only; tasks are a fixed
300
+ # whitelist. Use the Node version you start it with, so run `nvm use 20` first.
301
+ npm run eval:dashboard # http://127.0.0.1:4500
302
+ ```
303
+
304
+ Configuration precedence is `CLI flag > env (OPENYIDA_EVAL_*) > scripts/eval/eval.config.json > defaults`.
305
+
306
+ | Flag | Purpose |
307
+ |------|---------|
308
+ | `--mode e2e\|routing\|generate\|all` | Which evals to run (default `e2e`; `all` = routing + tool-pipeline baseline + real generation) |
309
+ | `--skill <name>` | Restrict the e2e run to one sub-skill; stages are reverse-looked-up from the `SKILL_COVERAGE` matrix |
310
+ | `--stages a,b` | Explicit stage list, overriding the skill reverse-lookup |
311
+ | `--screenshot` / `--no-screenshot` | Capture the published page (default on; skipped gracefully if Playwright is absent) |
312
+ | `--auto-score` / `--no-auto-score` | Score screenshots with the local `claude -p` agent (default off → human template only) |
313
+ | `--scenarios <dir>` | Routing golden-set directory (default `scripts/eval/scenarios`) |
314
+ | `--gen-scenarios <dir>` | Real-generation golden-set directory (default `scripts/eval/scenarios/generation`) |
315
+
316
+ Results are written back into the existing `acceptance-manifest.json` under a new `eval` section (guardrails, screenshots, scores) plus two sibling artifacts: a `scoring.md` human-scoring template and a self-contained `eval-report.html` visual report (screenshots inlined as base64, so the single file opens anywhere). Routing results land in `project/.cache/eval/routing-report.json`; generation results (with their own `scoring.md` + `eval-report.html`) land in `project/.cache/eval/generate/gen-<timestamp>/`. The harness degrades gracefully: a missing Playwright skips screenshots (enable with `npm install --no-save playwright && npx playwright install chromium`), and a missing `claude` CLI skips auto-scoring while keeping the human template. A guardrail failure (for example a resource-creating command issued before a successful `login --check-only`) fails the run.
317
+
318
+ A zero-dependency local dashboard (`npm run eval:dashboard`, then open `http://127.0.0.1:4500`) drives these runs from buttons and streams output live; its "📊 查看最新报告" button opens the most recent `eval-report.html`.
319
+
267
320
  ### Connectors, Integrations, and Reports
268
321
 
269
322
  ```bash
@@ -302,7 +355,7 @@ Run `openyida --help` or `openyida <command> --help` for detailed usage.
302
355
  | `openyida corp-efficiency [overview\|details\|detail\|groups\|notify] [options] [--open\|--no-open]` | Query enterprise efficiency overview and detail reports |
303
356
  | `openyida create-app "<name>"\|--name <name> [options] [--locale zh_CN\|en_US\|ja_JP] [--open\|--no-open]` | Create a Yida app |
304
357
  | `openyida update-app <appType> [--name "..."] [--layout slide\|ver] [--theme deepBlue]` | Update app info |
305
- | `openyida nav-group <list\|create\|rename\|delete\|move\|hide\|show> <appType> ...` | Manage app sidebar navigation groups |
358
+ | `openyida nav-group <list\|create\|rename\|delete\|move\|order\|hide\|show> <appType> ...` | Manage app sidebar navigation groups |
306
359
  | `openyida app-permission <get\|set\|add\|remove\|search-user> ...` | Manage app primary, data, and developer admins |
307
360
  | `openyida i18n <overview\|config\|languages\|list\|upsert\|delete\|translate\|translate-all\|upgrade> <appType> ...` | Manage app multilingual copy and language config |
308
361
  | `openyida export <appType> [output]` | Export app (generate migration package) |
@@ -323,6 +376,7 @@ Run `openyida --help` or `openyida <command> --help` for detailed usage.
323
376
  | `openyida list-forms <appType> [--keyword <text>]` | List forms/pages in an app |
324
377
  | `openyida aggregate-table <list\|create-empty\|inspect\|preview\|save\|publish\|status> <appType> ...` | Manage aggregate tables (virtualView) |
325
378
  | `openyida get-schema <appType> <formUuid\|--all>` | Get one form Schema or all form Schemas |
379
+ | `openyida er <appType> [--format mermaid\|json] [--output file] [--include-system] [--include-pages]` | Export app entity relationship diagram |
326
380
  | `openyida create-page <appType> "<name>" [--mode dashboard] [--locale zh_CN\|en_US\|ja_JP] [--open\|--no-open]` | Create a custom display page |
327
381
  | `openyida generate-page <template>` | Generate page from curated template |
328
382
  | `openyida build-page <sourceFile> [--output file\|--write]` | Build Yida-compatible page source |
@@ -390,7 +444,7 @@ Run `openyida --help` or `openyida <command> --help` for detailed usage.
390
444
 
391
445
  | Command | Description |
392
446
  |---------|-------------|
393
- | `openyida integration create <appType> ...` | Create integration automation flow |
447
+ | `openyida integration create <appType> ... [--spec file.json]` | Create integration automation flow |
394
448
  | `openyida integration list <appType> [--form-uuid <uuid>] [--status y\|n] [--json]` | List integration automation flows |
395
449
  | `openyida integration enable <appType> <formUuid> <processCode>` | Enable integration automation flow |
396
450
  | `openyida integration disable <appType> <formUuid> <processCode>` | Disable integration automation flow |
package/bin/yida.js CHANGED
@@ -214,6 +214,16 @@ function handleFirstRunGuide() {
214
214
  function printLoginResult(result) {
215
215
  noteLoginCommandResult(result);
216
216
 
217
+ if (!result) {
218
+ console.log(JSON.stringify({
219
+ ok: false,
220
+ status: 'login_failed',
221
+ can_auto_use: false,
222
+ error: 'login_failed',
223
+ }));
224
+ return;
225
+ }
226
+
217
227
  if (result && (result.status === 'need_qr_scan' || result.status === 'need_corp_selection')) {
218
228
  console.log(JSON.stringify(result));
219
229
  return;
@@ -245,6 +255,11 @@ function printLoginResult(result) {
245
255
  return;
246
256
  }
247
257
 
258
+ if (result.status && result.status !== 'ok' && !result.csrf_token) {
259
+ console.log(JSON.stringify(result));
260
+ return;
261
+ }
262
+
248
263
  const summary = {
249
264
  ok: true,
250
265
  base_url: result && result.base_url,
@@ -313,9 +328,11 @@ function shouldUsePlaywrightFallbackInAgentLogin() {
313
328
  return hasDesktopEnvironment() || process.env.OPENYIDA_AGENT_PLAYWRIGHT_FALLBACK === '1';
314
329
  }
315
330
 
316
- function shouldUseDesktopBrowserLogin() {
317
- const { hasDesktopEnvironment } = require('../lib/core/utils');
318
- return hasDesktopEnvironment();
331
+ function shouldUseLocalBrowserLogin(options = {}) {
332
+ const { hasLocalBrowserLoginCapability } = require('../lib/auth/login');
333
+ return hasLocalBrowserLoginCapability({
334
+ playwrightFallback: options.playwrightFallback,
335
+ });
319
336
  }
320
337
 
321
338
  function shouldUseCodexQrLogin(cliArgs) {
@@ -542,6 +559,7 @@ async function main() {
542
559
  case 'login': {
543
560
  const { checkLoginOnly } = require('../lib/auth/login');
544
561
  const loginArgs = applyLoginEnvironmentFlags(args, { inferTargetUrl: true });
562
+ const { isInjectedAuthMode } = require('../lib/core/utils');
545
563
  if (loginArgs.includes('--agent-poll') || loginArgs.includes('--codex-poll')) {
546
564
  const sessionFile = getArgValue(loginArgs, '--agent-poll') || getArgValue(loginArgs, '--codex-poll');
547
565
  const { pollCodexQrLogin } = require('../lib/auth/qr-login');
@@ -556,9 +574,12 @@ async function main() {
556
574
  corpId: getArgValue(loginArgs, '--corp-id'),
557
575
  });
558
576
  printLoginResult(result);
559
- } else if (loginArgs[0] === '--check-only') {
577
+ } else if (loginArgs.includes('--check-only')) {
560
578
  const result = checkLoginOnly({ includeSecrets: loginArgs.includes('--with-cookies') });
561
579
  console.log(JSON.stringify(result, null, 2));
580
+ } else if (isInjectedAuthMode()) {
581
+ const result = checkLoginOnly({ includeSecrets: true });
582
+ printLoginResult(result);
562
583
  } else if (shouldUseCodexQrLogin(loginArgs)) {
563
584
  const { startCodexQrLogin } = require('../lib/auth/qr-login');
564
585
  const result = await startCodexQrLogin({ corpId: getArgValue(loginArgs, '--corp-id') });
@@ -580,26 +601,17 @@ async function main() {
580
601
  if (cachedResult.status === 'ok') {
581
602
  printLoginResult(cachedResult);
582
603
  } else {
583
- const { detectActiveTool } = require('../lib/core/utils');
584
- const activeTool = detectActiveTool();
585
604
  const { interactiveLogin } = require('../lib/auth/login');
586
- const browserResult = interactiveLogin({
587
- playwrightFallback: shouldUsePlaywrightFallbackInAgentLogin(),
588
- });
605
+ const playwrightFallback = shouldUsePlaywrightFallbackInAgentLogin();
606
+ const browserResult = shouldUseLocalBrowserLogin({ playwrightFallback })
607
+ ? interactiveLogin({ playwrightFallback })
608
+ : null;
589
609
  if (browserResult) {
590
610
  printLoginResult(browserResult);
591
611
  } else {
592
- // CDP/Playwright 失败后的兜底策略:
593
- // Wukong/QoderWork in-app browser,优先使用 browser handoff;其余走 AI 对话框 QR handoff。
594
- if (activeTool && (activeTool.tool === 'wukong' || activeTool.tool === 'qoderwork')) {
595
- const { codexLogin } = require('../lib/auth/codex-login');
596
- const result = await codexLogin({ tool: activeTool.tool });
597
- printLoginResult(result);
598
- } else {
599
- const { startCodexQrLogin } = require('../lib/auth/qr-login');
600
- const result = await startCodexQrLogin({ corpId: getArgValue(loginArgs, '--corp-id') });
601
- printLoginResult(result);
602
- }
612
+ const { startCodexQrLogin } = require('../lib/auth/qr-login');
613
+ const result = await startCodexQrLogin({ corpId: getArgValue(loginArgs, '--corp-id') });
614
+ printLoginResult(result);
603
615
  }
604
616
  }
605
617
  } else if (shouldUseBrowserHandoffLogin(loginArgs)) {
@@ -617,7 +629,7 @@ async function main() {
617
629
  printLoginResult(cachedResult);
618
630
  break;
619
631
  }
620
- if (shouldUseDesktopBrowserLogin()) {
632
+ if (shouldUseLocalBrowserLogin({ playwrightFallback: true })) {
621
633
  const { interactiveLogin } = require('../lib/auth/login');
622
634
  const browserResult = interactiveLogin({ playwrightFallback: true });
623
635
  if (browserResult) {
@@ -760,6 +772,12 @@ async function main() {
760
772
  break;
761
773
  }
762
774
 
775
+ case 'er': {
776
+ const { run } = require('../lib/app/er');
777
+ await run(args);
778
+ break;
779
+ }
780
+
763
781
  case 'formula': {
764
782
  const subCommand = args[0];
765
783
  const subArgs = args.slice(1);
@@ -66,6 +66,7 @@ const { buildYidaI18n, normalizeYidaLocale, resolveContentLocale } = require('..
66
66
  const { banner, step, label, success, fail, warn, info, error, result, usage, hint, listItem } = require('../core/chalk');
67
67
  const { parseOpenOption, withBrowserHandoff } = require('../core/browser-handoff');
68
68
  const { default: babelTransform } = require('../core/babel-transform');
69
+ const { normalizeFormulaFieldRefs } = require('../formula/evaluate');
69
70
 
70
71
  // ── 选项类字段类型 ───────────────────────────────────
71
72
  const OPTION_FIELD_TYPES = ['RadioField', 'SelectField', 'CheckboxField', 'MultiSelectField'];
@@ -3601,13 +3602,34 @@ function jsString(value) {
3601
3602
  return JSON.stringify(value === undefined ? '' : value);
3602
3603
  }
3603
3604
 
3605
+ function compileCustomValidateSource(source) {
3606
+ const funcSource = String(source || 'function validateRule(value) { return true; }').trim();
3607
+ return 'function main(){\n \n "use strict";\n\nvar __compiledFunc__ = '
3608
+ + funcSource
3609
+ + ';\n return __compiledFunc__.apply(this, arguments);\n }';
3610
+ }
3611
+
3604
3612
  function normalizeCustomValidateParam(param) {
3605
- if (param && typeof param === 'object' && param.type === 'JSExpression') {
3606
- return param;
3613
+ if (param && typeof param === 'object' && param.type === 'js') {
3614
+ const source = param.source || 'function validateRule(value) { return true; }';
3615
+ return {
3616
+ compiled: param.compiled || compileCustomValidateSource(source),
3617
+ source: source,
3618
+ type: 'js',
3619
+ error: param.error || {},
3620
+ };
3621
+ }
3622
+ let funcSource = typeof param === 'string' ? param
3623
+ : (param && typeof param === 'object' && param.type === 'JSExpression') ? String(param.value || '')
3624
+ : String(param || '');
3625
+ if (!funcSource || !/function/.test(funcSource)) {
3626
+ funcSource = 'function validateRule(value) { return true; }';
3607
3627
  }
3608
3628
  return {
3609
- type: 'JSExpression',
3610
- value: String(param || 'function validateRule(value) { return true; }'),
3629
+ compiled: compileCustomValidateSource(funcSource),
3630
+ source: funcSource,
3631
+ type: 'js',
3632
+ error: {},
3611
3633
  };
3612
3634
  }
3613
3635
 
@@ -3617,6 +3639,9 @@ function buildCustomValidateExpressionParam(rule) {
3617
3639
 
3618
3640
  function buildCustomValidateParam(rule) {
3619
3641
  if (rule.type === 'customValidate' && rule.param) {
3642
+ if (typeof rule.param === 'object' && rule.param.type === 'js') {
3643
+ return rule.param;
3644
+ }
3620
3645
  return typeof rule.param === 'object' && rule.param.type === 'JSExpression'
3621
3646
  ? String(rule.param.value || '')
3622
3647
  : String(rule.param);
@@ -4357,6 +4382,11 @@ async function saveSchemaAndUpdateConfig(authRef, appType, formUuid, schema, ver
4357
4382
  const saveStep = stepOffset || 4;
4358
4383
  const configStep = saveStep + 1;
4359
4384
 
4385
+ const fixedRefs = normalizeFormulaFieldRefs(schema);
4386
+ if (fixedRefs > 0) {
4387
+ info(t('create_form.formula_prefix_fixed', fixedRefs));
4388
+ }
4389
+
4360
4390
  step(saveStep, t('create_form.step_save_schema', saveStep));
4361
4391
  info(t('create_form.sending_save'));
4362
4392