openyida 2026.9.2 → 2026.9.3

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 (80) hide show
  1. package/README.md +9 -7
  2. package/lib/app/create-form/api-path.js +16 -2
  3. package/lib/app/create-form/args.js +14 -0
  4. package/lib/app/create-form/nav-icon-service.js +202 -0
  5. package/lib/app/create-form/nav-icon.js +267 -0
  6. package/lib/app/create-form.js +77 -3
  7. package/lib/app/nav-group.js +221 -53
  8. package/lib/app/page-template-guard.js +64 -0
  9. package/lib/app/publish.js +15 -1
  10. package/lib/app/services/canvas-page-schema-builder.js +1 -1
  11. package/lib/asset/ai-image.js +8 -9
  12. package/lib/asset/asset-cmd.js +3 -49
  13. package/lib/asset/asset-resolve.js +8 -10
  14. package/lib/asset/asset-status.js +7 -7
  15. package/lib/core/agent-capabilities.js +43 -1
  16. package/lib/core/cli-error.js +6 -1
  17. package/lib/core/command-contract.js +42 -1
  18. package/lib/core/command-manifest.js +73 -11
  19. package/lib/core/locales/en.js +5 -1
  20. package/lib/core/locales/zh.js +7 -3
  21. package/lib/core/query-data.js +126 -8
  22. package/lib/core/sample.js +51 -10
  23. package/lib/samples/openyida-scaffold/canvas-form-drawer.canvas.jsx +7 -7
  24. package/package.json +1 -1
  25. package/scripts/postinstall.js +5 -5
  26. package/yida-skills/SKILL.md +13 -13
  27. package/yida-skills/references/task-retrospective.md +4 -4
  28. package/yida-skills/skills/yida-app/SKILL.md +9 -8
  29. package/yida-skills/skills/yida-app/references/common-issues.md +1 -1
  30. package/yida-skills/skills/yida-app/workflow/step-2-design.md +42 -15
  31. package/yida-skills/skills/yida-app/workflow/step-3-create-or-reuse-app.md +8 -1
  32. package/yida-skills/skills/yida-app/workflow/step-4-forms-processes.md +13 -15
  33. package/yida-skills/skills/yida-app/workflow/step-7-page-code.md +4 -2
  34. package/yida-skills/skills/yida-app/workflow/step-8-publish-navigation.md +26 -11
  35. package/yida-skills/skills/yida-app/workflow/step-9-output-finish.md +22 -11
  36. package/yida-skills/skills/yida-canvas-custom-page/SKILL.md +8 -8
  37. package/yida-skills/skills/yida-canvas-custom-page/references/canvas-authoring-examples.md +1 -1
  38. package/yida-skills/skills/yida-canvas-custom-page/references/canvas-style-implementation-guide.md +16 -16
  39. package/yida-skills/skills/yida-canvas-custom-page/references/data-bridge-guide.md +1 -1
  40. package/yida-skills/skills/yida-canvas-custom-page/references/navigation-and-entry-guide.md +1 -1
  41. package/yida-skills/skills/yida-canvas-custom-page/references/page-generation-guide.md +6 -7
  42. package/yida-skills/skills/yida-canvas-table-form/SKILL.md +2 -2
  43. package/yida-skills/skills/yida-create-app/SKILL.md +13 -7
  44. package/yida-skills/skills/yida-create-form-page/SKILL.md +15 -17
  45. package/yida-skills/skills/yida-create-form-page/references/form-field-properties.md +1 -4
  46. package/yida-skills/skills/yida-custom-page/SKILL.md +5 -5
  47. package/yida-skills/skills/yida-custom-page/references/coding-guide.md +2 -6
  48. package/yida-skills/skills/yida-custom-page/references/design-system.md +4 -4
  49. package/yida-skills/skills/yida-data-management/SKILL.md +6 -4
  50. package/yida-skills/skills/yida-data-management/references/data-format-guide.md +13 -5
  51. package/yida-skills/skills/yida-design/SKILL.md +36 -39
  52. package/yida-skills/skills/yida-design/references/asset-workflow.md +32 -85
  53. package/yida-skills/skills/yida-design/references/page-quality-gates.md +3 -3
  54. package/yida-skills/skills/yida-design/references/style-design-selection.md +4 -4
  55. package/yida-skills/skills/yida-design/references/theme/app-custom-theme-template.css +15 -24
  56. package/yida-skills/skills/yida-design/references/theme/theme-token-presets.md +8 -8
  57. package/yida-skills/skills/yida-design/references/visual-decision-engine.md +1 -1
  58. package/yida-skills/skills/yida-design/references/visual-scaffold-recipes.md +2 -2
  59. package/yida-skills/skills/yida-design/sub_skill/page-design/SKILL.md +12 -13
  60. package/yida-skills/skills/yida-design/workflow/output-design.md +40 -26
  61. package/yida-skills/skills/yida-design/workflow/output-prd.md +8 -8
  62. package/yida-skills/skills/yida-design/workflow/step-1-read-brief.md +14 -0
  63. package/yida-skills/skills/yida-design/workflow/step-2-theme-system.md +23 -17
  64. package/yida-skills/skills/yida-design/workflow/step-4-wireframe-interaction.md +3 -3
  65. package/yida-skills/skills/yida-design/workflow/step-5-visual-states.md +5 -5
  66. package/yida-skills/skills/yida-design/workflow/step-6-handoff.md +22 -55
  67. package/yida-skills/skills/yida-nav-group/SKILL.md +3 -1
  68. package/yida-skills/skills/yida-page-config/SKILL.md +3 -1
  69. package/yida-skills/skills/yida-prd/SKILL.md +48 -0
  70. package/yida-skills/skills/yida-prd/references/app/blueprint.md +73 -0
  71. package/yida-skills/skills/yida-prd/references/app/navigation-patterns.md +43 -0
  72. package/yida-skills/skills/yida-prd/references/app/role-journey.md +30 -0
  73. package/yida-skills/skills/yida-prd/workflow/output-prd.md +188 -0
  74. package/yida-skills/skills/yida-prd/workflow/step-1-read-brief.md +15 -0
  75. package/yida-skills/skills/{yida-design/workflow/step-3-information-architecture.md → yida-prd/workflow/step-2-information-architecture.md} +2 -2
  76. package/yida-skills/skills/yida-publish-page/SKILL.md +1 -1
  77. package/yida-skills/skills/yida-requirement-analysis/SKILL.md +49 -0
  78. package/yida-skills/skills-index.json +36 -35
  79. package/yida-skills/skills/yida-design/workflow/step-1-positioning.md +0 -58
  80. package/yida-skills/skills/yida-form-detail/SKILL.md +0 -68
