openyida 2026.8.30 → 2026.8.31

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
@@ -430,7 +430,7 @@ Run `openyida --help` or `openyida <command> --help` for detailed usage.
430
430
 
431
431
  | Command | Description |
432
432
  |---------|-------------|
433
- | `openyida data <query\|get\|create\|update\|delete> <form\|process\|subform\|tasks\|operation-records\|task> [args]` | Unified data management (form/process/task/subform) |
433
+ | `openyida data <query\|get\|create\|update> <resource> ... \| delete form <appType> <formUuid> --inst-id <id> --confirm [--json]` | Unified data management (form/process/task/subform) |
434
434
  | `openyida task-center <type> [options]` | Global task center (todo/processed/cc etc.) |
435
435
  | `openyida basic-info <overview\|commodity\|grant\|capacity\|quota\|abs-path\|dataflow\|i18n\|domain>` | Query organization basic info, capacity, quotas, and domain settings |
436
436
  | `openyida read-dingtalk-doc <docUrl> [--output <file>] [--json]` | Fetch Markdown content from a DingTalk document |
@@ -462,8 +462,8 @@ Run `openyida --help` or `openyida <command> --help` for detailed usage.
462
462
 
463
463
  | Command | Description |
464
464
  |---------|-------------|
465
- | `openyida create-report <appType> "<name>" ... [--open\|--no-open]` | Create a Yida report |
466
- | `openyida append-chart <appType> <reportId> ... [--open\|--no-open]` | Append chart to existing report |
465
+ | `openyida create-report <appType> "<name>" ... [--json] [--open\|--no-open]` | Create a Yida report |
466
+ | `openyida append-chart <appType> <reportId> ... [--json] [--open\|--no-open]` | Append chart to existing report |
467
467
  | `openyida report inspect <appType> <reportId> --json` | Inspect report runtime bindings (read-only) |
468
468
 
469
469
  ### Connectors
package/bin/yida.js CHANGED
@@ -13,7 +13,12 @@
13
13
  const { version: currentVersion } = require('../package.json');
14
14
  const { t } = require('../lib/core/i18n');
15
15
  const { warn } = require('../lib/core/chalk');
16
- const { CliError, isCliError, toErrorPayload } = require('../lib/core/cli-error');
16
+ const {
17
+ CliError,
18
+ isCliError,
19
+ shouldUseStructuredErrorOutput,
20
+ toErrorPayload,
21
+ } = require('../lib/core/cli-error');
17
22
  const { COMMAND_GROUPS, buildCommandManifest, findCommandSuggestion } = require('../lib/core/command-manifest');
18
23
 
19
24
  const command = process.argv[2];
@@ -492,11 +497,13 @@ const MANIFEST_HELP_PATHS = Object.freeze({
492
497
  report: ['report'],
493
498
  'create-process': ['create-process'],
494
499
  'create-report': ['create-report'],
500
+ 'append-chart': ['append-chart'],
495
501
  'save-share-config': ['save-share-config'],
496
502
  'verify-short-url': ['verify-short-url'],
497
503
  'integration-create': ['integration', 'create'],
498
504
  'save-permission': ['save-permission'],
499
505
  'get-permission': ['get-permission'],
506
+ copy: ['copy'],
500
507
  });
501
508
 
