openyida 2026.7.18 → 2026.7.21

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 (200) hide show
  1. package/README.md +37 -2
  2. package/bin/yida.js +113 -18
  3. package/docs/capabilities.md +202 -0
  4. package/lib/agent-center/agent-center.js +2 -3
  5. package/lib/app/app-list.js +3 -4
  6. package/lib/app/build-page.js +13 -6
  7. package/lib/app/check-page.js +16 -6
  8. package/lib/app/compile.js +17 -7
  9. package/lib/app/create-app.js +14 -2
  10. package/lib/app/create-form/api-path.js +25 -0
  11. package/lib/app/create-form/args.js +13 -0
  12. package/lib/app/create-form/commands.js +4 -0
  13. package/lib/app/create-form/definition-reader.js +23 -23
  14. package/lib/app/create-form/field-normalizers.js +26 -7
  15. package/lib/app/create-form/schema-patch.js +4 -1
  16. package/lib/app/create-form.js +155 -68
  17. package/lib/app/create-page.js +47 -10
  18. package/lib/app/generate-page.js +20 -1
  19. package/lib/app/get-form-config.js +2 -1
  20. package/lib/app/get-schema.js +67 -15
  21. package/lib/app/import-app.js +94 -42
  22. package/lib/app/list-forms.js +4 -8
  23. package/lib/app/page-ir.js +140 -0
  24. package/lib/app/publish.js +289 -556
  25. package/lib/app/schema-field-resolution.js +370 -0
  26. package/lib/app/services/app-reader.js +85 -0
  27. package/lib/app/services/app-service.js +235 -0
  28. package/lib/app/services/canvas-page-compiler.js +91 -0
  29. package/lib/app/services/canvas-page-schema-builder.js +149 -0
  30. package/lib/app/services/field-bindings.js +68 -0
  31. package/lib/app/services/form-compiler.js +1922 -0
  32. package/lib/app/services/form-mode-service.js +182 -0
  33. package/lib/app/services/form-schema-patcher.js +333 -0
  34. package/lib/app/services/form-schema-reader.js +59 -0
  35. package/lib/app/services/form-service.js +379 -0
  36. package/lib/app/services/form-validation.js +562 -0
  37. package/lib/app/services/native-page-compiler.js +92 -0
  38. package/lib/app/services/native-page-schema-builder.js +428 -0
  39. package/lib/app/services/page-resource-service.js +185 -0
  40. package/lib/app/update-app.js +22 -9
  41. package/lib/app/update-form-config.js +4 -2
  42. package/lib/asset/asset-cmd.js +19 -6
  43. package/lib/auth/oauth-loopback.js +376 -15
  44. package/lib/auth/token-auth.js +34 -3
  45. package/lib/auth/token-store.js +22 -4
  46. package/lib/basic-info/basic-info.js +2 -1
  47. package/lib/bridge/bridge.js +43 -18
  48. package/lib/core/agent-capabilities.js +5 -3
  49. package/lib/core/command-errors.js +38 -0
  50. package/lib/core/command-manifest.js +59 -1
  51. package/lib/core/copy.js +12 -0
  52. package/lib/core/doctor.js +15 -4
  53. package/lib/core/env-cmd.js +1 -1
  54. package/lib/core/env.js +7 -6
  55. package/lib/core/i18n.js +66 -8
  56. package/lib/core/legacy-schema-guard.js +408 -0
  57. package/lib/core/locales/en.js +38 -46
  58. package/lib/core/locales/zh.js +30 -46
  59. package/lib/core/sample.js +12 -2
  60. package/lib/core/utils.js +334 -66
  61. package/lib/core/yida-client.js +108 -5
  62. package/lib/corp-efficiency/corp-efficiency.js +2 -2
  63. package/lib/corp-manager/corp-manager.js +3 -3
  64. package/lib/formula/evaluate.js +11 -68
  65. package/lib/formula/field-refs.js +83 -0
  66. package/lib/i18n-management/i18n-management.js +2 -3
  67. package/lib/process/configure-process.js +44 -1992
  68. package/lib/process/create-process.js +54 -87
  69. package/lib/process/preview-process.js +20 -8
  70. package/lib/process/services/process-compiler.js +2056 -0
  71. package/lib/process/services/process-reader.js +232 -0
  72. package/lib/process/services/process-resource-service.js +571 -0
  73. package/lib/process/services/process-service.js +122 -0
  74. package/lib/process/services/process-stage-checkpoint.js +246 -0
  75. package/lib/report/append.js +7 -26
  76. package/lib/report/http.js +31 -5
  77. package/lib/report/index.js +10 -2
  78. package/lib/samples/yida-canvas-custom-page/business-list.canvas.jsx +63 -14
  79. package/lib/samples/yida-canvas-custom-page/dashboard-overview.canvas.jsx +176 -32
  80. package/lib/samples/yida-canvas-custom-page/dashboard-starter.canvas.jsx +5 -2
  81. package/lib/samples/yida-canvas-custom-page/data-management.canvas.jsx +228 -14
  82. package/lib/samples/yida-canvas-custom-page/portal-shell-home.canvas.jsx +2 -2
  83. package/lib/samples/yida-canvas-custom-page/split-pane-detail.canvas.jsx +206 -10
  84. package/lib/samples/yida-custom-page/data-management.oyd.jsx +14 -3
  85. package/lib/samples/yida-custom-page/design-tokens.js +2 -2
  86. package/lib/samples/yida-custom-page/detail-profile.oyd.jsx +1 -1
  87. package/lib/samples/yida-custom-page/portal-shell-home.oyd.jsx +7 -2
  88. package/lib/samples/yida-custom-page/split-pane-detail.oyd.jsx +2 -1
  89. package/lib/schema/adapters/app-adapter.js +210 -0
  90. package/lib/schema/adapters/form-adapter.js +1362 -0
  91. package/lib/schema/adapters/keys.js +19 -0
  92. package/lib/schema/adapters/page-adapter.js +566 -0
  93. package/lib/schema/adapters/process-adapter.js +519 -0
  94. package/lib/schema/applier.js +1878 -0
  95. package/lib/schema/apply-store.js +1083 -0
  96. package/lib/schema/command.js +645 -0
  97. package/lib/schema/dependency-graph.js +83 -0
  98. package/lib/schema/errors.js +481 -0
  99. package/lib/schema/hash.js +9 -0
  100. package/lib/schema/manifest-limits.js +177 -0
  101. package/lib/schema/manifest-loader.js +309 -0
  102. package/lib/schema/manifest-schema-v1.json +193 -0
  103. package/lib/schema/normalize-manifest.js +281 -0
  104. package/lib/schema/page-canvas-foundation.js +447 -0
  105. package/lib/schema/page-data-source-builder.js +561 -0
  106. package/lib/schema/page-foundation.js +556 -0
  107. package/lib/schema/page-source-loader.js +314 -0
  108. package/lib/schema/planner.js +691 -0
  109. package/lib/schema/remote-dispatch-boundary.js +39 -0
  110. package/lib/schema/remote-missing.js +21 -0
  111. package/lib/schema/remote-reader.js +189 -0
  112. package/lib/schema/resource-registry.js +157 -0
  113. package/lib/schema/server-revision.js +71 -0
  114. package/lib/schema/sort.js +28 -0
  115. package/lib/schema/state-store.js +589 -0
  116. package/package.json +10 -8
  117. package/scripts/check-release-risks.js +254 -0
  118. package/scripts/generate-command-docs.js +6 -1
  119. package/scripts/i18n-baseline.json +11 -11
  120. package/scripts/postinstall.js +8 -12
  121. package/scripts/validate-ci.sh +15 -11
  122. package/scripts/validate-i18n.js +30 -9
  123. package/scripts/validate-package-size.js +5 -2
  124. package/scripts/validate-skills.js +4 -0
  125. package/scripts/validate-structure.js +15 -0
  126. package/yida-skills/SKILL.md +117 -30
  127. package/yida-skills/references/schema-as-code-phase1.md +99 -0
  128. package/yida-skills/references/setup-and-env.md +59 -59
  129. package/yida-skills/references/task-retrospective.md +6 -6
  130. package/yida-skills/skills/yida-app/SKILL.md +78 -17
  131. package/yida-skills/skills/yida-canvas-custom-page/SKILL.md +18 -7
  132. package/yida-skills/skills/yida-canvas-custom-page/references/data-bridge-guide.md +3 -3
  133. package/yida-skills/skills/yida-canvas-custom-page/references/page-generation-guide.md +15 -0
  134. package/yida-skills/skills/yida-create-app/SKILL.md +21 -3
  135. package/yida-skills/skills/yida-create-form-page/SKILL.md +19 -1
  136. package/yida-skills/skills/yida-create-page/SKILL.md +16 -3
  137. package/yida-skills/skills/yida-create-process/SKILL.md +100 -4
  138. package/yida-skills/skills/yida-custom-page/SKILL.md +19 -4
  139. package/yida-skills/skills/yida-dashboard/SKILL.md +1 -1
  140. package/yida-skills/skills/yida-dashboard/references/pitfalls.md +1 -1
  141. package/yida-skills/skills/yida-get-schema/SKILL.md +49 -5
  142. package/yida-skills/skills/yida-i18n/SKILL.md +1 -1
  143. package/yida-skills/skills/yida-integration/SKILL.md +7 -1
  144. package/yida-skills/skills/yida-login/SKILL.md +50 -99
  145. package/yida-skills/skills/yida-page-config/SKILL.md +7 -1
  146. package/yida-skills/skills/yida-page-uiux/references/app/blueprint.md +0 -1
  147. package/yida-skills/skills/yida-page-uiux/references/app/navigation-patterns.md +0 -1
  148. package/yida-skills/skills/yida-page-uiux/references/app/role-journey.md +0 -1
  149. package/yida-skills/skills/yida-page-uiux/references/dashboard/app-blueprint.md +0 -1
  150. package/yida-skills/skills/yida-page-uiux/references/dashboard/chart-contracts.md +0 -1
  151. package/yida-skills/skills/yida-page-uiux/references/dashboard/component-contracts.md +0 -1
  152. package/yida-skills/skills/yida-page-uiux/references/dashboard/layout-patterns.md +0 -1
  153. package/yida-skills/skills/yida-page-uiux/references/dashboard/theme-recipes.md +0 -1
  154. package/yida-skills/skills/yida-page-uiux/references/detail/object-narrative.md +0 -1
  155. package/yida-skills/skills/yida-page-uiux/references/detail/section-patterns.md +0 -1
  156. package/yida-skills/skills/yida-page-uiux/references/detail/timeline-and-related.md +0 -1
  157. package/yida-skills/skills/yida-page-uiux/references/landing/assets-workflow.md +0 -1
  158. package/yida-skills/skills/yida-page-uiux/references/landing/industry-playbooks.md +0 -1
  159. package/yida-skills/skills/yida-page-uiux/references/landing/research-levels.md +0 -1
  160. package/yida-skills/skills/yida-page-uiux/references/landing/section-patterns.md +0 -1
  161. package/yida-skills/skills/yida-page-uiux/references/list/drawer-detail.md +0 -1
  162. package/yida-skills/skills/yida-page-uiux/references/list/empty-loading-error.md +0 -1
  163. package/yida-skills/skills/yida-page-uiux/references/list/filter-patterns.md +0 -1
  164. package/yida-skills/skills/yida-page-uiux/references/list/table-patterns.md +0 -1
  165. package/yida-skills/skills/yida-page-uiux/references/scenes/screen.md +0 -1
  166. package/yida-skills/skills/yida-page-uiux/references/workbench/entry-patterns.md +0 -1
  167. package/yida-skills/skills/yida-page-uiux/references/workbench/portal-layouts.md +0 -1
  168. package/yida-skills/skills/yida-page-uiux/references/workbench/task-feed.md +0 -1
  169. package/yida-skills/skills/yida-page-uiux/workflow/output-decision-block.md +1 -1
  170. package/yida-skills/skills/yida-process-rule/SKILL.md +35 -1
  171. package/yida-skills/skills/yida-publish-page/SKILL.md +46 -4
  172. package/yida-skills/skills/yida-report/SKILL.md +9 -235
  173. package/yida-skills/skills/yida-report/references/schema-builder-details.md +239 -0
  174. package/yida-skills/skills/yida-skill-evaluator/SKILL.md +170 -0
  175. package/yida-skills/skills-index.json +238 -54
  176. package/lib/core/locales/ar.js +0 -834
  177. package/lib/core/locales/de.js +0 -834
  178. package/lib/core/locales/es.js +0 -834
  179. package/lib/core/locales/fr.js +0 -834
  180. package/lib/core/locales/hi.js +0 -834
  181. package/lib/core/locales/ja.js +0 -1227
  182. package/lib/core/locales/ko.js +0 -836
  183. package/lib/core/locales/pt.js +0 -834
  184. package/lib/core/locales/vi.js +0 -834
  185. package/lib/core/locales/zh-HK.js +0 -1263
  186. package/project/pages/src/demo-birthday-game.oyd.jsx +0 -832
  187. package/project/pages/src/demo-chip-insight.oyd.jsx +0 -983
  188. package/project/pages/src/demo-compat-smoke.oyd.jsx +0 -58
  189. package/project/pages/src/demo-crm-batch-entry.oyd.jsx +0 -805
  190. package/project/pages/src/demo-crm-dashboard.oyd.jsx +0 -677
  191. package/project/pages/src/demo-future-vision-2026.oyd.jsx +0 -1102
  192. package/project/pages/src/demo-ppt.oyd.jsx +0 -1192
  193. package/project/pages/src/demo-salary-calculator.oyd.jsx +0 -904
  194. package/project/pages/src/openyida-knowledge-doc.oyd.jsx +0 -1714
  195. package/yida-skills/skills/large-file-write/SKILL.md +0 -93
  196. package/yida-skills/skills/large-file-write/references/write-patterns.md +0 -147
  197. package/yida-skills/skills/large-file-write/scripts/write.js +0 -157
  198. package/yida-skills/skills/sls-log-workbench/SKILL.md +0 -134
  199. package/yida-skills/skills/sls-log-workbench/references/workbench-reference.md +0 -130
  200. package/yida-skills/skills/sls-log-workbench/sls-query.js +0 -295