@@ -32,6 +32,7 @@ module.exports = {
32
32
  cmd_import: '导入迁移包,重建应用',
33
33
  group_form: '表单 & 页面',
34
34
  cmd_create_form: '创建表单页面',
35
+ cmd_list_form_icons: '列出可用的表单导航图标',
35
36
  cmd_validate_form: '本地校验表单字段 JSON',
36
37
  cmd_update_form: '更新表单页面',
37
38
  cmd_list_forms: '列出应用下的表单/页面',
@@ -102,7 +103,7 @@ module.exports = {
102
103
  cmd_a2a: '启动本地只读 A2A Adapter 或输出 Agent Card',
103
104
  cmd_bridge: '启动 OpenYida 本地网页桥接服务',
104
105
  cmd_copy: '复制 project 工作目录',
105
- cmd_sample: '输出代码示例/骨架',
106
+ cmd_sample: '输出代码模板',
106
107
  cmd_doctor: '环境诊断与自动修复',
107
108
  cmd_db_seq_fix: 'PostgreSQL Sequence 漂移检测与修复',
108
109
  cmd_formula_evaluate: '静态检查宜搭公式语法和字段引用',
@@ -112,7 +113,7 @@ module.exports = {
112
113
  cmd_batch: '批量执行 OpenYida 命令',
113
114
  cmd_flash_to_prd: '闪记 / 会议纪要转 PRD prompt',
114
115
  cmd_ai: '调用 AI 文生文和识图能力',
115
- cmd_asset: '检测素材能力 / 校验图片 URL / 解析回填素材',
116
+ cmd_asset: '检测素材能力 / 解析回填素材',
116
117
  cmd_cdn: 'CDN 图片管理(配置/上传/刷新)',
117
118
  cmd_cdn_config: '配置 CDN / OSS 上传',
118
119
  cmd_cdn_upload: '上传图片到 CDN',
@@ -136,7 +137,7 @@ openyida - 宜搭命令行工具
136
137
  copy [--force] 复制 project 工作目录到当前 AI 工具环境
137
138
  login OAuth token 登录态管理
138
139
  logout 退出登录 / 切换账号
139
- create-app --name "<名称>" [--theme-file <css> 及导航布局选项] 创建应用;推荐导入新版主题,输出 appType
140
+ create-app --name "<名称>" [--theme-file <css> 及导航布局选项] 创建应用;推荐导入应用主题文件,输出 appType
140
141
  create-page <appType> "<页面名>" [--mode dashboard] [--hide-nav] 创建自定义页面,输出 pageId
141
142
  update-app <appType> [--name "..."] [--hide-app-nav|--show-app-nav] 更新应用信息
142
143
  create-form create <appType> "<表单名>" <字段JSON> [--layout <布局>] [--theme <主题>] [--label-align <对齐>] 创建表单页面
@@ -1802,6 +1803,8 @@ openyida - 宜搭命令行工具
1802
1803
  };
1803
1804
 
1804
1805
  Object.assign(module.exports.query_data || (module.exports.query_data = {}), {
1806
+ association_derived_field_read_only: '关联表单查询派生字段 {0} 只读,不能用于保存或更新。请写入不带 _id 后缀的原始关联表单字段。',
1807
+ association_value_invalid: '关联表单字段 {0} 的写入值无效。必须使用对象数组,每项完整包含 appType、formUuid、formType、instanceId 和 title。',
1805
1808
  command_unsupported: '不支持的数据命令:{0} {1}。请使用 openyida commands --json 查询真实能力。',
1806
1809
  delete_confirmation_required: '删除表单实例前必须先查询并向用户展示目标摘要,获得明确确认后追加 --confirm。未执行删除。',
1807
1810
  delete_preflight_failed: '无法读取表单实例 {0} 完成删除前校验,未执行删除。',
@@ -1810,6 +1813,7 @@ Object.assign(module.exports.query_data || (module.exports.query_data = {}), {
1810
1813
  delete_result_unknown: '表单实例 {0} 的删除结果未知。请只读回查目标,不要自动重试删除。',
1811
1814
  delete_target_mismatch: '表单实例 {0} 不属于目标表单 {1},已停止且未执行删除。',
1812
1815
  delete_target_unverified: '无法验证表单实例 {0} 的身份和归属,已停止且未执行删除。',
1816
+ field_reference_unknown: '字段引用 {0} 不是当前表单的真实 fieldId 或组件别名,已在写入前停止。',
1813
1817
  form_mode_unverified: '无法验证表单 {0} 的类型,已停止创建;未执行任何数据写入。',
1814
1818
  instance_target_mismatch: '实例 {0} 不属于期望的业务资源 {1},已在写入前停止。',
1815
1819
  instance_target_unverified: '无法验证实例 {0} 的业务资源归属,已在写入前停止。',
@@ -334,6 +334,90 @@ function isPlainObject(value) {
334
334
  return Object.prototype.toString.call(value) === '[object Object]';
335
335
  }
336
336
 
337
+ const ASSOCIATION_FORM_FIELD_PREFIX = 'associationFormField_';
338
+ const ASSOCIATION_FORM_DERIVED_ID_RE = /^associationFormField_.+_id$/;
339
+ const ASSOCIATION_FORM_REQUIRED_KEYS = [
340
+ 'appType',
341
+ 'formUuid',
342
+ 'formType',
343
+ 'instanceId',
344
+ 'title',
345
+ ];
346
+
347
+ function isAssociationFormField(fieldId, aliasContext) {
348
+ const fieldInfo = aliasContext && aliasContext.fieldInfoById[fieldId];
349
+ return fieldId.startsWith(ASSOCIATION_FORM_FIELD_PREFIX)
350
+ || (fieldInfo && fieldInfo.componentName === 'AssociationFormField');
351
+ }
352
+
353
+ function throwAssociationFormValueInvalid(fieldId, index, reason, missingFields = []) {
354
+ dataError(
355
+ 'DATA_ASSOCIATION_FORM_VALUE_INVALID',
356
+ t('query_data.association_value_invalid', fieldId),
357
+ {
358
+ fieldId,
359
+ index,
360
+ reason,
361
+ missingFields,
362
+ retryable: false,
363
+ retrySafe: true,
364
+ sideEffectState: 'none',
365
+ nextStep: 'provide_complete_association_form_value',
366
+ }
367
+ );
368
+ }
369
+
370
+ function normalizeAssociationFormFields(data, aliasContext) {
371
+ if (!isPlainObject(data)) {
372
+ return data;
373
+ }
374
+
375
+ const normalized = {};
376
+ Object.entries(data).forEach(([fieldId, value]) => {
377
+ if (ASSOCIATION_FORM_DERIVED_ID_RE.test(fieldId)) {
378
+ dataError(
379
+ 'DATA_ASSOCIATION_FORM_DERIVED_FIELD_READ_ONLY',
380
+ t('query_data.association_derived_field_read_only', fieldId),
381
+ {
382
+ fieldId,
383
+ retryable: false,
384
+ retrySafe: true,
385
+ sideEffectState: 'none',
386
+ nextStep: 'write_the_source_association_form_field',
387
+ }
388
+ );
389
+ }
390
+
391
+ if (!isAssociationFormField(fieldId, aliasContext)) {
392
+ normalized[fieldId] = value;
393
+ return;
394
+ }
395
+ if (!Array.isArray(value)) {
396
+ throwAssociationFormValueInvalid(fieldId, null, 'value_must_be_array');
397
+ }
398
+
399
+ normalized[fieldId] = value.map((item, index) => {
400
+ if (!isPlainObject(item)) {
401
+ throwAssociationFormValueInvalid(fieldId, index, 'item_must_be_object');
402
+ }
403
+ const missingFields = ASSOCIATION_FORM_REQUIRED_KEYS.filter((key) => (
404
+ typeof item[key] !== 'string' || item[key].trim() === ''
405
+ ));
406
+ if (missingFields.length > 0) {
407
+ throwAssociationFormValueInvalid(fieldId, index, 'required_fields_missing', missingFields);
408
+ }
409
+ if (item.subTitle !== undefined && typeof item.subTitle !== 'string') {
410
+ throwAssociationFormValueInvalid(fieldId, index, 'subtitle_must_be_string');
411
+ }
412
+ return {
413
+ ...item,
414
+ subTitle: item.subTitle === undefined ? '' : item.subTitle,
415
+ };
416
+ });
417
+ });
418
+ return normalized;
419
+ }
420
+
337
421
  function buildFieldInfoById(schemaResult) {
338
422
  const fieldInfoById = {};
339
423
  const pages = schemaResult && schemaResult.content && schemaResult.content.pages;
@@ -373,6 +457,8 @@ async function fetchFormAliasContext(session, appType, formUuid) {
373
457
  return {
374
458
  ...buildComponentAliasMaps(result),
375
459
  fieldInfoById: buildFieldInfoById(result),
460
+ appType,
461
+ formUuid,
376
462
  };
377
463
  }
378
464
 
@@ -393,6 +479,24 @@ function resolveFieldRef(value, aliasContext) {
393
479
  return aliasContext.fieldIdByAlias[value] || value;
394
480
  }
395
481
 
482
+ function requireKnownDataFieldRef(value, aliasContext) {
483
+ const fieldId = resolveFieldRef(value, aliasContext);
484
+ if (!aliasContext || aliasContext.fieldInfoById[fieldId]) {
485
+ return fieldId;
486
+ }
487
+ dataError(
488
+ 'DATA_FIELD_REFERENCE_UNKNOWN',
489
+ t('query_data.field_reference_unknown', value),
490
+ {
491
+ fieldRef: value,
492
+ retryable: false,
493
+ retrySafe: true,
494
+ sideEffectState: 'none',
495
+ nextStep: `openyida get-schema ${aliasContext.appType} ${aliasContext.formUuid} --field-map-json`,
496
+ }
497
+ );
498
+ }
499
+
396
500
  function translateSubformRows(value, aliasContext) {
397
501
  if (!Array.isArray(value)) {
398
502
  return value;
@@ -411,7 +515,7 @@ function translateFormDataObject(data, aliasContext) {
411
515
  }
412
516
  const translated = {};
413
517
  Object.entries(data).forEach(([key, value]) => {
414
- const fieldId = resolveFieldRef(key, aliasContext);
518
+ const fieldId = requireKnownDataFieldRef(key, aliasContext);
415
519
  const fieldInfo = aliasContext && aliasContext.fieldInfoById[fieldId];
416
520
  translated[fieldId] = fieldInfo && fieldInfo.componentName === 'TableField'
417
521
  ? translateSubformRows(value, aliasContext)
@@ -444,12 +548,26 @@ function translateJsonWithAliases(jsonValue, aliasContext, translator) {
444
548
  if (!aliasContext || !jsonValue) {
445
549
  return jsonValue;
446
550
  }
551
+ let parsed;
447
552
  try {
448
- return JSON.stringify(translator(JSON.parse(jsonValue), aliasContext));
553
+ parsed = JSON.parse(jsonValue);
449
554
  } catch (err) {
450
555
  parseError(`--resolve-aliases 只能处理合法 JSON:${err.message}`);
451
556
  }
452
- return jsonValue;
557
+ return JSON.stringify(translator(parsed, aliasContext));
558
+ }
559
+
560
+ function prepareFormMutationJson(jsonValue, aliasContext) {
561
+ let data;
562
+ try {
563
+ data = JSON.parse(jsonValue);
564
+ } catch (err) {
565
+ parseError(`--data-json 只能处理合法 JSON:${err.message}`);
566
+ }
567
+ const translated = aliasContext
568
+ ? translateFormDataObject(data, aliasContext)
569
+ : data;
570
+ return JSON.stringify(normalizeAssociationFormFields(translated, aliasContext));
453
571
  }
454
572
 
455
573
  /**
@@ -923,7 +1041,7 @@ async function createForm(positionals, options, session) {
923
1041
  const params = {
924
1042
  appType,
925
1043
  formUuid,
926
- formDataJson: translateJsonWithAliases(dataJson, aliasContext, translateFormDataObject),
1044
+ formDataJson: prepareFormMutationJson(dataJson, aliasContext),
927
1045
  };
928
1046
  if (options.dept_id) {params.deptId = options.dept_id;}
929
1047
 
@@ -964,7 +1082,7 @@ async function updateForm(positionals, options, session) {
964
1082
  const aliasContext = await resolveAliasContextIfNeeded(session, appType, options.form_uuid, options, dataJson);
965
1083
  const params = {
966
1084
  formInstId: options.inst_id,
967
- updateFormDataJson: translateJsonWithAliases(dataJson, aliasContext, translateFormDataObject),
1085
+ updateFormDataJson: prepareFormMutationJson(dataJson, aliasContext),
968
1086
  };
969
1087
  if (options.use_latest_version) {params.useLatestVersion = options.use_latest_version;}
970
1088
  printResult(await sendPostOnce(session, appType, `/dingtalk/web/${appType}/v1/form/updateFormData.json`, params));
@@ -1233,7 +1351,7 @@ async function createProcess(positionals, options, session) {
1233
1351
  const params = {
1234
1352
  processCode: options.process_code,
1235
1353
  formUuid,
1236
- formDataJson: translateJsonWithAliases(dataJson, aliasContext, translateFormDataObject),
1354
+ formDataJson: prepareFormMutationJson(dataJson, aliasContext),
1237
1355
  };
1238
1356
  if (options.dept_id) {params.deptId = options.dept_id;}
1239
1357
  printCreateResult(
@@ -1259,7 +1377,7 @@ async function updateProcess(positionals, options, session) {
1259
1377
  const aliasContext = await resolveAliasContextIfNeeded(session, appType, options.form_uuid, options, dataJson);
1260
1378
  printResult(await sendPostOnce(session, appType, `/dingtalk/web/${appType}/v1/process/updateInstance.json`, {
1261
1379
  processInstanceId: options.process_inst_id,
1262
- updateFormDataJson: translateJsonWithAliases(dataJson, aliasContext, translateFormDataObject),
1380
+ updateFormDataJson: prepareFormMutationJson(dataJson, aliasContext),
1263
1381
  }));
1264
1382
  }
1265
1383
 
@@ -1294,7 +1412,7 @@ async function executeTask(positionals, options, session) {
1294
1412
  };
1295
1413
  const dataJson = readJsonOption(options, 'data_json', 'data_file', '数据');
1296
1414
  const aliasContext = await resolveAliasContextIfNeeded(session, appType, options.form_uuid, options, dataJson);
1297
- if (dataJson) {params.formDataJson = translateJsonWithAliases(dataJson, aliasContext, translateFormDataObject);}
1415
+ if (dataJson) {params.formDataJson = prepareFormMutationJson(dataJson, aliasContext);}
1298
1416
  if (options.no_execute_expressions) {params.noExecuteExpressions = options.no_execute_expressions;}
1299
1417
  printResult(await sendPostOnce(session, appType, `/dingtalk/web/${appType}/v1/task/executeTask.json`, params));
1300
1418
  }
@@ -44,25 +44,60 @@ const SAMPLES = {
44
44
  'yida-canvas-table-form': {
45
45
  'table-form-batch-submit': 'table-form-batch-submit.canvas.jsx',
46
46
  },
47
- 'openyida-scaffold': {
47
+ 'openyida-page-template': {
48
48
  'form-fields': 'form-fields.json',
49
49
  'canvas-form-drawer': 'canvas-form-drawer.canvas.jsx',
50
50
  },
51
+ 'yida-design': {
52
+ 'app-theme': 'app-custom-theme-template.css',
53
+ },
51
54
  'yida-table-form': {
52
55
  'table-form-batch-submit': 'table-form-batch-submit.js',
53
56
  },
54
57
  };
55
58
 
59
+ const SAMPLE_SOURCE_DIRECTORIES = {
60
+ 'openyida-page-template': 'openyida-scaffold',
61
+ };
62
+
63
+ const SAMPLE_SOURCE_FILES = {
64
+ 'yida-design/app-theme': path.join(
65
+ __dirname,
66
+ '..',
67
+ '..',
68
+ 'yida-skills',
69
+ 'skills',
70
+ 'yida-design',
71
+ 'references',
72
+ 'theme',
73
+ 'app-custom-theme-template.css'
74
+ ),
75
+ };
76
+
77
+ const SAMPLE_OUTPUT_FILENAMES = {
78
+ 'yida-design/app-theme': 'app-theme.css',
79
+ };
80
+
81
+ const SAMPLE_HINTS = {
82
+ 'yida-design/app-theme': '已复制应用主题模板;请由 yida-design 按 design.md 定点修改需要变化的 token。',
83
+ };
84
+
56
85
  // ── 工具函数 ──────────────────────────────────────────────────────────
57
86
 
58
87
  /**
59
88
  * 解析 sample 文件在 npm 包中的绝对路径
60
89
  * @param {string} skill
90
+ * @param {string} name
61
91
  * @param {string} filename
62
92
  * @returns {string}
63
93
  */
64
- function resolveSampleSourcePath(skill, filename) {
65
- return path.join(__dirname, '..', 'samples', skill, filename);
94
+ function resolveSampleSourcePath(skill, name, filename) {
95
+ const sourceFile = SAMPLE_SOURCE_FILES[`${skill}/${name}`];
96
+ if (sourceFile) {
97
+ return sourceFile;
98
+ }
99
+ const sourceDirectory = SAMPLE_SOURCE_DIRECTORIES[skill] || skill;
100
+ return path.join(__dirname, '..', 'samples', sourceDirectory, filename);
66
101
  }
67
102
 
68
103
  /**
@@ -175,23 +210,29 @@ async function run(args) {
175
210
  }
176
211
 
177
212
  // 解析源文件路径
178
- const sourcePath = resolveSampleSourcePath(skill, filename);
213
+ const sampleKey = `${skill}/${name}`;
214
+ const sourcePath = resolveSampleSourcePath(skill, name, filename);
179
215
  if (!fs.existsSync(sourcePath)) {
180
216
  chalkError(`sample 文件不存在:${sourcePath}`, { hint: '请确认 openyida 已正确安装(npm install -g openyida@latest)' });
181
217
  }
182
218
 
183
219
  // 解析输出路径与模板变量
184
- const defaultOutputPath = path.join(process.cwd(), '.cache', 'samples', filename);
220
+ const outputFilename = SAMPLE_OUTPUT_FILENAMES[sampleKey] || filename;
221
+ const defaultOutputPath = path.join(process.cwd(), '.cache', 'samples', outputFilename);
185
222
  const { outputPath, variables } = parseOptions(rest, defaultOutputPath);
186
223
 
187
224
  // 写入文件
188
225
  ensureDirectoryExists(outputPath);
189
- const sourceContent = fs.readFileSync(sourcePath, 'utf-8');
190
- const outputContent = applyTemplateVariables(sourceContent, variables);
191
- fs.writeFileSync(outputPath, outputContent, 'utf-8');
226
+ if (Object.keys(variables).length === 0) {
227
+ fs.copyFileSync(sourcePath, outputPath);
228
+ } else {
229
+ const sourceContent = fs.readFileSync(sourcePath, 'utf-8');
230
+ const outputContent = applyTemplateVariables(sourceContent, variables);
231
+ fs.writeFileSync(outputPath, outputContent, 'utf-8');
232
+ }
192
233
 
193
- chalkSuccess(`sample 已输出到:${c.cyan}${outputPath}${c.reset}`);
194
- chalkHint('使用 read_file 读取该文件作为代码模板参考。可通过 --var KEY=VALUE 替换 {{KEY}} 模板变量。');
234
+ chalkSuccess(`模板文件已复制到:${c.cyan}${outputPath}${c.reset}`);
235
+ chalkHint(SAMPLE_HINTS[sampleKey] || '请读取文件并按当前业务需求修改;发布前移除模板标记、示例数据和占位文案。');
195
236
  }
196
237
 
197
238
  module.exports = { run, applyTemplateVariables, parseOptions };
@@ -1,15 +1,15 @@
1
1
  /**
2
- * OpenYida Code Canvas 表单入口脚手架。
2
+ * @openyida-page-template-base
3
+ * OpenYida Code Canvas 表单入口基准模板。
3
4
  *
4
- * 使用方式:
5
- * openyida sample openyida-scaffold canvas-form-drawer --output project/pages/src/customer-entry.canvas.jsx --var APP_TYPE=APP_XXX --var FORM_UUID=FORM_XXX
5
+ * 内部生成流程必须先复制本文件,再按 PRD、design.md 和真实数据契约改写。
6
+ * 发布前必须删除本标记、示例数据和全部占位内容。
6
7
  *
7
8
  * 关键约定:
8
9
  * - PC 端新增和详情使用 FormOpenContainer 右侧抽屉 iframe。
9
10
  * - 移动端才整页进入原生提交页或详情页。
10
11
  * - 详情页必须先解析真实 formInstId,缺少实例 ID 时禁用入口。
11
12
  * - 预览行不携带伪造 formInstId,接入 searchFormDatas 真实 rows 后才启用详情。
12
- * - 提交页和详情页由新版主题运行时自行加载应用级自定义主题 CSS。
13
13
  */
14
14
 
15
15
  import React, { useMemo, useState } from 'react';
@@ -347,7 +347,7 @@ function YidaComp(props) {
347
347
  <Text type="secondary">原生表单负责提交和详情,自定义页负责列表、筛选与当前页面交互。</Text>
348
348
  </div>
349
349
  <Space wrap>
350
- <Tag color={isBound ? 'success' : 'warning'}>{isBound ? '已绑定真实表单' : '脚手架预览'}</Tag>
350
+ <Tag color={isBound ? 'success' : 'warning'}>{isBound ? '数据源已配置' : '数据源待配置'}</Tag>
351
351
  <Tag>{rows.length} 条记录</Tag>
352
352
  </Space>
353
353
  </div>
@@ -357,8 +357,8 @@ function YidaComp(props) {
357
357
  type="warning"
358
358
  showIcon
359
359
  style={{ marginBottom: 12 }}
360
- message="当前仍是脚手架占位资源"
361
- description="请通过 --var APP_TYPE=... --var FORM_UUID=... 替换模板变量,或在运行时 props 中传入 appType、formUuid 和 rows。"
360
+ message="页面数据尚未配置"
361
+ description="请先完成应用与表单绑定,并接入真实业务数据。"
362
362
  />
363
363
  ) : null}
364
364
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openyida",
3
- "version": "2026.9.2",
3
+ "version": "2026.9.3",
4
4
  "description": "OpenYida CLI - 宜搭低代码 AI 开发工具(安装即用,零配置)",
5
5
  "bin": {
6
6
  "openyida": "bin/yida.js",
@@ -285,9 +285,9 @@ openyida copy
285
285
 
286
286
  用户说“按默认方案 / 不要追问 / 直接创建 / 尽快搭建”时,加载 \`yida-app\` 走完整应用统一编排。
287
287
 
288
- 统一编排只做:解析资源上下文 → \`yida-design\` 输出 \`prd.md\` 和 \`design.md\` → 创建/复用应用 → 核心表单/流程 → 主页面 → 编写主页面源码 → 发布 + 轻量导航排序 → 返回 2-3 句业务交付总结和一个主入口链接。资源创建顺序按 PRD 执行:应用先落位,表单/流程先于自定义页面。发布主页面成功后,PRD 写明导航顺序时执行 \`openyida nav-group order <appType> <页面/表单...>\`;PRD 只写宽泛分组或缺少导航顺序时,执行 \`openyida publish ... --auto-nav-order\` 或 \`openyida nav-group auto-order <appType>\` 兜底,兜底顺序为门户/首页/工作台入口、业务办理、数据管理、经营分析、系统配置。
288
+ 统一编排只做:解析资源上下文并生成共享需求简报 → 并行调用 \`yida-prd\` 输出 \`prd.md\`、\`yida-design\` 输出 \`design.md\` → 由 \`yida-app\` join 两份产物 → 创建/复用应用 → 核心表单/流程 → 主页面 → 编写主页面源码 → 发布 + 轻量导航排序 → 返回 2-3 句业务交付总结和一个主入口链接。资源创建顺序按 PRD 执行:应用先落位,表单/流程先于自定义页面。发布主页面成功后,PRD 写明导航顺序时执行 \`openyida nav-group order <appType> <页面/表单...>\`;PRD 只写宽泛分组或缺少导航顺序时,执行 \`openyida publish ... --auto-nav-order\` 或 \`openyida nav-group auto-order <appType>\` 兜底,兜底顺序为门户/首页/工作台入口、业务办理、数据管理、经营分析、系统配置。
289
289
 
290
- 表单页开发默认加载 \`yida-form-detail\` 做表单视觉引导,并把 Divider 分割线语义分组合并进字段 JSON。运行容器在自定义页面、表单、提交页、详情页和 \`FormOpenContainer\` iframe 中加载同一应用级自定义主题 CSS,确保主题变量一致。
290
+ 应用主题只在应用级统一配置。严禁页面代码向原生表单、详情页、父页面或平台容器写入主题样式;\`YidaCodeCanvas\` 页面只在 \`YidaComp\` 内消费现有主题 token。字段结构统一交给 \`yida-create-form-page\`。
291
291
 
292
292
  完整应用页面源码默认不得使用 \`this.dataSourceMap.*\`,除非本轮已经明确创建并绑定设计器数据源;默认使用入口型页面或 \`this.utils.yida.*\` 查询已创建表单。
293
293
 
@@ -297,7 +297,7 @@ openyida copy
297
297
 
298
298
  使用 \`YidaCodeCanvas\` 组件实现的自定义页面统一直接写最终 \`.canvas.jsx\`:先读 PRD 的页面场景、业务区块、数据来源和主操作,再读 design.md 的主题、布局、材质、组件和状态规则,然后用 \`compileCanvasLocal\` 快检或 \`openyida publish\` 的编译阶段验证发布。\`openyida check-page\` / \`openyida compile\` 只用于历史平台 JSX 组件页面维护。
299
299
 
300
- 完整应用需求分析和产品设计由 \`yida-design\` 承担,并输出两份文件:\`prd/<项目名>/prd.md\` 写业务目标、数据结构、页面与功能、资源顺序、导航顺序和验收标准;\`prd/<项目名>/design.md\` 写主题色、themeProfile、tokens、视觉系统、组件和状态规则。页面实现先读 PRD 的页面场景、页面区块、数据来源、主操作和表单入口,再读 design.md 的主题、布局、材质、组件和状态规则,然后交给 \`yida-canvas-custom-page\` 落地。只有已识别为历史平台 JSX 组件页面维护时,才由 \`yida-custom-page\` 自身闭环处理。
300
+ 完整应用先由 \`yida-requirement-analysis\` 生成共享需求简报,再并行执行两个独立 artifact:\`yida-prd\` 写 \`prd/<项目名>/prd.md\`,负责业务目标、数据结构、页面与功能、资源顺序、导航顺序和验收标准;\`yida-design\` 写 \`prd/<项目名>/design.md\`,负责主题色、themeProfile、tokens、视觉系统、组件和状态规则。\`yida-app\` 必须等待两份产物完成并通过 join 后才能创建业务资源。页面实现先读 PRD 的页面场景、页面区块、数据来源、主操作和表单入口,再读 design.md 的主题、布局、材质、组件和状态规则,然后交给 \`yida-canvas-custom-page\` 落地。只有已识别为历史平台 JSX 组件页面维护时,才由 \`yida-custom-page\` 自身闭环处理。
301
301
 
302
302
  默认只加载当前阶段必需技能;示例数据、精细导航分组、截图验收、公开访问、数据源深接、数据管理和原生报表只在用户明确要求或 PRD 验收标准命中时执行。发布后的轻量导航排序是统一编排默认收尾,不等于精细导航分组。
303
303
 
@@ -309,8 +309,8 @@ openyida copy
309
309
  | --- | --- | --- |
310
310
  | \`yida-skills/context\` | 登录、退出、组织信息、Schema、fieldId、只读预检 | \`yida-login\`, \`yida-logout\`, \`yida-basic-info\`, \`yida-get-schema\`, \`yida-corp-efficiency\` |
311
311
  | \`yida-skills/app\` | 从零搭应用、导航、多语言 | \`yida-app\`, \`yida-create-app\`, \`yida-nav-group\`, \`yida-i18n\` |
312
- | \`yida-skills/design\` | 完整应用产品设计、单页 UI 改造、主页面视觉设计、应用主题色、全局换肤、PRD 和 design.md | \`yida-design\` |
313
- | \`yida-skills/form\` | 表单字段、公式、校验、业务规则、详情页、批量录入、数据记录 | \`yida-create-form-page\`, \`yida-formula\`, \`yida-formula-evaluate\`, \`yida-business-rule\`, \`yida-form-detail\`, \`yida-canvas-table-form\`, \`yida-table-form\`, \`yida-data-management\` |
312
+ | \`yida-skills/design\` | 完整应用需求简报、产品 PRD、单页 UI 改造、主页面视觉设计、应用主题色、全局换肤 | \`yida-requirement-analysis\`, \`yida-prd\`, \`yida-design\` |
313
+ | \`yida-skills/form\` | 表单字段、公式、校验、业务规则、批量录入、数据记录 | \`yida-create-form-page\`, \`yida-formula\`, \`yida-formula-evaluate\`, \`yida-business-rule\`, \`yida-canvas-table-form\`, \`yida-table-form\`, \`yida-data-management\` |
314
314
  | \`yida-skills/process\` | 审批、流程表单、流程规则、代理人 | \`yida-create-process\`, \`yida-process-rule\`, \`yida-agent-center\` |
315
315
  | \`yida-skills/page\` | 自定义展示页、YidaCodeCanvas 组件、历史平台 JSX 组件页面维护、发布、导航壳、PPT | \`yida-create-page\`, \`yida-canvas-custom-page\`, \`yida-custom-page\`, \`yida-canvas-data-binding\`, \`yida-canvas-upgrade\`, \`yida-publish-page\`, \`yida-openyida-publish-guard\`, \`yida-density\`, \`yida-nav-shell\`, \`yida-ppt-slider\` |
316
316
  | \`yida-skills/analytics\` | 报表、统计、图表、Recharts、ECharts、看板、驾驶舱 | \`yida-report\`, \`yida-rechart\`, \`yida-chart\`, \`yida-dashboard\` |
@@ -2,7 +2,7 @@
2
2
  name: openyida
3
3
  description: >
4
4
  宜搭应用开发总入口技能。通过具备代码生成能力的智能体(千问办公/Claude/Open Code 等)+ 宜搭低代码平台,实现一句话搭建或修改完整应用。
5
- 当用户提到“宜搭”、“yida”、“低代码”、“创建应用”、“创建表单”、“发布页面”、“自定义页面脚手架”、“搭建”、“系统”等关键词时,使用此技能;只是讨论通用前端/后端代码、非宜搭平台产品、或只解释概念而不操作宜搭资源时不触发。
5
+ 当用户提到“宜搭”、“yida”、“低代码”、“创建应用”、“创建表单”、“发布页面”、“自定义页面模板”、“搭建”、“系统”等关键词时,使用此技能;只是讨论通用前端/后端代码、非宜搭平台产品、或只解释概念而不操作宜搭资源时不触发。
6
6
  重要路由规则:完整应用/系统/平台的从零搭建、已有 app 但没有任何页面、或已有 app/page 需要补成完整业务系统时,必须先加载 yida-app 子技能作为编排入口。已有资源的单点改字段、改页面、发布、权限或数据任务按对应子技能路由。
7
7
  ---
8
8
 
@@ -70,8 +70,8 @@ description: >
70
70
  | --- | --- | --- |
71
71
  | `yida-skills/context` | 登录、退出、切换组织、组织版本/容量、Schema、fieldId、执行前检查 | `yida-login`、`yida-logout`、`yida-basic-info`、`yida-get-schema`、`yida-corp-efficiency` |
72
72
  | `yida-skills/app` | 从零搭应用、完整系统、应用启停、应用导航、多语言 | `yida-app`、`yida-create-app`、`yida-app-lifecycle`、`yida-nav-group`、`yida-i18n` |
73
- | `yida-skills/design` | 完整应用产品设计、单页 UI 改造、主页面视觉设计、应用主题色、全局换肤、PRD 和 design.md | `yida-design` |
74
- | `yida-skills/form` | 表单字段、公式、校验、业务关联规则、详情页、批量录入、数据记录 | `yida-create-form-page`、`yida-formula`、`yida-formula-evaluate`、`yida-business-rule`、`yida-form-detail`、`yida-canvas-table-form`、`yida-table-form`、`yida-data-management` |
73
+ | `yida-skills/design` | 完整应用需求简报、PRD、视觉设计、单页 UI 改造、应用主题色、全局换肤 | `yida-requirement-analysis`、`yida-prd`、`yida-design` |
74
+ | `yida-skills/form` | 表单字段、公式、校验、业务关联规则、批量录入、数据记录 | `yida-create-form-page`、`yida-formula`、`yida-formula-evaluate`、`yida-business-rule`、`yida-canvas-table-form`、`yida-table-form`、`yida-data-management` |
75
75
  | `yida-skills/process` | 审批、流程表单、流程规则、节点/分支/字段权限、流程代理 | `yida-create-process`、`yida-process-rule`、`yida-agent-center` |
76
76
  | `yida-skills/page` | 自定义展示页、页面源码开发、平台 JSX 组件页面维护、页面发布、页面内导航、PPT 页面 | `yida-create-page`、`yida-canvas-custom-page`、`yida-custom-page`、`yida-canvas-data-binding`、`yida-canvas-upgrade`、`yida-publish-page`、`yida-openyida-publish-guard`、`yida-density`、`yida-nav-shell`、`yida-ppt-slider` |
77
77
  | `yida-skills/analytics` | 聚合表、虚拟视图、报表、统计、图表、Recharts、ECharts、看板、驾驶舱、大屏 | `yida-aggregate-table`、`yida-report`、`yida-rechart`、`yida-chart`、`yida-dashboard` |
@@ -84,16 +84,16 @@ description: >
84
84
 
85
85
  | 用户意图 | 选哪个 |
86
86
  | --- | --- |
87
- | 从零搭一个完整应用/系统 | `yida-app`;统一编排,先由 `yida-design` 完成产品设计 |
87
+ | 从零搭一个完整应用/系统 | `yida-app`;统一编排,先生成共享需求简报,再并行生成 `prd.md` 与 `design.md` 并 join |
88
88
  | 已有 app 但没有任何页面,需要补成完整系统 | `yida-app`;复用已有 `appType`,按 PRD 补齐表单、流程、页面(如需要)和导航 |
89
89
  | 读取钉钉在线文档正文 | `yida-document-markdown`,使用登录态接口获取 Markdown |
90
90
  | 按 taskUuid 读取钉钉听记 | `yida-tingji`,将听记任务 ID 原样传入命令 |
91
91
  | 用户给 taskUuid 并要求转 PRD | 先用 `yida-tingji` 读取听记内容,再把已有内容交给 `yida-flash-note-to-prd` 生成 PRD |
92
92
  | 已有会议纪要/闪记内容转 PRD | `yida-flash-note-to-prd`,只处理已有内容,不负责按 taskUuid 拉取听记 |
93
- | 只创建应用壳并拿 appType | `yida-create-app`;创建成功后把真实 `appType` 交给 `yida-design` 生成或更新 `prd/<项目名>/prd.md` 和 `prd/<项目名>/design.md`,后续表单、流程、页面和发布都消费这两份文件 |
93
+ | 只创建应用壳并拿 appType | `yida-create-app`;若随后继续完整搭建,已 join 的共享需求简报、`prd.md` 与 `design.md` 保持冻结,真实 `appType` 只写入 schema 或当前任务资源上下文 |
94
94
  | 启用/上线或停用/下线已有应用 | `yida-app-lifecycle`;只有用户明确要求时执行,`app-offline` 执行前需再次确认目标应用 |
95
95
  | 创建自定义展示页资源 | `yida-create-page`,之后交给 `yida-canvas-custom-page` 编写页面源码,再交给 `yida-publish-page` 发布 |
96
- | 开发表单字段结构 / 增删改字段 | 先加载 `yida-form-detail` 做表单视觉引导并合并 Divider 分割线,再用 `yida-create-form-page` 落地字段结构 |
96
+ | 开发表单字段结构 / 增删改字段 | 使用 `yida-create-form-page` 落地字段结构 |
97
97
  | 创建带审批的流程表单 | `yida-create-process` |
98
98
  | 修改已有流程节点/分支/字段权限 | `yida-process-rule` |
99
99
  | 查字段 ID / 保存 Schema 证据 | `yida-get-schema`;凡涉及 fieldId 的数据、流程、公式、页面代码先取证 |
@@ -108,8 +108,8 @@ description: >
108
108
  | 高级图表、可视化、看板图表 | 默认 `yida-rechart` |
109
109
  | 明确 ECharts、维护旧 ECharts 页面、复杂 option 超出 Recharts 能力 | `yida-chart` |
110
110
  | 产品化经营看板/驾驶舱交付 | `yida-dashboard` |
111
- | 批量录入、表格填写、多行编辑 | 默认 `yida-canvas-table-form`;只有已检测到平台 JSX 组件页面/native 页面源码直接依赖实例 `this.utils.yida.saveFormData` 时用 `yida-table-form` |
112
- | 页面视觉方向、页面美化、去 AI 味 | `yida-design` 产出 `prd/<项目名>/prd.md` 和 `prd/<项目名>/design.md`,或单页 PRD 章节 + design spec;实现阶段默认交给 `yida-canvas-custom-page` |
111
+ | 批量录入、表格填写、多行编辑 | 默认 `yida-canvas-table-form`;已检测到平台 JSX 组件页面、native 页面或存量源码使用 `this.utils.yida.saveFormData` 时用 `yida-table-form` |
112
+ | 页面视觉方向、页面美化、去 AI 味 | `yida-design` 只产出或更新 `prd/<项目名>/design.md`;若业务/页面契约也变化,由 `yida-prd` 更新 `prd.md`;实现阶段默认交给 `yida-canvas-custom-page` |
113
113
  | 应用级主题、品牌色、全局换肤 | `yida-design` |
114
114
  | 平台左侧导航树分组/排序 | `yida-nav-group` |
115
115
  | 应用导航隐藏后自绘导航壳 | `yida-nav-shell` |
@@ -137,9 +137,9 @@ description: >
137
137
  10. **读取与复核用合适工具**:读取或定位 workspace 文件优先用当前工具的 Read / Glob / Grep 或 `rg`;OpenYida CLI 已返回成功 JSON、URL、`appType`、`formUuid` 或 `fieldId` 时,以 CLI 结果作为证据。
138
138
  11. **资源 ID 必须精确**:`appType`、`formUuid`、`fieldId` 等应用、表单、字段 ID 必须来自 CLI/API/cache 证据并一字不差传入命令和源码;不得凭名称、截图、相似前缀或记忆补写、改写、截断。
139
139
  12. **字段和 Schema 以证据为准**:字段级表单操作优先交给 `create-form update/add-option/bind-datasource/validation/rule` 的 schema-aware 解析;页面代码、数据、流程、公式等需要字段映射时,每表单一次性执行 `openyida get-schema --field-map-json` 并缓存字段摘要。
140
- 13. **设计事实源固定**:完整应用和真实业务页先由 `yida-design` 输出 `prd/<项目名>/prd.md` 与 `prd/<项目名>/design.md`;页面目标、区块、数据和交互以 PRD 为准,布局、主题、材质和状态视觉以 design.md 为准。
140
+ 13. **设计事实源固定**:完整应用先由 `yida-requirement-analysis` 生成共享简报,再由 `yida-prd` 与 `yida-design` 并行输出 `prd/<项目名>/prd.md` 与 `prd/<项目名>/design.md`,由 `yida-app` join;页面目标、区块、数据和交互以 PRD 为准,布局、主题、材质和状态视觉以 design.md 为准。
141
141
  14. **配置优先于页面代码**:字段、公式、联动、报表、审批和集成交给对应技能;自定义页面负责展示数据、放置业务入口,并串联表单、流程、报表和导航入口。
142
- 15. **Canvas 脚手架桥统一口径**:`.canvas.jsx` / `.canvas.tsx` 发布为 `YidaCodeCanvas` 时,外层页面 `didMount` 默认注入 `window.__OPENYIDA_YIDA_API__` 和 `window.__OPENYIDA_UTILS__`。Canvas 组件内部不得直接写 `this.utils.yida.*`;表单/流程/表单设计 API 走 `window.__OPENYIDA_YIDA_API__`,`toast/dialog/openPage/router.push/isMobile` 等根级工具走 `window.__OPENYIDA_UTILS__`,且 `window.__OPENYIDA_UTILS__.yida` 指向同一个 yida API 桥。
142
+ 15. **Canvas 运行桥统一口径**:`.canvas.jsx` / `.canvas.tsx` 发布为 `YidaCodeCanvas` 时,外层页面 `didMount` 默认注入 `window.__OPENYIDA_YIDA_API__` 和 `window.__OPENYIDA_UTILS__`。Canvas 组件内部不得直接写 `this.utils.yida.*`;表单/流程/表单设计 API 走 `window.__OPENYIDA_YIDA_API__`,`toast/dialog/openPage/router.push/isMobile` 等根级工具走 `window.__OPENYIDA_UTILS__`,且 `window.__OPENYIDA_UTILS__.yida` 指向同一个 yida API 桥。
143
143
  16. **分页查询默认 pageSize 50**:生成表单、流程、任务、成员等分页查询代码时,一般显式写 `pageSize: 50` 或 `pageSize: '50'`。除非用户明确要求小页或大页,不写 `20`、`100` 等其他值;平台上限仍是 100。
144
144
  17. **数据性能优先**:统计聚合用 `yida-report` 服务端聚合,不在前端拉全量后自行聚合。
145
145
  18. **避免无效重试**:失败先查登录态、组织、参数和字段 ID;无修改不连续重试超 1 次。
@@ -157,9 +157,9 @@ description: >
157
157
  - 不把 OpenYida 业务中间文件写到仓库根目录或系统临时目录。
158
158
 
159
159
  20. **报表和可视化先分流**:标准统计与原生报表用 `yida-report`;定制图表页面默认用 `yida-rechart`;只有明确 ECharts、维护旧 ECharts 页面或复杂 option 超出 Recharts 能力时用 `yida-chart`。
160
- 21. **UI 设计技能优先**:涉及应用蓝图、页面视觉、应用主题色、品牌色、全局换肤或 `--color-brand1-*` 时先读 `yida-design`;主题必须根据行业、品牌、业务情绪和视觉目标判断,不套用刻板配色。
161
- 22. **默认完成即停止**:完整应用默认以资源发布成功、轻量导航排序完成、示例数据就绪并输出主入口 URL 与业务交付总结为 doneWhen;截图、精细导航整理和额外深读属于 optionalAfterDone,除非用户明确要求。
162
- 23. **输出业务化**:最终回复先写 2-3 句业务交付总结,再给主入口链接;默认不输出资源 ID 表格、长列表、管理态链接、CDN 构建产物或中间文件 URL。
160
+ 21. **应用主题只有一份**:涉及应用蓝图、页面视觉、应用主题色、品牌色、全局换肤或 `--color-brand1-*` 时先读 `yida-design`。`app-theme.css` 只在应用级统一配置,由平台作用于应用壳、原生表单、详情页和自定义页面外层。严禁在页面级重复写入、同步或向上层注入主题样式;`YidaCodeCanvas` 源码只在 `YidaComp` 内消费现有主题 token。
161
+ 22. **默认完成即停止**:完整应用默认以资源发布成功、轻量导航排序完成、示例数据就绪并输出一组有明确名称的应用入口与业务交付总结为 doneWhen;截图、精细导航整理和额外深读属于 optionalAfterDone,除非用户明确要求。
162
+ 23. **输出业务化**:最终回复先写 2-3 句业务交付总结,再给一组“应用访问入口”。不得把需求简报、PRD、视觉设计、build manifest、资源清单、Schema 或每个表单/流程/报表分别登记成用户可见交付物;完整应用始终给工作台入口,主页面经 PRD 标记为 `standalone` 且导航配置回读通过时增加独立业务入口,非云端 Agent 再增加开发后台入口。
163
163
  24. **任务复盘沉淀**:用户多次纠正、平台接口假成功、页面骨架共性质量问题、线上回读验收方法、一次性脚本可产品化等情况,完成前判断是否需要沉淀到 CLI、测试或 skill。
164
164
 
165
165
  常见问题见 [常见问题解决方案](references/execution-rules.md)。
@@ -17,7 +17,7 @@ OpenYida 任务完成后,除了交付当前结果,还要判断是否有可
17
17
 
18
18
  | 经验类型 | 首选落盘位置 | 示例 |
19
19
  | --- | --- | --- |
20
- | 命令行为、参数校验、平台 API 链路 | `lib/**` + `tests/**` | `update-app --theme` 不能只走 `updateAppName`,需回读详情后用 `updateApp` 保存 |
20
+ | 应用主题文件生成 | `yida-design` + 主题模板 | 复制完整模板后只修改设计确定的 token |
21
21
  | 技能路由、工作流、验收纪律 | `yida-skills/SKILL.md` 或对应子技能 `SKILL.md` | 主题任务必须先读 `yida-design`,页面视觉先读 `yida-design` |
22
22
  | 页面视觉、Dribbble/优秀案例参考方法 | `yida-design` workflow/reference | 参考案例要转译为布局、视觉锚点、密度、色彩、组件细节 |
23
23
  | 自定义页面共性规则 | `yida-canvas-custom-page` | 独立页面按场景确定主题、演示数据有标识、发布后回读 Schema |
@@ -34,11 +34,11 @@ OpenYida 任务完成后,除了交付当前结果,还要判断是否有可
34
34
  1. **参考 Dribbble 不是一句话**
35
35
  用户要求参考 Dribbble / 优秀示例时,必须把参考转成可执行设计变量:页面类型、构图、视觉锚点、信息密度、色彩关系、组件细节、反默认点。交付时说明“参考转译成了什么”。
36
36
 
37
- 2. **所有页面统一消费应用主题**
38
- 独立品牌页、活动页、沉浸页和应用导航隐藏后的自绘壳也统一加载应用主题文件;页面差异通过布局、材质、素材、构图和辅助视觉表达。
37
+ 2. **主题文件统一由 yida-design 生成**
38
+ 页面实现读取 `design.md` 的布局、材质、素材、构图和辅助视觉规则,并使用当前应用主题变量。
39
39
 
40
40
  3. **`--theme` 只能填平台预置 key**
41
- `deepBlue/podBlue/royalBlue/lightBlue/teal/podGreen/deepPurple/purple/podOrange/yellow/magenta/red/greyBlue/coffee/black` 才能作为 app `colour`。默认优先使用 `podBlue`、`podGreen`、`podOrange`;自定义“活力橙”“深玫红”“暗黑金”等应用主题统一生成应用级 CSS,并联合保存 `themeColor`、`navTheme` 与 `customThemeStyle.cssUrl`,由运行容器在各页面上下文加载。
41
+ `deepBlue/podBlue/royalBlue/lightBlue/teal/podGreen/deepPurple/purple/podOrange/yellow/magenta/red/greyBlue/coffee/black` 才能作为 app `colour`。应用级 CSS 由 `yida-design` 生成,应用创建或更新阶段直接消费;页面技能不处理主题保存链路。
42
42
 
43
43
  4. **CLI 成功不等于线上生效**
44
44
  修改应用主题后必须回读 `getAppIncludingAecpInfo`,确认 `colour` 和 `config.COLOUR`。如果接口回包成功但字段没变,要修 CLI 链路和测试,而不是只用一次性脚本绕过。
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: yida-app
3
- description: 宜搭完整应用开发编排技能。对普通 OpenYida 应用做完整搭建或补齐时使用;先解析资源上下文并消费 yida-design 的 prd.md 与 design.md,再按 PRD 创建或复用应用、表单、流程和页面;页面阶段默认使用 Canvas 发布脚手架注入 yida/utils window 桥。
3
+ description: 宜搭完整应用开发编排技能。对普通 OpenYida 应用做完整搭建或补齐时使用;先解析资源上下文并生成共享需求简报,再并行生成 prd.md 与 design.md,join 通过后按 PRD 创建或复用应用、表单、流程和页面;页面阶段默认复制 Canvas 页面基准模板并按业务改写。
4
4
  ---
5
5
 
6
6
  # yida-app
@@ -18,25 +18,26 @@ description: 宜搭完整应用开发编排技能。对普通 OpenYida 应用做
18
18
  | 步骤 | 名称 | 目标 | 产出 |
19
19
  | --- | --- | --- | --- |
20
20
  | 1 | [解析资源上下文](workflow/step-1-resource-context.md) | 合并本轮显式资源、绑定上下文、workspace 配置/缓存和会话历史,确认复用还是允许创建 | 目标 app/page/form/process 上下文 |
21
- | 2 | [产品设计](workflow/step-2-design.md) | 执行 `use_skill("yida-design", "完整应用产品设计")`,产出完整 PRD 和视觉契约 | `prd/<项目名>/prd.md` + `prd/<项目名>/design.md` |
21
+ | 2 | [产品与视觉并行设计](workflow/step-2-design.md) | 先执行 `yida-requirement-analysis` 生成共享简报,再并行执行 `yida-prd` 与 `yida-design`,由本技能 join 两份内部产物 | 内部 `requirement-brief.json` + `prd.md` + `design.md` |
22
22
  | 3 | [创建或复用应用](workflow/step-3-create-or-reuse-app.md) | 已有 `appType` 直接复用;缺少 app 且允许创建时执行 `use_skill("yida-create-app")` | 真实目标 `appType` |
23
- | 4 | [创建或更新业务资源](workflow/step-4-forms-processes.md) | 执行 `use_skill("yida-form-detail")`、`use_skill("yida-create-form-page")`;按 PRD 执行 `use_skill("yida-create-process")`、`use_skill("yida-get-schema")`、`use_skill("yida-report")` 和 `use_skill("yida-integration")` | 真实 `formUuid`、`processCode`、必要 `fieldId/reportId` |
23
+ | 4 | [创建或更新业务资源](workflow/step-4-forms-processes.md) | 执行 `use_skill("yida-create-form-page")`;按 PRD 执行 `use_skill("yida-create-process")`、`use_skill("yida-get-schema")`、`use_skill("yida-report")` 和 `use_skill("yida-integration")` | 真实 `formUuid`、`processCode`、必要 `fieldId/reportId` |
24
24
  | 5 | [写入初始表单数据](workflow/step-5-seed-records.md) | 执行 `use_skill("yida-data-management")`,为核心普通表单写入 1-3 条业务化 seed records 并 query 抽查 | 真实表单记录或明确跳过原因 |
25
25
  | 6 | [创建或复用主页面](workflow/step-6-main-page.md) | 已有 display 页面直接复用;缺少主页面且允许创建时执行 `use_skill("yida-create-page")` | 真实主页面 `formUuid` |
26
26
  | 7 | [编写或更新页面](workflow/step-7-page-code.md) | 执行 `use_skill("yida-canvas-custom-page")`;看板/工作台/驾驶舱必须再执行 `use_skill("yida-dashboard")`,读取表单数据时必须执行 `use_skill("yida-canvas-data-binding")` | 页面源码和真实 dataBinding 通过校验 |
27
27
  | 8 | [发布页面并排序导航](workflow/step-8-publish-navigation.md) | 执行 `use_skill("yida-publish-page")`,发布本轮源码到主页面并执行轻量导航排序 | 已发布主页面 URL |
28
- | 9 | [输出与收尾](workflow/step-9-output-finish.md) | 核对完成条件,按业务语言输出结果 | 2-3 句业务总结 + 一个主入口链接 |
28
+ | 9 | [输出与收尾](workflow/step-9-output-finish.md) | 核对完成条件,按业务语言输出结果 | 2-3 句业务总结 + 一组应用访问入口 |
29
29
 
30
30
  ## 核心规则
31
31
 
32
32
  1. **资源判断以 Step 1 为准**:已有 app/page/form/process 默认复用;只有用户明确从零创建,或目标缺失且本轮允许创建时,才创建缺失资源。
33
33
  2. **显式目标优先**:本轮用户给出的 `appType`、`formUuid`、URL、页面名或流程标识,优先级高于绑定上下文和历史缓存;同级冲突或无法唯一识别时才问用户。
34
- 3. **设计事实源唯一**:需求分析、资源蓝图、页面结构、导航顺序和验收标准由 `yida-design` 写入 `prd.md`;主题 token、布局、材质、圆角、密度、组件和状态规则由 `design.md` 承担。
34
+ 3. **双产物事实源分工**:`yida-requirement-analysis` 只提供共享输入;业务目标、资源蓝图、页面结构、导航顺序和验收标准由 `yida-prd` 写入 `prd.md`;主题 token、布局、材质、圆角、密度、组件和状态规则由 `yida-design` 写入 `design.md`。两份产物 join 通过前不得创建资源。
35
35
  4. **阶段技能按需加载**:进入应用壳、表单、流程、页面、发布、数据写入等阶段时,才执行对应 `use_skill(...)`。
36
36
  5. **真实 ID 和真实数据**:不编造 `appType`、`formUuid`、`fieldId`、`processCode`、`reportId`。完整应用默认给核心普通表单写入 1-3 条业务化 seed records 并 query 抽查;不适合造数时说明原因和空态方案。
37
37
  6. **自定义页面开发技能固定**:完整应用页面源码按 Step 7 执行。
38
38
  7. **删除必须确认**:用户要求删除应用时,先展示应用名称、应用 ID 和影响范围,等待明确“确认删除”后才能执行。
39
39
  8. **列表页选择**:默认使用普通表单的数据管理页;用户明确要求自定义列表页时才创建 display 页面。
40
+ 9. **交付物收口**:Step 2 的三个文件和 Step 9 的 build manifest 都是内部事实源,不是用户交付物。表单、流程、报表和页面只在业务总结中概述,不逐项调用宿主 artifact/交付工具;宿主支持交付工具时,final 只交付一次“应用访问入口”组。
40
41
 
41
42
  ## 关键决策树
42
43
 
@@ -51,7 +52,7 @@ description: 宜搭完整应用开发编排技能。对普通 OpenYida 应用做
51
52
  - 默认页面源码不得使用 `this.dataSourceMap.*`,除非本轮已经创建并绑定对应设计器数据源。
52
53
  - 真实表单数据默认通过页面数据桥或 `window.__OPENYIDA_YIDA_API__.searchFormDatas(params)` 读取;流程发起、流程列表、表单保存/更新等能力也通过发布层注入的同一个 yida API 桥调用;不要用前端 seedRows 冒充真实表单数据。
53
54
  - 页面根级运行态工具通过 `window.__OPENYIDA_UTILS__` 读取,`toast/dialog/openPage/router.push/isMobile` 等工具不能在 `YidaComp` 内直接写 `this.utils.*`。
54
- - 表单新建/提交/详情入口统一使用 `FormOpenContainer`,详情页必须从真实行数据解析 `formInstId`;新版主题由运行容器在自定义页面和提交页/详情页 iframe 分别加载同一应用主题文件。
55
+ - 表单新建/提交/详情入口统一使用 `FormOpenContainer`,详情页必须从真实行数据解析 `formInstId`。
55
56
  - 用户明确要求的自定义列表、看板和详情页优先读取真实表单数据;`page-spec.json` 写 `dataBinding.mode=form`、真实 `appType/formUuid/fieldId` 和字段映射。表单数据管理页不另生成页面源码。
56
57
  - 完整应用默认先写入 1-3 条业务化 seed records 并 query 抽查;没写入成功时,页面展示空态、表单入口、刷新或登记按钮,并在 final 说明原因。
57
58
  - 若页面确实依赖 `this.dataSourceMap.*`,必须执行 `use_skill("yida-data-source-connectors")` 创建/绑定数据源,并在发布后确认页面 Schema 中存在对应数据源;发布输出出现 `No custom page data sources to preserve` 时,本次发布不能视为完成。
@@ -65,9 +66,9 @@ description: 宜搭完整应用开发编排技能。对普通 OpenYida 应用做
65
66
  | 文档 | 覆盖范围 | 何时阅读 |
66
67
  | --- | --- | --- |
67
68
  | [Step 1:解析资源上下文](workflow/step-1-resource-context.md) | 只读预检、资源优先级、命令选择、路径口径 | 必读 |
68
- | [Step 2:产品设计](workflow/step-2-design.md) | `yida-design` 产物边界、主题 key、PRD/design.md 消费 | 必读 |
69
+ | [Step 2:产品与视觉并行设计](workflow/step-2-design.md) | 共享需求简报、PRD/视觉 artifact 生命周期、并行执行、join 与主题 key | 必读 |
69
70
  | [Step 3:创建或复用应用](workflow/step-3-create-or-reuse-app.md) | app 复用、app 创建、主题 key | 必读 |
70
- | [Step 4:创建或更新表单/流程](workflow/step-4-forms-processes.md) | 表单、流程、字段 ID、新版应用主题消费与 legacy formDetail 兼容 | 必读 |
71
+ | [Step 4:创建或更新表单/流程](workflow/step-4-forms-processes.md) | 表单、流程、字段 ID 与表单结构规则 | 必读 |
71
72
  | [Step 5:写入初始表单数据](workflow/step-5-seed-records.md) | seed records、字段类型、query 抽查、跳过条件 | 必读 |
72
73
  | [Step 6:创建或复用主页面](workflow/step-6-main-page.md) | display 页面复用、页面创建、corpId 一致性检查 | 必读 |
73
74
  | [Step 7:编写或更新页面](workflow/step-7-page-code.md) | 页面源码、page-spec、dataBinding、本地校验 | 必读 |