502
509
  function printManifestCommandHelp(commandName) {
@@ -1261,7 +1268,7 @@ async function main() {
1261
1268
 
1262
1269
  main()
1263
1270
  .catch((err) => {
1264
- if (isCliError(err) && args.includes('--json')) {
1271
+ if (shouldUseStructuredErrorOutput(err, args)) {
1265
1272
  console.error(JSON.stringify(toErrorPayload(err), null, 2));
1266
1273
  } else if (isCliError(err)) {
1267
1274
  warn(t('cli.exec_failed', err.message));
@@ -65,6 +65,31 @@ async function run(args) {
65
65
  modern: options.modern,
66
66
  });
67
67
 
68
+ const throwBuildFailure = () => {
69
+ const matchedPrimaryIssue = buildResult.errors.find(issue => issue.code === 'UNSUPPORTED_HOOK') || buildResult.errors[0];
70
+ const primaryIssue = matchedPrimaryIssue ? JSON.parse(JSON.stringify(matchedPrimaryIssue)) : undefined;
71
+ throwCommandError(t('build_page.failed'), {
72
+ code: 'BUILD_PAGE_FAILED',
73
+ details: {
74
+ errors: buildResult.errors,
75
+ primaryIssue,
76
+ retryable: false,
77
+ retrySafe: true,
78
+ sideEffectState: 'none',
79
+ sourceRepairable: buildResult.errors.length > 0,
80
+ nextAction: {
81
+ type: 'edit_source_then_recheck',
82
+ commandId: 'check-page',
83
+ args: { sourcePath },
84
+ },
85
+ },
86
+ });
87
+ };
88
+
89
+ if (!buildResult.ok && options.json) {
90
+ throwBuildFailure();
91
+ }
92
+
68
93
  if (options.json) {
69
94
  console.log(JSON.stringify({
70
95
  ok: buildResult.ok,
@@ -92,10 +117,7 @@ async function run(args) {
92
117
  }
93
118
 
94
119
  if (!buildResult.ok) {
95
- throwCommandError(t('build_page.failed'), {
96
- code: 'BUILD_PAGE_FAILED',
97
- details: { errors: buildResult.errors },
98
- });
120
+ throwBuildFailure();
99
121
  }
100
122
 
101
123
  if (!options.json) {
@@ -44,6 +44,32 @@ async function run(args) {
44
44
  const buildErrors = buildResult && buildResult.errors ? buildResult.errors : [];
45
45
  const ok = buildErrors.length === 0 && lintResult.errors.length === 0;
46
46
 
47
+ const throwCheckFailure = () => {
48
+ const matchedPrimaryIssue = buildErrors.find(issue => issue.code === 'UNSUPPORTED_HOOK') || buildErrors[0] || lintResult.errors[0];
49
+ const primaryIssue = matchedPrimaryIssue ? JSON.parse(JSON.stringify(matchedPrimaryIssue)) : undefined;
50
+ throwCommandError(t('check_page.failed'), {
51
+ code: 'CHECK_PAGE_FAILED',
52
+ details: {
53
+ errors: lintResult.errors,
54
+ buildErrors,
55
+ primaryIssue,
56
+ retryable: false,
57
+ retrySafe: true,
58
+ sideEffectState: 'none',
59
+ sourceRepairable: buildErrors.length > 0,
60
+ nextAction: buildErrors.length > 0 ? {
61
+ type: 'edit_source_then_recheck',
62
+ commandId: 'check-page',
63
+ args: { sourcePath },
64
+ } : undefined,
65
+ },
66
+ });
67
+ };
68
+
69
+ if (!ok && options.json) {
70
+ throwCheckFailure();
71
+ }
72
+
47
73
  if (options.json) {
48
74
  console.log(JSON.stringify({
49
75
  ok,
@@ -67,13 +93,7 @@ async function run(args) {
67
93
  }
68
94
 
69
95
  if (!ok) {
70
- throwCommandError(t('check_page.failed'), {
71
- code: 'CHECK_PAGE_FAILED',
72
- details: {
73
- errors: lintResult.errors,
74
- buildErrors,
75
- },
76
- });
96
+ throwCheckFailure();
77
97
  }
78
98
  }
79
99
 
@@ -352,6 +352,7 @@ function createFieldNormalizers(deps) {
352
352
  'mac',
353
353
  'chineseID',
354
354
  'customValidate',
355
+ 'regex',
355
356
  ].indexOf(rule.type) !== -1;
356
357
  }
357
358
 
@@ -31,6 +31,12 @@ const SUPPORTED_REMOVABLE_IMPORTS = new Set([
31
31
  ]);
32
32
 
33
33
  const SUPPORTED_HOOKS = new Set(['useState', 'useEffect']);
34
+ const UNSUPPORTED_HOOK_REPAIRS = Object.freeze({
35
+ useReducer: 'Replace the reducer with supported useState state updates, or move the page to .canvas.jsx when reducer semantics are required.',
36
+ useMemo: 'Compute the derived value with a plain local expression, or move the page to .canvas.jsx when memoization is required.',
37
+ useCallback: 'Use a plain local function, or move the page to .canvas.jsx when stable callback identity is required.',
38
+ useLayoutEffect: 'Use supported useEffect(..., []) for mount-only work, or move the page to .canvas.jsx when layout effects are required.',
39
+ });
34
40
  const REQUIRED_RUNTIME_EXPORTS = {
35
41
  getCustomState: [
36
42
  'export function getCustomState(key) {',
@@ -783,7 +789,20 @@ function collectUnsupportedHooks(ast, errors) {
783
789
  errors.push({
784
790
  code: 'UNSUPPORTED_HOOK',
785
791
  message: `${name} is not supported in OpenYida authoring mode.`,
792
+ hook: name,
786
793
  line: pathRef.node.loc && pathRef.node.loc.start && pathRef.node.loc.start.line,
794
+ retryable: false,
795
+ retrySafe: true,
796
+ sideEffectState: 'none',
797
+ sourceRepairable: true,
798
+ supportedHooks: [...SUPPORTED_HOOKS],
799
+ recommendedAuthoringMode: 'canvas',
800
+ replacement: UNSUPPORTED_HOOK_REPAIRS[name]
801
+ || 'Use only supported useState/useEffect(..., []) authoring, or move the page to .canvas.jsx for full React Hook support.',
802
+ nextAction: {
803
+ type: 'edit_source_then_recheck',
804
+ commandId: 'check-page',
805
+ },
787
806
  });
788
807
  }
789
808
  },
@@ -564,7 +564,28 @@ async function runMain(argv) {
564
564
  buildResult.errors.forEach((issue) => warn(`${issue.code}: ${issue.message}`));
565
565
  const lintErrors = buildResult.lint && buildResult.lint.errors ? buildResult.lint.errors : [];
566
566
  lintErrors.forEach((issue) => warn(`${issue.rule}: ${issue.message}`));
567
- process.exit(1);
567
+ const matchedPrimaryIssue = buildResult.errors.find(issue => issue.code === 'UNSUPPORTED_HOOK')
568
+ || buildResult.errors[0]
569
+ || lintErrors[0];
570
+ const primaryIssue = matchedPrimaryIssue ? JSON.parse(JSON.stringify(matchedPrimaryIssue)) : undefined;
571
+ throw new CliError(t('build_page.failed'), {
572
+ code: 'BUILD_PAGE_FAILED',
573
+ details: {
574
+ sourcePath,
575
+ errors: buildResult.errors,
576
+ lintErrors,
577
+ primaryIssue,
578
+ retryable: false,
579
+ retrySafe: true,
580
+ sideEffectState: 'none',
581
+ sourceRepairable: buildResult.errors.length > 0,
582
+ nextAction: {
583
+ type: 'edit_source_then_recheck',
584
+ commandId: 'check-page',
585
+ args: { sourcePath },
586
+ },
587
+ },
588
+ });
568
589
  }
569
590
  sourcePath = buildResult.outputPath;
570
591
  success(t('build_page.output', sourcePath));
@@ -154,6 +154,7 @@ function isNativeFieldValidationRule(rule) {
154
154
  'mac',
155
155
  'chineseID',
156
156
  'customValidate',
157
+ 'regex',
157
158
  ].indexOf(rule.type) !== -1;
158
159
  }
159
160
 
@@ -368,7 +368,7 @@ function toAuthProfileCandidate(session = {}) {
368
368
  function buildAuthProfileNextStep(status) {
369
369
  if (status === 'profile_required') {
370
370
  return {
371
- next_step: 'Multiple auth profiles are available. Run openyida auth profiles, then run openyida auth profile switch <auth_profile> with the exact profile id. For one command, pass --profile <auth_profile>.',
371
+ next_step: 'Multiple auth profiles are available. Run openyida auth profiles, then run openyida auth profile switch <auth_profile> with the exact profile id. The switch updates the current project auth pointer.',
372
372
  next_step_commands: [
373
373
  'openyida auth profiles',
374
374
  'openyida auth profile switch <auth_profile>',
@@ -754,7 +754,7 @@ function selectUserProfileSession(options = {}, selection = {}) {
754
754
  status: 'profile_required',
755
755
  candidate_count: candidates.length,
756
756
  candidates: candidates.map(toAuthProfileCandidate),
757
- message: 'multiple auth profiles found; pass --corp-id, --profile, or OPENYIDA_AUTH_PROFILE',
757
+ message: 'multiple auth profiles found; switch the current project auth pointer with openyida auth profile switch <auth_profile>',
758
758
  ...buildAuthProfileNextStep('profile_required'),
759
759
  };
760
760
  }
@@ -37,6 +37,26 @@ function toErrorPayload(error) {
37
37
  if (details.nextStep) {
38
38
  payload.nextStep = details.nextStep;
39
39
  }
40
+ [
41
+ 'partial',
42
+ 'residual',
43
+ 'retryable',
44
+ 'retrySafe',
45
+ 'sideEffectState',
46
+ 'readbackAllowed',
47
+ 'recommendedRecovery',
48
+ 'nextAction',
49
+ 'target',
50
+ 'deleted',
51
+ 'alreadyAbsent',
52
+ 'mutationAccepted',
53
+ 'readbackVerified',
54
+ 'status',
55
+ ].forEach((key) => {
56
+ if (Object.prototype.hasOwnProperty.call(details, key)) {
57
+ payload[key] = details[key];
58
+ }
59
+ });
40
60
  }
41
61
  payload.details = details;
42
62
  }
@@ -44,8 +64,34 @@ function toErrorPayload(error) {
44
64
  return payload;
45
65
  }
46
66
 
67
+ function shouldUseStructuredErrorOutput(error, args = []) {
68
+ if (!isCliError(error)) {return false;}
69
+ if (Array.isArray(args) && args.includes('--json')) {return true;}
70
+ const details = error.details;
71
+ const ownedPartial = !!(
72
+ details
73
+ && typeof details === 'object'
74
+ && !Array.isArray(details)
75
+ && details.partial === true
76
+ && details.residual
77
+ && typeof details.residual === 'object'
78
+ && details.retrySafe === false
79
+ );
80
+ const mutationOutcomeUnknown = !!(
81
+ details
82
+ && typeof details === 'object'
83
+ && !Array.isArray(details)
84
+ && details.target
85
+ && typeof details.target === 'object'
86
+ && details.retrySafe === false
87
+ && details.sideEffectState === 'unknown'
88
+ );
89
+ return ownedPartial || mutationOutcomeUnknown;
90
+ }
91
+
47
92
  module.exports = {
48
93
  CliError,
49
94
  isCliError,
95
+ shouldUseStructuredErrorOutput,
50
96
  toErrorPayload,
51
97
  };
@@ -1168,9 +1168,10 @@ const COMMAND_GROUPS = [
1168
1168
  id: 'data',
1169
1169
  titleKey: 'help.group_data',
1170
1170
  commands: [
1171
- command('data', ['data'], 'data <query|get|create|update|delete> <form|process|subform|tasks|operation-records|task> [args]', 'help.cmd_data', {
1171
+ command('data', ['data'], 'data <query|get|create|update> <resource> ... | delete form <appType> <formUuid> --inst-id <id> --confirm [--json]', 'help.cmd_data', {
1172
1172
  examples: [
1173
1173
  'openyida data create form APP_XXX FORM_XXX --data-json \'{"textField_name":"客户 A","dateField_followUp":1787932800000}\'',
1174
+ 'openyida data delete form APP_XXX FORM_XXX --inst-id FINST_XXX --confirm --json',
1174
1175
  ],
1175
1176
  }),
1176
1177
  command('task-center', ['task-center'], 'task-center <type> [options]', 'help.cmd_task_center'),
@@ -1223,8 +1224,8 @@ const COMMAND_GROUPS = [
1223
1224
  id: 'report',
1224
1225
  titleKey: 'help.group_report',
1225
1226
  commands: [
1226
- command('create-report', ['create-report'], 'create-report <appType> "<name>" ... [--open|--no-open]', 'help.cmd_create_report'),
1227
- command('append-chart', ['append-chart'], 'append-chart <appType> <reportId> ... [--open|--no-open]', 'help.cmd_append_chart'),
1227
+ command('create-report', ['create-report'], 'create-report <appType> "<name>" ... [--json] [--open|--no-open]', 'help.cmd_create_report'),
1228
+ command('append-chart', ['append-chart'], 'append-chart <appType> <reportId> ... [--json] [--open|--no-open]', 'help.cmd_append_chart'),
1228
1229
  command('report.inspect', ['report', 'inspect'], 'report inspect <appType> <reportId> --json', 'help.cmd_report_inspect', { output: 'json' }),
1229
1230
  ],
1230
1231
  },
package/lib/core/copy.js CHANGED
@@ -23,6 +23,7 @@
23
23
  const fs = require('fs');
24
24
  const path = require('path');
25
25
  const os = require('os');
26
+ const { CliError } = require('./cli-error');
26
27
  const { detectEnvironment } = require('./env');
27
28
  const { buildSkillsDiagnostics, resolveProjectRoot } = require('./utils');
28
29
  const { t } = require('./i18n');
@@ -128,6 +129,55 @@ function resolveExistingPath(targetPath) {
128
129
  }
129
130
  }
130
131
 
132
+ function resolveCanonicalPath(targetPath) {
133
+ let current = path.resolve(targetPath);
134
+ const missingSegments = [];
135
+
136
+ while (!fs.existsSync(current)) {
137
+ const parent = path.dirname(current);
138
+ if (parent === current) {
139
+ break;
140
+ }
141
+ missingSegments.unshift(path.basename(current));
142
+ current = parent;
143
+ }
144
+
145
+ const existingBase = fs.existsSync(current) ? fs.realpathSync(current) : current;
146
+ return path.resolve(existingBase, ...missingSegments);
147
+ }
148
+
149
+ function isSameOrDescendantPath(candidatePath, parentPath) {
150
+ const relative = path.relative(parentPath, candidatePath);
151
+ return relative === '' || (
152
+ relative !== '..' &&
153
+ !relative.startsWith(`..${path.sep}`) &&
154
+ !path.isAbsolute(relative)
155
+ );
156
+ }
157
+
158
+ function assertCopyDestinationSafe(sourceDir, destDir) {
159
+ const sourcePath = resolveCanonicalPath(sourceDir);
160
+ const destinationPath = resolveCanonicalPath(destDir);
161
+ const destinationInsideSource = isSameOrDescendantPath(destinationPath, sourcePath);
162
+ const sourceInsideDestination = isSameOrDescendantPath(sourcePath, destinationPath);
163
+
164
+ if (!destinationInsideSource && !sourceInsideDestination) {
165
+ return;
166
+ }
167
+
168
+ throw new CliError(t('copy.source_destination_overlap', sourcePath, destinationPath), {
169
+ code: 'COPY_SOURCE_DESTINATION_OVERLAP',
170
+ details: {
171
+ sourcePath,
172
+ destinationPath,
173
+ relation: destinationInsideSource ? 'destination_inside_source' : 'source_inside_destination',
174
+ sideEffectState: 'none',
175
+ retryable: false,
176
+ retrySafe: true,
177
+ },
178
+ });
179
+ }
180
+
131
181
  function isSameDirectory(a, b) {
132
182
  const pathA = resolveExistingPath(a);
133
183
  const pathB = resolveExistingPath(b);
@@ -244,6 +294,7 @@ function resolveDestBaseFromEnv(activeToolName, activeProjectRoot, envResults, o
244
294
  * 执行单项复制任务,打印结果。
245
295
  */
246
296
  function copyItem(label, sourceDir, destDir, isForce, options = {}) {
297
+ assertCopyDestinationSafe(sourceDir, destDir);
247
298
  console.log(t('copy.copying_label', label));
248
299
  const count = isForce
249
300
  ? forceCopyDir(sourceDir, destDir, options)
@@ -256,6 +307,9 @@ function copyItem(label, sourceDir, destDir, isForce, options = {}) {
256
307
  * @param {string[]} [args=process.argv.slice(3)] 命令参数
257
308
  */
258
309
  function run(args = process.argv.slice(3)) {
310
+ if (args.includes('--help') || args.includes('-h')) {
311
+ return { help: true };
312
+ }
259
313
  const { c, sep, banner, info, success, label, fail: chalkFail, listItem } = require('./chalk');
260
314
 
261
315
  banner(t('copy.title'), { stderr: false });
@@ -339,6 +393,7 @@ function run(args = process.argv.slice(3)) {
339
393
  const selectedSkills = skillsDiagnostics.selected;
340
394
 
341
395
  if (selectedSkills && selectedSkills.path) {
396
+ assertCopyDestinationSafe(packageYidaSkillsDir, selectedSkills.path);
342
397
  // 清理旧版遗留在根目录的错误安装
343
398
  if (activeResult && selectedSkills.scope === 'user') {
344
399
  removeSkillsLink(path.join(os.homedir(), activeResult.dirName, 'yida-skills'));
@@ -359,6 +414,7 @@ function run(args = process.argv.slice(3)) {
359
414
  } else {
360
415
  // 未检测到 AI 工具,复制到当前目录下
361
416
  const destSkillsDest = path.join(destBase, 'yida-skills');
417
+ assertCopyDestinationSafe(packageYidaSkillsDir, destSkillsDest);
362
418
  removeSkillsLink(destSkillsDest);
363
419
  const count = mergeCopyDir(packageYidaSkillsDir, destSkillsDest);
364
420
  results.push({
@@ -397,6 +453,7 @@ function run(args = process.argv.slice(3)) {
397
453
  module.exports = {
398
454
  run,
399
455
  _internal: {
456
+ assertCopyDestinationSafe,
400
457
  forceCopyDir,
401
458
  ensureProjectWorkspaceDirs,
402
459
  resolveDestBaseFromEnv,
@@ -1199,6 +1199,7 @@ Examples:
1199
1199
  remove_failed: ' ❌ Remove failed: {0} ({1})',
1200
1200
  symlink_fallback_copy: ' ⚠️ Windows symlink creation failed (requires admin privileges), falling back to directory copy: {0}',
1201
1201
  symlink_failed: ' ❌ Symlink creation failed: {0} ({1})',
1202
+ source_destination_overlap: 'Copy stopped because the source and destination directories overlap. Source: {0}; destination: {1}',
1202
1203
  result_symlink: ' {0} → {1} (symlink)',
1203
1204
  result_copy: ' {0} → {1} ({2} files)',
1204
1205
  },
@@ -1843,6 +1844,14 @@ Options:
1843
1844
  };
1844
1845
 
1845
1846
  Object.assign(module.exports.query_data || (module.exports.query_data = {}), {
1847
+ command_unsupported: 'Unsupported data command: {0} {1}. Run openyida commands --json to inspect the actual capability.',
1848
+ delete_confirmation_required: 'Before deleting a form instance, query it, show the target summary to the user, and add --confirm only after explicit approval. No delete was performed.',
1849
+ delete_preflight_failed: 'Could not read form instance {0} for delete preflight. No delete was performed.',
1850
+ delete_process_unsupported: 'Deleting process instances is not supported in this version. Stop and report the capability gap; do not try scripts or private APIs.',
1851
+ delete_readback_mismatch: 'The delete request was accepted, but form instance {0} is still present on readback. The result is unverified; do not retry the delete automatically.',
1852
+ delete_result_unknown: 'The delete outcome for form instance {0} is unknown. Perform read-only inspection and do not retry the delete automatically.',
1853
+ delete_target_mismatch: 'Form instance {0} does not belong to target form {1}. The operation stopped before delete.',
1854
+ delete_target_unverified: 'Could not verify the identity and ownership of form instance {0}. The operation stopped before delete.',
1846
1855
  form_mode_unverified: 'Could not verify the type of form {0}. Creation stopped before any data write.',
1847
1856
  resource_required: 'data query is missing the form resource type. Suggested command: {0}',
1848
1857
  });
@@ -1172,6 +1172,7 @@ openyida - 宜搭命令行工具
1172
1172
  remove_failed: ' ❌ 删除失败: {0} ({1})',
1173
1173
  symlink_fallback_copy: ' ⚠️ Windows 软链创建失败(需要管理员权限),降级为目录复制: {0}',
1174
1174
  symlink_failed: ' ❌ 软链接创建失败: {0} ({1})',
1175
+ source_destination_overlap: '复制已停止:源目录与目标目录重叠。源目录:{0};目标目录:{1}',
1175
1176
  },
1176
1177
 
1177
1178
  // ── lib/check-update.js ────────────────────────────
@@ -1798,6 +1799,14 @@ openyida - 宜搭命令行工具
1798
1799
  };
1799
1800
 
1800
1801
  Object.assign(module.exports.query_data || (module.exports.query_data = {}), {
1802
+ command_unsupported: '不支持的数据命令:{0} {1}。请使用 openyida commands --json 查询真实能力。',
1803
+ delete_confirmation_required: '删除表单实例前必须先查询并向用户展示目标摘要,获得明确确认后追加 --confirm。未执行删除。',
1804
+ delete_preflight_failed: '无法读取表单实例 {0} 完成删除前校验,未执行删除。',
1805
+ delete_process_unsupported: '当前版本不支持删除流程实例。请停止并报告能力缺口,不要尝试脚本或底层 API。',
1806
+ delete_readback_mismatch: '删除请求已被接受,但回读仍能找到表单实例 {0}。结果未验证,禁止自动重试删除。',
1807
+ delete_result_unknown: '表单实例 {0} 的删除结果未知。请只读回查目标,不要自动重试删除。',
1808
+ delete_target_mismatch: '表单实例 {0} 不属于目标表单 {1},已停止且未执行删除。',
1809
+ delete_target_unverified: '无法验证表单实例 {0} 的身份和归属,已停止且未执行删除。',
1801
1810
  form_mode_unverified: '无法验证表单 {0} 的类型,已停止创建;未执行任何数据写入。',
1802
1811
  resource_required: 'data query 缺少资源类型 form。建议:{0}',
1803
1812
  });