@@ -15,32 +15,43 @@
15
15
 
16
16
  const fs = require('fs');
17
17
  const path = require('path');
18
- const { execSync } = require('child_process');
19
18
  const { CliError } = require('../core/cli-error');
20
- const { createAuthRef, createYidaClient, isAuthRefReady } = require('../core/yida-client');
19
+ const { createAuthRef, isAuthRefReady } = require('../core/yida-client');
21
20
  const { t } = require('../core/i18n');
22
21
  const { warn } = require('../core/chalk');
22
+ const { createFormForLegacyProcess } = require('../app/create-form');
23
+ const {
24
+ assertLegacyDirectWriteAllowed,
25
+ extractLegacyGuardArgs,
26
+ } = require('../core/legacy-schema-guard');
27
+ const {
28
+ getProcessCodeFromAppParam,
29
+ getProcessCodeFromSchema,
30
+ switchFormType,
31
+ } = require('./services/process-service');
23
32
 
24
33
  // ── 参数解析 ─────────────────────────────────────────
25
34
 
26
35
  function parseArgs(args) {
27
- const formUuidIndex = args.indexOf('--formUuid');
36
+ const guardSplit = extractLegacyGuardArgs(args || []);
37
+ const directArgs = guardSplit.args;
38
+ const formUuidIndex = directArgs.indexOf('--formUuid');
28
39
 
29
40
  // 用法 2: <appType> --formUuid <formUuid> <processDefinitionFile>
30
41
  if (formUuidIndex !== -1) {
31
- if (formUuidIndex + 2 >= args.length) {
42
+ if (formUuidIndex + 2 >= directArgs.length) {
32
43
  warn(t('create_process.usage2'));
33
44
  throw new CliError(t('create_process.usage2'), {
34
45
  code: 'CREATE_PROCESS_INVALID_ARGUMENTS',
35
46
  });
36
47
  }
37
48
  let appType = null;
38
- const existingFormUuid = args[formUuidIndex + 1];
39
- const processDefFile = args[formUuidIndex + 2];
49
+ const existingFormUuid = directArgs[formUuidIndex + 1];
50
+ const processDefFile = directArgs[formUuidIndex + 2];
40
51
 
41
- for (let i = 0; i < args.length; i++) {
42
- if (args[i] !== '--formUuid' && args[i] !== existingFormUuid && args[i] !== processDefFile) {
43
- appType = args[i];
52
+ for (let i = 0; i < directArgs.length; i++) {
53
+ if (directArgs[i] !== '--formUuid' && directArgs[i] !== existingFormUuid && directArgs[i] !== processDefFile) {
54
+ appType = directArgs[i];
44
55
  break;
45
56
  }
46
57
  }
@@ -51,81 +62,27 @@ function parseArgs(args) {
51
62
  fieldsJsonFile: null,
52
63
  processDefinitionFile: processDefFile,
53
64
  existingFormUuid,
65
+ legacyGuardOptions: guardSplit.guardOptions,
54
66
  };
55
67
  }
56
68
 
57
69
  // 用法 1: <appType> <formTitle> <fieldsJsonFile> <processDefinitionFile>
58
- if (args.length < 4) {
70
+ if (directArgs.length < 4) {
59
71
  warn(t('create_process.usage'));
60
72
  throw new CliError(t('create_process.usage'), {
61
73
  code: 'CREATE_PROCESS_INVALID_ARGUMENTS',
62
74
  });
63
75
  }
64
76
  return {
65
- appType: args[0],
66
- formTitle: args[1],
67
- fieldsJsonFile: args[2],
68
- processDefinitionFile: args[3],
77
+ appType: directArgs[0],
78
+ formTitle: directArgs[1],
79
+ fieldsJsonFile: directArgs[2],
80
+ processDefinitionFile: directArgs[3],
69
81
  existingFormUuid: null,
82
+ legacyGuardOptions: guardSplit.guardOptions,
70
83
  };
71
84
  }
72
85
 
73
- // ── API 调用函数 ─────────────────────────────────────
74
-
75
- function switchFormType(authRef, appType, formUuid) {
76
- const requestPath = '/' + appType + '/query/formdesign/switchFormType.json'
77
- + '?_api=Nav.transformForm&_mock=false&_stamp=' + Date.now();
78
- return createYidaClient({ authRef }).postForm(requestPath, {
79
- _locale_time_zone_offset: '28800000',
80
- toFormType: 'process',
81
- formUuid: formUuid,
82
- });
83
- }
84
-
85
- function getProcessCodeFromAppParam(authRef, appType, formUuid) {
86
- const requestPath = '/' + appType + '/query/app/getAppPlatFormParam.json';
87
- return createYidaClient({ authRef }).get(requestPath, {
88
- _api: 'nattyFetch',
89
- _mock: 'false',
90
- _locale_time_zone_offset: '28800000',
91
- pageIndex: 1,
92
- pageSize: 50,
93
- _stamp: Date.now(),
94
- }).then(function (result) {
95
- if (result.success && result.content && result.content.formNavigationList) {
96
- const navList = result.content.formNavigationList;
97
- for (let i = 0; i < navList.length; i++) {
98
- if (navList[i].formUuid === formUuid && navList[i].processCode) {
99
- return navList[i].processCode;
100
- }
101
- }
102
- }
103
- return null;
104
- });
105
- }
106
-
107
- function getProcessCodeFromSchema(authRef, appType, formUuid) {
108
- const requestPath = '/dingtalk/web/' + appType + '/query/formdesign/getFormSchema.json';
109
- return createYidaClient({ authRef }).get(requestPath, {
110
- formUuid,
111
- schemaVersion: 'V5',
112
- }).then(function (result) {
113
- if (result.success && result.content) {
114
- const schemaStr = typeof result.content === 'string' ? result.content : JSON.stringify(result.content);
115
- const matches = schemaStr.match(/TPROC[A-Za-z0-9_-]+/g);
116
- if (matches && matches.length > 0) {
117
- const unique = [];
118
- const seen = {};
119
- matches.forEach(function (m) {
120
- if (!seen[m]) { seen[m] = true; unique.push(m); }
121
- });
122
- return unique[0];
123
- }
124
- }
125
- return null;
126
- });
127
- }
128
-
129
86
  // ── 主流程 ───────────────────────────────────────────
130
87
 
131
88
  async function run(args) {
@@ -136,6 +93,13 @@ async function run(args) {
136
93
  const useExistingForm = !!existingFormUuid;
137
94
  const fieldsJsonFile = parsed.fieldsJsonFile ? path.resolve(parsed.fieldsJsonFile) : null;
138
95
  const processDefinitionFile = path.resolve(parsed.processDefinitionFile);
96
+ assertLegacyDirectWriteAllowed({
97
+ command: 'create-process',
98
+ resourceType: 'process',
99
+ action: 'create',
100
+ appType,
101
+ formUuid: existingFormUuid,
102
+ }, { guardOptions: parsed.legacyGuardOptions });
139
103
 
140
104
  warn('═'.repeat(60));
141
105
  warn(' 🔧 ' + t('create_process.title'));
@@ -189,17 +153,11 @@ async function run(args) {
189
153
  } else {
190
154
  warn('\n📋 Step 1: ' + t('create_process.creating_form') + '...');
191
155
  try {
192
- // 调用 openyida create-form create 命令
193
- const createFormOutput = execSync(
194
- 'node ' + JSON.stringify(path.resolve(__dirname, '..', '..', 'bin', 'yida.js')) +
195
- ' create-form create ' +
196
- JSON.stringify(appType) + ' ' +
197
- JSON.stringify(formTitle) + ' ' +
198
- JSON.stringify(fieldsJsonFile),
199
- { timeout: 60000, encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }
200
- );
201
- const outputLines = createFormOutput.trim().split('\n');
202
- const createFormResult = JSON.parse(outputLines[outputLines.length - 1]);
156
+ const createFormResult = await createFormForLegacyProcess(authRef, {
157
+ appType,
158
+ formTitle,
159
+ fieldsJsonFile,
160
+ });
203
161
 
204
162
  if (!createFormResult || !createFormResult.success || !createFormResult.formUuid) {
205
163
  warn(' ❌ ' + t('create_process.create_form_failed') + ': ' + JSON.stringify(createFormResult));
@@ -212,12 +170,12 @@ async function run(args) {
212
170
  formUuid = createFormResult.formUuid;
213
171
  fieldCount = createFormResult.fieldCount || 0;
214
172
  warn(' ✅ ' + t('create_process.form_created') + ': ' + formUuid);
215
- } catch (execError) {
216
- warn(' ❌ ' + t('create_process.create_form_failed') + ': ' + execError.message);
217
- if (execError.stderr) {
218
- warn(' ' + execError.stderr.substring(0, 1000));
173
+ } catch (createError) {
174
+ warn(' ❌ ' + t('create_process.create_form_failed') + ': ' + createError.message);
175
+ if (createError.stderr) {
176
+ warn(' ' + createError.stderr.substring(0, 1000));
219
177
  }
220
- throw new CliError(t('create_process.create_form_failed') + ': ' + execError.message, {
178
+ throw new CliError(t('create_process.create_form_failed') + ': ' + createError.message, {
221
179
  code: 'CREATE_PROCESS_CREATE_FORM_FAILED',
222
180
  });
223
181
  }
@@ -245,7 +203,7 @@ async function run(args) {
245
203
  warn('\n🔍 Step 3: ' + t('create_process.getting_process_code') + '...');
246
204
  let processCode = null;
247
205
 
248
- // 方法 1: 从 getAppPlatFormParam 接口提取
206
+ // 方法 1: 从精确表单流程绑定接口提取
249
207
  warn(' ' + t('create_process.method1') + '...');
250
208
  processCode = await getProcessCodeFromAppParam(authRef, appType, formUuid);
251
209
  if (processCode) {
@@ -278,6 +236,15 @@ async function run(args) {
278
236
  });
279
237
  }
280
238
 
239
+ assertLegacyDirectWriteAllowed({
240
+ command: 'configure-process',
241
+ resourceType: 'process',
242
+ action: 'update',
243
+ appType,
244
+ formUuid,
245
+ processCode,
246
+ }, { guardOptions: parsed.legacyGuardOptions });
247
+
281
248
  // Step 4: 配置并发布流程
282
249
  warn('\n⚙️ Step 4: ' + t('create_process.configuring_process') + '...');
283
250
  try {
@@ -21,6 +21,7 @@
21
21
 
22
22
  const fs = require('fs');
23
23
  const path = require('path');
24
+ const { spawnSync } = require('child_process');
24
25
  const {
25
26
  findProjectRoot,
26
27
  } = require('../core/utils');
@@ -859,16 +860,25 @@ async function run(args) {
859
860
  return result;
860
861
  }
861
862
 
863
+ function resolvePreviewBrowserLauncher(filePath, platform = process.platform) {
864
+ if (platform === 'darwin') {
865
+ return { command: 'open', args: [filePath] };
866
+ }
867
+ if (platform === 'win32') {
868
+ return { command: 'rundll32', args: ['url.dll,FileProtocolHandler', filePath] };
869
+ }
870
+ return { command: 'xdg-open', args: [filePath] };
871
+ }
872
+
862
873
  function tryOpenBrowser(filePath) {
863
874
  try {
864
- const { execSync } = require('child_process');
865
- const platform = process.platform;
866
- if (platform === 'darwin') {
867
- execSync(`open "${filePath}"`, { stdio: 'ignore' });
868
- } else if (platform === 'win32') {
869
- execSync(`start "" "${filePath}"`, { stdio: 'ignore' });
870
- } else {
871
- execSync(`xdg-open "${filePath}"`, { stdio: 'ignore' });
875
+ const launcher = resolvePreviewBrowserLauncher(filePath);
876
+ const result = spawnSync(launcher.command, launcher.args, {
877
+ stdio: 'ignore',
878
+ windowsHide: true,
879
+ });
880
+ if (result && (result.error || (typeof result.status === 'number' && result.status !== 0))) {
881
+ throw result.error || new Error('open_browser_failed');
872
882
  }
873
883
  warn(`🌐 ${t('preview_process.browser_opened')}`);
874
884
  } catch {
@@ -883,4 +893,6 @@ module.exports = {
883
893
  fetchProcessInstance,
884
894
  fetchOperationRecords,
885
895
  parseProcessData,
896
+ resolvePreviewBrowserLauncher,
897
+ tryOpenBrowser,
886
898
  };