openyida 2026.8.28 → 2026.8.29

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 CHANGED
@@ -305,6 +305,10 @@ OPENYIDA_E2E=1 npm run eval:e2e -- --skill yida-dashboard --screenshot --auto-sc
305
305
  # above, here the agent self-orchestrates.
306
306
  OPENYIDA_E2E=1 npm run eval:generate -- --screenshot
307
307
 
308
+ # Re-evaluate an archived real CLI trace against the latest scenario contract and
309
+ # current read-only platform state. This does not run an agent or mutate resources.
310
+ npm run eval:replay -- --report <generation-report.json> --scenario <scenario.json> --app-type APP_XXX
311
+
308
312
  # Run all three in one pass (routing + tool-pipeline baseline + real generation).
309
313
  OPENYIDA_E2E=1 npm run eval:all -- --skill yida-dashboard --screenshot
310
314
 
@@ -406,7 +410,7 @@ Run `openyida --help` or `openyida <command> --help` for detailed usage.
406
410
  | `openyida create-form add-option <appType> <formUuid> <fieldLabel> <option1> [option2] ...` | Update a form page |
407
411
  | `openyida list-forms <appType> [--keyword <text>]` | List forms/pages in an app |
408
412
  | `openyida aggregate-table <list\|create-empty\|inspect\|preview\|save\|publish\|status> <appType> ...` | Manage aggregate tables (virtualView) |
409
- | `openyida get-schema <appType> <formUuid\|--all> [--summary-json\|--field-map-json]` | Get one form Schema or all form Schemas |
413
+ | `openyida get-schema <appType> <formUuid\|--all> [--summary-json\|--field-map-json\|--analysis-json]` | Get one form Schema or all form Schemas |
410
414
  | `openyida check-prd-completeness <prd.md> --app-type <appType> [--build-manifest <file>] [--json]` | Check PRD page/resource count risk |
411
415
  | `openyida er <appType> [--format mermaid\|json] [--output file] [--include-system] [--include-pages]` | Export app entity relationship diagram |
412
416
  | `openyida create-page <appType> "<name>" [--mode dashboard] [--hide-nav] [--locale zh_CN\|en_US\|ja_JP] [--open\|--no-open]` | Create a custom display page |
@@ -424,13 +428,13 @@ Run `openyida --help` or `openyida <command> --help` for detailed usage.
424
428
 
425
429
  | Command | Description |
426
430
  |---------|-------------|
427
- | `openyida data <action> <resource> [args]` | Unified data management (form/process/task/subform) |
431
+ | `openyida data <query\|get\|create\|update\|delete> <form\|process\|subform\|tasks\|operation-records\|task> [args]` | Unified data management (form/process/task/subform) |
428
432
  | `openyida task-center <type> [options]` | Global task center (todo/processed/cc etc.) |
429
433
  | `openyida basic-info <overview\|commodity\|grant\|capacity\|quota\|abs-path\|dataflow\|i18n\|domain>` | Query organization basic info, capacity, quotas, and domain settings |
430
434
  | `openyida read-dingtalk-doc <docUrl> [--output <file>] [--json]` | Fetch Markdown content from a DingTalk document |
431
435
  | `openyida read-dingtalk-tingji <taskUuid> [--json]` | Fetch DingTalk Tingji details by task UUID |
432
- | `openyida get-permission <appType> <formUuid>` | Query form permission config |
433
- | `openyida save-permission <appType> <formUuid> ...` | Save form permission config |
436
+ | `openyida get-permission <appType> <formUuid> [--package-uuid <packageUuid>] [--json]` | Query form permission config |
437
+ | `openyida save-permission <appType> <formUuid> --package-uuid <packageUuid> [--data-permission <json>\|--action-permission <json>\|--field-permission <json>]` | Save form permission config |
434
438
  | `openyida corp-manager <search-user\|list\|add\|remove\|address-book> ...` | Manage platform admins and address book permissions |
435
439
  | `openyida agent-center <list\|create\|update\|cancel\|range\|search-user> ...` | Manage process and departure delegation |
436
440
 
@@ -485,7 +489,7 @@ Run `openyida --help` or `openyida <command> --help` for detailed usage.
485
489
  |---------|-------------|
486
490
  | `openyida integration create <appType> ... [--spec file.json]` | Create integration automation flow |
487
491
  | `openyida integration update <appType> <formUuid> <processCode> --spec <desired-spec.json> [--publish]` | Probe integration update capability (currently blocked without full readback) |
488
- | `openyida integration list <appType> [--form-uuid <uuid>] [--status y\|n] [--json]` | List integration automation flows |
492
+ | `openyida integration list <appType> [--flow-types 1,2,3,5,6] [--form-uuid <uuid>] [--status y\|n] [--json]` | List integration automation flows |
489
493
  | `openyida integration enable <appType> <formUuid> <processCode>` | Enable integration automation flow |
490
494
  | `openyida integration disable <appType> <formUuid> <processCode>` | Disable integration automation flow |
491
495
  | `openyida integration check <appType...>` | Check abnormal integration automation run logs |
package/bin/yida.js CHANGED
@@ -484,6 +484,45 @@ function printCommandUsage(...lines) {
484
484
  console.log(lines.filter(Boolean).join('\n'));
485
485
  }
486
486
 
487
+ const MANIFEST_HELP_PATHS = Object.freeze({
488
+ 'get-schema': ['get-schema'],
489
+ 'query-data': ['data'],
490
+ 'data-manage': ['data'],
491
+ data: ['data'],
492
+ report: ['report'],
493
+ 'create-process': ['create-process'],
494
+ 'create-report': ['create-report'],
495
+ 'save-share-config': ['save-share-config'],
496
+ 'verify-short-url': ['verify-short-url'],
497
+ 'integration-create': ['integration', 'create'],
498
+ 'save-permission': ['save-permission'],
499
+ 'get-permission': ['get-permission'],
500
+ });
501
+
502
+ function printManifestCommandHelp(commandName) {
503
+ const canonicalPath = MANIFEST_HELP_PATHS[commandName];
504
+ if (!canonicalPath) {
505
+ return false;
506
+ }
507
+
508
+ const manifest = buildCommandManifest({ t, version: currentVersion });
509
+ const matches = manifest.commands.filter((entry) =>
510
+ canonicalPath.every((token, index) => entry.path[index] === token)
511
+ );
512
+ const exact = matches.find((entry) => entry.path.length === canonicalPath.length);
513
+ const entries = exact ? [exact] : matches;
514
+ if (entries.length === 0) {
515
+ return false;
516
+ }
517
+
518
+ printCommandUsage(...entries.flatMap((entry) => [
519
+ entry.usage,
520
+ entry.description,
521
+ ...(entry.examples || []),
522
+ ]));
523
+ return true;
524
+ }
525
+
487
526
  function printLoginHelp() {
488
527
  printCommandUsage(t('cli.login_usage'), t('cli.login_example'));
489
528
  }
@@ -549,6 +588,10 @@ async function main() {
549
588
  return;
550
589
  }
551
590
 
591
+ if (hasHelpFlag(args) && printManifestCommandHelp(command)) {
592
+ return;
593
+ }
594
+
552
595
  switch (command) {
553
596
  case 'commands': {
554
597
  if (args[0] === 'validate' || args[0] === 'build') {
@@ -3,8 +3,8 @@
3
3
  *
4
4
  * 用法:
5
5
  * openyida get-schema <appType> <formUuid> [--compact] [--resolve-fields <labelOrFieldId,...>]
6
- * openyida get-schema <appType> <formUuid> [--summary-json|--field-map-json]
7
- * openyida get-schema <appType> --all [--summary-json] [--output-dir <dir>] [--concurrency N] [--retries N]
6
+ * openyida get-schema <appType> <formUuid> [--summary-json|--field-map-json|--analysis-json]
7
+ * openyida get-schema <appType> --all [--summary-json|--analysis-json] [--output-dir <dir>] [--concurrency N] [--retries N]
8
8
  */
9
9
 
10
10
  'use strict';
@@ -22,15 +22,27 @@ const { t } = require('../core/i18n');
22
22
  const { throwCommandError } = require('../core/command-errors');
23
23
  const { fetchFormPageList } = require('./form-navigation');
24
24
  const { buildFieldResolution } = require('./schema-field-resolution');
25
+ const { buildSemanticAnalysis } = require('./schema-semantic-analysis');
25
26
 
26
27
  // 需要在报表 fieldCode 中加 _value 后缀的字段类型
27
28
  const FIELD_TYPES_NEEDING_VALUE_SUFFIX = new Set([
28
29
  'SelectField',
30
+ 'MultiSelectField',
29
31
  'EmployeeField',
32
+ 'DepartmentSelectField',
30
33
  'RadioField',
31
34
  'CheckboxField',
32
35
  ]);
33
36
 
37
+ const FIELD_COMPONENT_NAMES = new Set([
38
+ 'TextField', 'TextareaField', 'SelectField', 'MultiSelectField',
39
+ 'DateField', 'CascadeDateField', 'NumberField', 'RadioField', 'CheckboxField',
40
+ 'EmployeeField', 'DepartmentSelectField', 'PhoneField', 'EmailField',
41
+ 'CascadeSelectField', 'CountrySelectField', 'CitySelectField', 'AddressField',
42
+ 'ImageField', 'AttachmentField', 'TableField', 'AssociationFormField',
43
+ 'RateField', 'SignatureField', 'SerialNumberField',
44
+ ]);
45
+
34
46
  /**
35
47
  * 从 Schema 中提取字段摘要,列出每个字段的真实 fieldId、组件别名和报表用 reportFieldCode。
36
48
  * @param {object} schemaResult - getFormSchema API 返回结果
@@ -44,12 +56,6 @@ function extractFieldSummary(schemaResult) {
44
56
  }
45
57
  const aliasMaps = buildComponentAliasMaps(schemaResult);
46
58
 
47
- const FIELD_COMPONENT_NAMES = new Set([
48
- 'TextField', 'TextareaField', 'SelectField', 'DateField', 'NumberField',
49
- 'RadioField', 'CheckboxField', 'EmployeeField', 'PhoneField', 'EmailField',
50
- 'CascadeSelectField', 'ImageField', 'AttachmentField', 'TableField',
51
- ]);
52
-
53
59
  function traverse(node) {
54
60
  if (!node) {
55
61
  return;
@@ -67,6 +73,15 @@ function extractFieldSummary(schemaResult) {
67
73
  if (fieldId) {
68
74
  const options = extractOptionSummary(props);
69
75
  const optionSource = getOptionSource(props) || [];
76
+ const complexDefault = props.complexValue && typeof props.complexValue === 'object'
77
+ ? props.complexValue.value
78
+ : undefined;
79
+ const defaultValue = firstPresent([complexDefault, props.defaultValue, props.value, props.default]);
80
+ const validationRules = Array.isArray(props.validation) ? props.validation : [];
81
+ const hasRequiredSignal = Object.prototype.hasOwnProperty.call(props, 'required')
82
+ || validationRules.some(rule => rule && (rule.type === 'required' || rule.required === true));
83
+ const required = props.required === true || props.required === 'true'
84
+ || validationRules.some(rule => rule && (rule.type === 'required' || rule.required === true));
70
85
  fields.push({
71
86
  label,
72
87
  componentName: node.componentName,
@@ -76,6 +91,10 @@ function extractFieldSummary(schemaResult) {
76
91
  options,
77
92
  optionCount: optionSource.length,
78
93
  optionsTruncated: optionSource.length > options.length,
94
+ ...(hasRequiredSignal
95
+ ? { required }
96
+ : {}),
97
+ ...(defaultValue !== undefined ? { defaultValue } : {}),
79
98
  });
80
99
  }
81
100
  }
@@ -321,6 +340,7 @@ function parseArgs(args) {
321
340
  field: '',
322
341
  json: false,
323
342
  summaryJson: false,
343
+ analysisJson: false,
324
344
  };
325
345
 
326
346
  for (let index = 1; index < args.length; index++) {
@@ -354,6 +374,8 @@ function parseArgs(args) {
354
374
  parsed.json = true;
355
375
  } else if (arg === '--summary-json' || arg === '--field-map-json') {
356
376
  parsed.summaryJson = true;
377
+ } else if (arg === '--analysis-json') {
378
+ parsed.analysisJson = true;
357
379
  } else if (!arg.startsWith('--') && !parsed.formUuid) {
358
380
  parsed.formUuid = arg;
359
381
  }
@@ -426,15 +448,6 @@ function collectFieldNodes(schemaResult) {
426
448
  const pages = schemaResult && schemaResult.content && schemaResult.content.pages;
427
449
  if (!pages || pages.length === 0) {return nodes;}
428
450
 
429
- const FIELD_COMPONENT_NAMES = new Set([
430
- 'TextField', 'TextareaField', 'SelectField', 'DateField', 'NumberField',
431
- 'RadioField', 'CheckboxField', 'EmployeeField', 'PhoneField', 'EmailField',
432
- 'CascadeSelectField', 'ImageField', 'AttachmentField', 'TableField',
433
- 'MultiSelectField', 'DepartmentSelectField', 'AssociationFormField',
434
- 'CountrySelectField', 'CitySelectField', 'RateField', 'SignatureField',
435
- 'SerialNumberField',
436
- ]);
437
-
438
451
  function traverse(node) {
439
452
  if (!node) {return;}
440
453
  if (FIELD_COMPONENT_NAMES.has(node.componentName)) {
@@ -486,7 +499,10 @@ async function fetchSchema(appType, formUuid, authRef) {
486
499
  }
487
500
 
488
501
  function isSuccessfulSchemaResult(result) {
489
- return !!(result && result.success !== false && !result.__needLogin);
502
+ const content = resolveSchemaContent(result);
503
+ const pages = content && content.pages;
504
+ return !!(result && result.success !== false && !result.__needLogin
505
+ && Array.isArray(pages));
490
506
  }
491
507
 
492
508
  function printFieldSummary(result) {
@@ -722,6 +738,16 @@ async function runSingle(parsed, authRef) {
722
738
  return;
723
739
  }
724
740
 
741
+ if (parsed.analysisJson) {
742
+ console.log(JSON.stringify(buildSemanticAnalysis(
743
+ parsed.appType,
744
+ parsed.formUuid,
745
+ result,
746
+ extractFieldSummary(result)
747
+ ), null, 2));
748
+ return;
749
+ }
750
+
725
751
  chalkSuccess(t('get_schema.success'));
726
752
  printFieldSummary(result);
727
753
  console.log(JSON.stringify(result, null, 2));
@@ -756,6 +782,14 @@ async function runBatch(parsed, authRef) {
756
782
 
757
783
  const records = await mapLimit(forms, parsed.concurrency, async (form) => {
758
784
  const record = await fetchSchemaRecord(parsed.appType, form, authRef, parsed.retries);
785
+ if (record.success && parsed.analysisJson) {
786
+ record.semanticAnalysis = buildSemanticAnalysis(
787
+ parsed.appType,
788
+ record.formUuid,
789
+ record.schema,
790
+ record.fieldSummary
791
+ );
792
+ }
759
793
  if (record.success) {
760
794
  info(` ✅ ${record.formName || record.formUuid}`);
761
795
  } else {
@@ -764,7 +798,9 @@ async function runBatch(parsed, authRef) {
764
798
  return record;
765
799
  });
766
800
 
767
- const outputRecords = writeBatchOutput(parsed.outputDir, records, { compact: parsed.summaryJson });
801
+ const outputRecords = writeBatchOutput(parsed.outputDir, records, {
802
+ compact: parsed.summaryJson || parsed.analysisJson,
803
+ });
768
804
  const successCount = records.filter(record => record.success).length;
769
805
  const failedCount = records.length - successCount;
770
806
 
@@ -780,6 +816,7 @@ async function runBatch(parsed, authRef) {
780
816
  successCount,
781
817
  failedCount,
782
818
  summaryOnly: parsed.summaryJson || undefined,
819
+ analysisOnly: parsed.analysisJson || undefined,
783
820
  outputDir: parsed.outputDir ? path.resolve(parsed.outputDir) : undefined,
784
821
  forms: outputRecords,
785
822
  }, null, 2));
@@ -800,6 +837,8 @@ module.exports = {
800
837
  extractFieldSummary,
801
838
  extractOptionSummary,
802
839
  buildSchemaSummary,
840
+ buildSemanticAnalysis,
841
+ isSuccessfulSchemaResult,
803
842
  buildComponentAliasMaps,
804
843
  parseArgs,
805
844
  appendFieldQueries,
@@ -0,0 +1,223 @@
1
+ 'use strict';
2
+
3
+ const crypto = require('crypto');
4
+
5
+ function parseObject(value) {
6
+ if (typeof value !== 'string') {
7
+ return value && typeof value === 'object' ? value : null;
8
+ }
9
+ try {
10
+ const parsed = JSON.parse(value);
11
+ return parsed && typeof parsed === 'object' ? parsed : null;
12
+ } catch {
13
+ return null;
14
+ }
15
+ }
16
+
17
+ function resolveContent(schemaResult) {
18
+ if (!schemaResult) {return null;}
19
+ return parseObject(schemaResult.content !== undefined ? schemaResult.content : schemaResult);
20
+ }
21
+
22
+ function labelText(label) {
23
+ if (label === null || label === undefined) {return '';}
24
+ if (typeof label === 'object') {
25
+ return String(label.zh_CN || label.zh_HK || label.en_US || label.text || label.label || '');
26
+ }
27
+ return String(label);
28
+ }
29
+
30
+ function unique(values) {
31
+ return [...new Set(values.filter(Boolean))].sort();
32
+ }
33
+
34
+ function isPresent(value) {
35
+ if (value === null || value === undefined || value === '') {return false;}
36
+ if (Array.isArray(value)) {return value.length > 0;}
37
+ if (typeof value === 'object') {return Object.keys(value).length > 0;}
38
+ return true;
39
+ }
40
+
41
+ function hasFormulaSemantics(value) {
42
+ if (!isPresent(value)) {return false;}
43
+ if (typeof value === 'string') {return value.trim() !== '';}
44
+ if (Array.isArray(value)) {return value.length > 0;}
45
+ if (typeof value !== 'object') {return true;}
46
+ if (['expression', 'source', 'value', 'formula'].some(key => isPresent(value[key]))) {
47
+ return true;
48
+ }
49
+ if (Array.isArray(value.data) && value.data.length > 0) {return true;}
50
+ if (value.event && typeof value.event === 'object') {
51
+ return Object.values(value.event).some(events => Array.isArray(events) ? events.length > 0 : isPresent(events));
52
+ }
53
+ return false;
54
+ }
55
+
56
+ function extractFunctionNames(source) {
57
+ const names = [];
58
+ const patterns = [
59
+ /export\s+(?:async\s+)?function\s+([A-Za-z_$][\w$]*)\s*\(/g,
60
+ /exports\.([A-Za-z_$][\w$]*)\s*=\s*/g,
61
+ ];
62
+ for (const pattern of patterns) {
63
+ let match;
64
+ while ((match = pattern.exec(source)) !== null) {
65
+ names.push(match[1]);
66
+ }
67
+ }
68
+ return unique(names);
69
+ }
70
+
71
+ function extractUrlParams(source) {
72
+ const keys = [];
73
+ const pattern = /urlParams(?:\.([A-Za-z_$][\w$]*)|\[['"]([^'"]+)['"]\])/g;
74
+ let match;
75
+ while ((match = pattern.exec(source)) !== null) {
76
+ keys.push(match[1] || match[2]);
77
+ }
78
+ return unique(keys);
79
+ }
80
+
81
+ function extractFieldMutations(source) {
82
+ const mutations = [];
83
+ const pattern = /this\.\$\(\s*['"]([^'"]+)['"]\s*\)\s*\.\s*(setValue|setBehavior|reset|validate|show|hide)\s*\(/g;
84
+ let match;
85
+ while ((match = pattern.exec(source)) !== null) {
86
+ mutations.push({ fieldId: match[1], operation: match[2] });
87
+ }
88
+ const seen = new Set();
89
+ return mutations.filter((item) => {
90
+ const key = `${item.fieldId}:${item.operation}`;
91
+ if (seen.has(key)) {return false;}
92
+ seen.add(key);
93
+ return true;
94
+ });
95
+ }
96
+
97
+ function bindingFromValue(value, path) {
98
+ if (!value || typeof value !== 'object' || value.type !== 'actionRef') {return null;}
99
+ return {
100
+ event: path[path.length - 1] || '',
101
+ actionName: value.name || value.id || '',
102
+ fieldId: path.find(part => typeof part === 'string' && /Field_/.test(part)) || '',
103
+ };
104
+ }
105
+
106
+ function buildSemanticAnalysis(appType, formUuid, schemaResult, fieldSummary = []) {
107
+ const content = resolveContent(schemaResult) || {};
108
+ const actionModule = content.actions && content.actions.module || {};
109
+ const source = typeof actionModule.source === 'string' ? actionModule.source : '';
110
+ const compiled = typeof actionModule.compiled === 'string' ? actionModule.compiled : '';
111
+ const fieldBehaviors = [];
112
+ const bindings = [];
113
+ let associationRuleCount = 0;
114
+
115
+ function visit(value, path = []) {
116
+ if (!value) {return;}
117
+ if (Array.isArray(value)) {
118
+ value.forEach((item, index) => visit(item, path.concat(index)));
119
+ return;
120
+ }
121
+ if (typeof value !== 'object') {return;}
122
+
123
+ const binding = bindingFromValue(value, path);
124
+ if (binding) {bindings.push(binding);}
125
+
126
+ const props = value.props || {};
127
+ if (Array.isArray(props.associationRules)) {
128
+ associationRuleCount += props.associationRules.length;
129
+ }
130
+ if (props.fieldId) {
131
+ const validation = Array.isArray(props.validation) ? props.validation : [];
132
+ const validationTypes = unique(validation.map(rule => rule && (rule.type || rule.name || (rule.required ? 'required' : ''))));
133
+ const behavior = props.behavior && props.behavior !== 'NORMAL' ? String(props.behavior) : '';
134
+ const formula = hasFormulaSemantics(props.formula)
135
+ || hasFormulaSemantics(props.defaultDataSource && props.defaultDataSource.formula);
136
+ const dataSourceUrl = props.remoteDataSource && props.remoteDataSource.url
137
+ || props.dataSource && !Array.isArray(props.dataSource) && props.dataSource.url
138
+ || props.dataSource && props.dataSource.searchConfig && props.dataSource.searchConfig.url
139
+ || '';
140
+ const hasDataSourceBinding = !!(
141
+ props.remoteDataSource
142
+ || dataSourceUrl
143
+ || props.dataSourceLinkage
144
+ || (props.dataSourceType && props.dataSourceType !== 'custom')
145
+ );
146
+ const association = props.associationForm || props.associationFormConfig || null;
147
+ if (behavior || validationTypes.length || formula || hasDataSourceBinding || association) {
148
+ fieldBehaviors.push({
149
+ fieldId: String(props.fieldId),
150
+ label: labelText(props.label),
151
+ componentName: value.componentName || '',
152
+ ...(behavior ? { behavior } : {}),
153
+ ...(validationTypes.length ? { validationTypes } : {}),
154
+ ...(formula ? { hasFormulaOrLinkage: true } : {}),
155
+ ...(hasDataSourceBinding ? {
156
+ dataSource: {
157
+ type: props.dataSourceType || (props.remoteDataSource ? 'remote' : 'linked'),
158
+ hasUrl: !!dataSourceUrl,
159
+ },
160
+ } : {}),
161
+ ...(association ? {
162
+ association: {
163
+ formUuid: association.formUuid || association.targetFormUuid || association.formId || '',
164
+ hasBackfill: !!(association.backfill || association.backfillRules || association.fillRules),
165
+ },
166
+ } : {}),
167
+ });
168
+ }
169
+ }
170
+
171
+ Object.keys(value).forEach((key) => {
172
+ if (key !== 'source' && key !== 'compiled') {
173
+ visit(value[key], path.concat(key));
174
+ }
175
+ });
176
+ }
177
+
178
+ visit(content.pages || []);
179
+
180
+ const actionList = content.actions && Array.isArray(content.actions.list)
181
+ ? content.actions.list
182
+ : [];
183
+ const actionEntries = actionList.map(item => ({
184
+ id: item.id || item.name || '',
185
+ name: item.name || item.title || item.id || '',
186
+ type: item.type || '',
187
+ relatedEventId: item.relatedEventId || '',
188
+ }));
189
+ const mutationFields = unique(extractFieldMutations(source).map(item => item.fieldId));
190
+
191
+ return {
192
+ kind: 'yida_schema_semantic_analysis',
193
+ contractVersion: 1,
194
+ resource: {
195
+ appType,
196
+ formUuid,
197
+ schemaHash: `sha256:${crypto.createHash('sha256').update(JSON.stringify(content)).digest('hex')}`,
198
+ },
199
+ fieldCount: fieldSummary.length,
200
+ fields: fieldSummary,
201
+ semantics: {
202
+ actions: {
203
+ sourceBytes: Buffer.byteLength(source, 'utf8'),
204
+ compiledBytes: Buffer.byteLength(compiled, 'utf8'),
205
+ functions: extractFunctionNames(source),
206
+ entries: actionEntries,
207
+ bindings,
208
+ urlParams: extractUrlParams(source),
209
+ fieldMutations: extractFieldMutations(source),
210
+ referencedMutationFields: mutationFields,
211
+ },
212
+ fieldBehaviors,
213
+ associationRuleCount,
214
+ },
215
+ };
216
+ }
217
+
218
+ module.exports = {
219
+ buildSemanticAnalysis,
220
+ extractFieldMutations,
221
+ extractFunctionNames,
222
+ extractUrlParams,
223
+ };
@@ -136,6 +136,10 @@ const BUILDER_CORE_COMMAND_IDS = Object.freeze([
136
136
  'app-list',
137
137
  'list-forms',
138
138
  'get-schema',
139
+ 'data',
140
+ 'nav-group',
141
+ 'get-permission',
142
+ 'save-permission',
139
143
  'create-app',
140
144
  'create-form.create',
141
145
  'create-page',
@@ -154,6 +158,7 @@ function commandBriefs(manifest, commandIds) {
154
158
  output: entry.output,
155
159
  permission_mode: entry.permission && entry.permission.mode,
156
160
  side_effect_kind: entry.side_effect && entry.side_effect.kind,
161
+ examples: entry.examples || [],
157
162
  }));
158
163
  }
159
164
 
@@ -920,7 +920,7 @@ const FORBIDDEN_ALIASES = Object.freeze([
920
920
  suggested_usage: 'openyida app-list [--size N]',
921
921
  alternative_command_ids: ['get-schema', 'agent-capabilities'],
922
922
  alternative_usages: [
923
- 'openyida get-schema <appType> <formUuid|--all> [--summary-json|--field-map-json]',
923
+ 'openyida get-schema <appType> <formUuid|--all> [--summary-json|--field-map-json|--analysis-json]',
924
924
  'openyida agent-capabilities --summary-json',
925
925
  ],
926
926
  message_key: 'cli.forbidden_alias_get_app',
@@ -958,7 +958,7 @@ const FORBIDDEN_ALIASES = Object.freeze([
958
958
  pattern: 'get-schema --app-type',
959
959
  matcher: { type: 'command_has_option', command: 'get-schema', option: '--app-type' },
960
960
  suggested_command_id: 'get-schema',
961
- suggested_usage: 'openyida get-schema <appType> <formUuid|--all> [--summary-json|--field-map-json]',
961
+ suggested_usage: 'openyida get-schema <appType> <formUuid|--all> [--summary-json|--field-map-json|--analysis-json]',
962
962
  message_key: 'cli.forbidden_alias_get_schema_app_type_option',
963
963
  message_args: ['get-schema', '--app-type'],
964
964
  }),
@@ -967,7 +967,7 @@ const FORBIDDEN_ALIASES = Object.freeze([
967
967
  pattern: 'get-schema --form-uuid',
968
968
  matcher: { type: 'command_has_option', command: 'get-schema', option: '--form-uuid' },
969
969
  suggested_command_id: 'get-schema',
970
- suggested_usage: 'openyida get-schema <appType> <formUuid|--all> [--summary-json|--field-map-json]',
970
+ suggested_usage: 'openyida get-schema <appType> <formUuid|--all> [--summary-json|--field-map-json|--analysis-json]',
971
971
  message_key: 'cli.forbidden_alias_get_schema_form_uuid_option',
972
972
  message_args: ['get-schema', '--form-uuid'],
973
973
  }),
@@ -1038,6 +1038,10 @@ const COMMAND_GROUPS = [
1038
1038
  command('nav-group', ['nav-group'], 'nav-group <list|create|rename|delete|move|order|auto-order|hide|show> <appType> ...', 'help.cmd_nav_group', {
1039
1039
  output: 'json',
1040
1040
  aliases: ['group'],
1041
+ examples: [
1042
+ 'openyida nav-group list APP_XXX --flat',
1043
+ 'openyida nav-group move APP_XXX FORM_XXX --to NAV_XXX',
1044
+ ],
1041
1045
  }),
1042
1046
  command('app-permission', ['app-permission'], 'app-permission <get|set|add|remove|search-user> ...', 'help.cmd_app_permission', {
1043
1047
  output: 'json',
@@ -1133,11 +1137,15 @@ const COMMAND_GROUPS = [
1133
1137
  command('add-validation', ['add-validation'], 'add-validation <appType> <formUuid> --field <labelOrId> --type <phone|regex|idCard|email|...> [--message <text>]', 'help.cmd_update_form'),
1134
1138
  command('create-form.bind-datasource', ['create-form', 'bind-datasource'], 'create-form bind-datasource <appType> <formUuid> <fieldLabelOrId> <dataSourceJsonOrFile> [--open|--no-open]', 'help.cmd_update_form'),
1135
1139
  command('create-form.add-option', ['create-form', 'add-option'], 'create-form add-option <appType> <formUuid> <fieldLabel> <option1> [option2] ...', 'help.cmd_update_form'),
1136
- command('list-forms', ['list-forms'], 'list-forms <appType> [--keyword <text>]', 'help.cmd_list_forms'),
1140
+ command('list-forms', ['list-forms'], 'list-forms <appType> [--keyword <text>]', 'help.cmd_list_forms', {
1141
+ examples: ['openyida list-forms APP_XXX --keyword 客户'],
1142
+ }),
1137
1143
  command('aggregate-table', ['aggregate-table'], 'aggregate-table <list|create-empty|inspect|preview|save|publish|status> <appType> ...', 'help.cmd_aggregate_table', {
1138
1144
  output: 'json',
1139
1145
  }),
1140
- command('get-schema', ['get-schema'], 'get-schema <appType> <formUuid|--all> [--summary-json|--field-map-json]', 'help.cmd_get_schema'),
1146
+ command('get-schema', ['get-schema'], 'get-schema <appType> <formUuid|--all> [--summary-json|--field-map-json|--analysis-json]', 'help.cmd_get_schema', {
1147
+ examples: ['openyida get-schema APP_XXX FORM_XXX --field-map-json'],
1148
+ }),
1141
1149
  command('check-prd-completeness', ['check-prd-completeness'], 'check-prd-completeness <prd.md> --app-type <appType> [--build-manifest <file>] [--json]', 'help.cmd_check_prd_completeness', {
1142
1150
  output: 'json',
1143
1151
  }),
@@ -1160,7 +1168,11 @@ const COMMAND_GROUPS = [
1160
1168
  id: 'data',
1161
1169
  titleKey: 'help.group_data',
1162
1170
  commands: [
1163
- command('data', ['data'], 'data <action> <resource> [args]', 'help.cmd_data'),
1171
+ command('data', ['data'], 'data <query|get|create|update|delete> <form|process|subform|tasks|operation-records|task> [args]', 'help.cmd_data', {
1172
+ examples: [
1173
+ 'openyida data create form APP_XXX FORM_XXX --data-json \'{"textField_name":"客户 A","dateField_followUp":1787932800000}\'',
1174
+ ],
1175
+ }),
1164
1176
  command('task-center', ['task-center'], 'task-center <type> [options]', 'help.cmd_task_center'),
1165
1177
  command('basic-info', ['basic-info'], 'basic-info <overview|commodity|grant|capacity|quota|abs-path|dataflow|i18n|domain>', 'help.cmd_basic_info', {
1166
1178
  output: 'json',
@@ -1171,8 +1183,13 @@ const COMMAND_GROUPS = [
1171
1183
  command('read-dingtalk-tingji', ['read-dingtalk-tingji'], 'read-dingtalk-tingji <taskUuid> [--json]', 'help.cmd_read_dingtalk_tingji', {
1172
1184
  output: 'json',
1173
1185
  }),
1174
- command('get-permission', ['get-permission'], 'get-permission <appType> <formUuid>', 'help.cmd_get_permission'),
1175
- command('save-permission', ['save-permission'], 'save-permission <appType> <formUuid> ...', 'help.cmd_save_permission'),
1186
+ command('get-permission', ['get-permission'], 'get-permission <appType> <formUuid> [--package-uuid <packageUuid>] [--json]', 'help.cmd_get_permission'),
1187
+ command('save-permission', ['save-permission'], 'save-permission <appType> <formUuid> --package-uuid <packageUuid> [--data-permission <json>|--action-permission <json>|--field-permission <json>]', 'help.cmd_save_permission', {
1188
+ examples: [
1189
+ 'openyida get-permission APP_XXX FORM_XXX --json',
1190
+ 'openyida save-permission APP_XXX FORM_XXX --package-uuid PACKAGE_XXX --data-permission \'{"dataRange":"ORIGINATOR"}\'',
1191
+ ],
1192
+ }),
1176
1193
  command('corp-manager', ['corp-manager'], 'corp-manager <search-user|list|add|remove|address-book> ...', 'help.cmd_corp_manager', { output: 'json' }),
1177
1194
  command('agent-center', ['agent-center'], 'agent-center <list|create|update|cancel|range|search-user> ...', 'help.cmd_agent_center', { output: 'json' }),
1178
1195
  ],
@@ -1240,7 +1257,7 @@ const COMMAND_GROUPS = [
1240
1257
  requiresLogin: false,
1241
1258
  output: 'json',
1242
1259
  }),
1243
- command('integration.list', ['integration', 'list'], 'integration list <appType> [--form-uuid <uuid>] [--status y|n] [--json]', 'help.cmd_integration_list', {
1260
+ command('integration.list', ['integration', 'list'], 'integration list <appType> [--flow-types 1,2,3,5,6] [--form-uuid <uuid>] [--status y|n] [--json]', 'help.cmd_integration_list', {
1244
1261
  output: 'json',
1245
1262
  }),
1246
1263
  command('integration.enable', ['integration', 'enable'], 'integration enable <appType> <formUuid> <processCode>', 'help.cmd_integration_enable', {
@@ -419,7 +419,7 @@ function buildAuthRef() {
419
419
  }));
420
420
  }
421
421
 
422
- function appendFlow(result, group, flow) {
422
+ function appendFlow(result, group, flow, flowType = '') {
423
423
  if (!flow || !flow.processCode || result.seenProcessCodes.has(flow.processCode)) {
424
424
  return;
425
425
  }
@@ -435,6 +435,7 @@ function appendFlow(result, group, flow) {
435
435
  status: flow.status || '',
436
436
  eventName: flow.eventName || '',
437
437
  eventType: flow.eventType || group.eventType || null,
438
+ flowType: String(flow.flowType || flow.type || group.flowType || group.type || flowType || ''),
438
439
  executeByOrder: flow.executeByOrder,
439
440
  gmtModified: flow.gmtModified || '',
440
441
  lastAction: flow.lastAction || '',
@@ -442,15 +443,15 @@ function appendFlow(result, group, flow) {
442
443
  });
443
444
  }
444
445
 
445
- function collectFlowsFromListResponse(result, response) {
446
+ function collectFlowsFromListResponse(result, response, flowType = '') {
446
447
  const groups = response.data || [];
447
448
  for (const item of groups) {
448
449
  if (Array.isArray(item.flowList)) {
449
450
  for (const flow of item.flowList) {
450
- appendFlow(result, item, flow);
451
+ appendFlow(result, item, flow, flowType);
451
452
  }
452
453
  } else {
453
- appendFlow(result, {}, item);
454
+ appendFlow(result, {}, item, flowType);
454
455
  }
455
456
  }
456
457
  }
@@ -478,7 +479,7 @@ async function listAllFlowsForForm(authRef, appType, formUuid, baseGroup, option
478
479
  pageIndex,
479
480
  pageSize,
480
481
  });
481
- collectFlowsFromListResponse(flows, response);
482
+ collectFlowsFromListResponse(flows, response, type);
482
483
  totalCount = response.totalCount || totalCount;
483
484
  pageIndex++;
484
485
  if (!response.hasMore && (!totalCount || (pageIndex - 1) * pageSize >= totalCount)) {
@@ -527,7 +528,7 @@ async function listAllLogicflows(authRef, appType, options = {}) {
527
528
  pageIndex,
528
529
  pageSize,
529
530
  });
530
- collectFlowsFromListResponse(result, response);
531
+ collectFlowsFromListResponse(result, response, type);
531
532
  for (const group of response.data || []) {
532
533
  if (group && group.formUuid && group.hasMore) {
533
534
  groupsWithMore.push(group);