openyida 2026.9.21 → 2026.9.22-beta.1

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 (334) hide show
  1. package/README.md +14 -20
  2. package/bin/yida.js +6 -11
  3. package/lib/app/app-list.js +3 -7
  4. package/lib/app/canvas-compile.js +12 -22
  5. package/lib/app/check-prd-completeness.js +0 -7
  6. package/lib/app/create-app.js +1 -4
  7. package/lib/app/create-form/args.js +12 -37
  8. package/lib/app/create-form/batch.js +11 -86
  9. package/lib/app/create-form.js +86 -193
  10. package/lib/app/create-page.js +17 -84
  11. package/lib/app/custom-theme.js +0 -11
  12. package/lib/app/form-field-validator.js +41 -26
  13. package/lib/app/form-open-guard.js +10 -97
  14. package/lib/app/get-form-config.js +0 -1
  15. package/lib/app/inline-css-guard.js +31 -1
  16. package/lib/app/services/form-compiler.js +4 -2
  17. package/lib/app/theme-from-design.js +41 -144
  18. package/lib/app/theme-presets.js +1 -1
  19. package/lib/app/update-app.js +13 -63
  20. package/lib/asset/ai-image.js +9 -59
  21. package/lib/asset/asset-cmd.js +7 -18
  22. package/lib/asset/asset-plan.js +9 -102
  23. package/lib/asset/asset-resolve.js +10 -55
  24. package/lib/asset/asset-status.js +4 -5
  25. package/lib/asset/host-capabilities.js +2 -11
  26. package/lib/asset/url-verify.js +4 -19
  27. package/lib/auth/dws-sync.js +145 -0
  28. package/lib/auth/token-auth.js +73 -9
  29. package/lib/auth/token-store.js +50 -0
  30. package/lib/connector/connector-test.js +5 -19
  31. package/lib/connector/contract.js +1 -3
  32. package/lib/core/agent-capabilities.js +16 -19
  33. package/lib/core/command-manifest.js +40 -329
  34. package/lib/core/locales/en.js +17 -74
  35. package/lib/core/locales/zh.js +16 -73
  36. package/lib/core/redact.js +10 -15
  37. package/lib/core/sample.js +30 -72
  38. package/lib/core/utils.js +4 -0
  39. package/lib/design-plan/design-plan.js +4 -51
  40. package/lib/design-plan/init.js +26 -121
  41. package/lib/design-plan/materialize.js +348 -451
  42. package/lib/design-plan/normalize.js +29 -74
  43. package/lib/design-plan/parallel.js +16 -71
  44. package/lib/design-plan/patch.js +16 -63
  45. package/lib/design-plan/preview.js +8 -6
  46. package/lib/design-plan/validate.js +11 -71
  47. package/lib/process/create-process.js +50 -84
  48. package/lib/samples/openyida-scaffold/canvas-form-drawer.canvas.jsx +90 -20
  49. package/lib/samples/openyida-scaffold/canvas-nav/content.jsx +13 -93
  50. package/lib/samples/openyida-scaffold/canvas-nav/data.jsx +18 -100
  51. package/lib/samples/openyida-scaffold/canvas-nav/mixed.jsx +4 -6
  52. package/lib/samples/openyida-scaffold/canvas-nav/shared.jsx +5 -5
  53. package/lib/samples/openyida-scaffold/canvas-nav/side.jsx +2 -1
  54. package/lib/samples/openyida-scaffold/canvas-nav/sidebar.jsx +1 -1
  55. package/lib/samples/openyida-scaffold/canvas-nav/top.jsx +9 -15
  56. package/lib/samples/yida-canvas-table-form/table-form-batch-submit.canvas.jsx +83 -9
  57. package/lib/samples/yida-rechart/trend-combo.canvas.jsx +87 -14
  58. package/package.json +1 -3
  59. package/scripts/postinstall.js +3 -3
  60. package/yida-skills/SKILL.md +16 -19
  61. package/yida-skills/references/official-example-schema-patterns.md +1 -1
  62. package/yida-skills/references/yida-api.md +0 -4
  63. package/yida-skills/skills/yida-app/SKILL.md +23 -46
  64. package/yida-skills/skills/yida-app/workflow/parallel-work.md +6 -15
  65. package/yida-skills/skills/yida-app/workflow/plan/step-1-understand.md +1 -1
  66. package/yida-skills/skills/yida-app/workflow/plan/step-2-confirm.md +1 -1
  67. package/yida-skills/skills/yida-app/workflow/plan/step-4-deliver.md +15 -29
  68. package/yida-skills/skills/yida-app/workflow/plan/workflow.md +11 -29
  69. package/yida-skills/skills/yida-app/workflow/step-1-resource-context.md +2 -4
  70. package/yida-skills/skills/yida-app/workflow/step-2-design.md +9 -23
  71. package/yida-skills/skills/yida-app/workflow/step-3-create-or-reuse-app.md +4 -6
  72. package/yida-skills/skills/yida-app/workflow/step-4-forms-processes.md +4 -15
  73. package/yida-skills/skills/yida-app/workflow/step-6-main-page.md +4 -6
  74. package/yida-skills/skills/yida-app/workflow/step-7-page-code.md +9 -15
  75. package/yida-skills/skills/yida-app/workflow/step-8-publish-navigation.md +11 -25
  76. package/yida-skills/skills/yida-app/workflow/step-9-output-finish.md +28 -68
  77. package/yida-skills/skills/yida-canvas-custom-page/SKILL.md +43 -42
  78. package/yida-skills/skills/yida-canvas-custom-page/references/canvas-style-implementation-guide.md +44 -60
  79. package/yida-skills/skills/yida-canvas-custom-page/references/canvas-theme-provider.md +50 -72
  80. package/yida-skills/skills/yida-canvas-custom-page/references/component-library-guide.md +1 -13
  81. package/yida-skills/skills/yida-canvas-custom-page/references/data-bridge-guide.md +1 -140
  82. package/yida-skills/skills/yida-canvas-custom-page/references/navigation-and-entry-guide.md +72 -101
  83. package/yida-skills/skills/yida-canvas-custom-page/references/page-generation-guide.md +32 -35
  84. package/yida-skills/skills/yida-canvas-custom-page/scripts/build-canvas-theme.js +3 -29
  85. package/yida-skills/skills/yida-canvas-custom-page/scripts/canvas-theme-provider.template.jsx +6 -69
  86. package/yida-skills/skills/yida-canvas-data-binding/SKILL.md +0 -26
  87. package/yida-skills/skills/yida-create-app/SKILL.md +0 -2
  88. package/yida-skills/skills/yida-create-form-page/SKILL.md +58 -72
  89. package/yida-skills/skills/yida-create-form-page/references/advanced-form-modes.md +5 -5
  90. package/yida-skills/skills/yida-create-form-page/references/association-form-field.md +4 -4
  91. package/yida-skills/skills/yida-create-form-page/references/batch-forms.md +5 -6
  92. package/yida-skills/skills/yida-create-form-page/references/field-definition-guide.md +19 -7
  93. package/yida-skills/skills/yida-create-form-page/references/form-field-properties.md +44 -62
  94. package/yida-skills/skills/yida-create-page/SKILL.md +6 -14
  95. package/yida-skills/skills/yida-create-process/SKILL.md +2 -13
  96. package/yida-skills/skills/yida-custom-page/SKILL.md +0 -2
  97. package/yida-skills/skills/yida-custom-page/references/design-system.md +1 -1
  98. package/yida-skills/skills/yida-dashboard/SKILL.md +4 -5
  99. package/yida-skills/skills/yida-data-management/SKILL.md +2 -4
  100. package/yida-skills/skills/yida-data-management/references/data-format-guide.md +4 -4
  101. package/yida-skills/skills/yida-design/SKILL.md +14 -29
  102. package/yida-skills/skills/yida-design/references/app/blueprint.md +70 -0
  103. package/yida-skills/skills/yida-design/references/app/navigation-patterns.md +43 -0
  104. package/yida-skills/skills/yida-design/references/app/role-journey.md +30 -0
  105. package/yida-skills/skills/yida-design/references/ask-human-interaction-contract.md +42 -67
  106. package/yida-skills/skills/yida-design/references/asset-workflow.md +2 -6
  107. package/yida-skills/skills/yida-design/references/design-mode.md +4 -4
  108. package/yida-skills/skills/yida-design/references/page-quality-gates.md +38 -26
  109. package/yida-skills/skills/yida-design/references/style-design-selection.md +137 -0
  110. package/yida-skills/skills/yida-design/references/style-designs/_design-md-template.md +185 -0
  111. package/yida-skills/skills/yida-design/references/style-designs/aqua-service-progress-dashboard.md +242 -0
  112. package/yida-skills/skills/yida-design/references/style-designs/blue-insight-operations-dashboard.md +243 -0
  113. package/yida-skills/skills/yida-design/references/style-designs/blue-productivity-insight-workbench.md +242 -0
  114. package/yida-skills/skills/yida-design/references/style-designs/command-filter-card-console.md +304 -0
  115. package/yida-skills/skills/yida-design/references/style-designs/contrast-command-analytics-workbench.md +261 -0
  116. package/yida-skills/skills/yida-design/references/style-designs/dark-stage-analytic-dashboard.md +369 -0
  117. package/yida-skills/skills/yida-design/references/style-designs/filterable-card-catalog.md +354 -0
  118. package/yida-skills/skills/yida-design/references/style-designs/green-timeline-progress-workbench.md +250 -0
  119. package/yida-skills/skills/yida-design/references/style-designs/registry.md +117 -0
  120. package/yida-skills/skills/yida-design/references/style-designs/soft-analytic-workbench.md +348 -0
  121. package/yida-skills/skills/yida-design/references/style-designs/soft-blue-grid-analytic-dashboard.md +658 -0
  122. package/yida-skills/skills/yida-design/references/style-designs/soft-bordered-analytic-workbench.md +385 -0
  123. package/yida-skills/skills/yida-design/references/style-designs/soft-curated-filter-gallery.md +300 -0
  124. package/yida-skills/skills/yida-design/references/style-designs/soft-modular-analytic-workbench.md +404 -0
  125. package/yida-skills/skills/yida-design/references/style-designs/soft-progress-analytics-workbench.md +382 -0
  126. package/yida-skills/skills/yida-design/references/style-designs/soft-timeline-analytics-workbench.md +367 -0
  127. package/yida-skills/skills/yida-design/references/style-designs/teal-rail-analytics-workbench.md +341 -0
  128. package/yida-skills/skills/yida-design/references/theme/app-custom-theme-template.css +432 -350
  129. package/yida-skills/skills/yida-design/references/visual-decision-engine.md +143 -19
  130. package/yida-skills/skills/yida-design/references/visual-scaffold-recipes.md +27 -15
  131. package/yida-skills/skills/yida-design/sub_skill/page-design/SKILL.md +0 -4
  132. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/SKILL.md +8 -22
  133. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/assets/README.md +10 -14
  134. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/assets/build-plan-template.html +4 -9
  135. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/references/build-plan-compact-schema.md +27 -49
  136. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/references/build-plan-schema.md +154 -33
  137. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/references/visual-design.md +127 -48
  138. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/references/visual-theme-selection.md +51 -37
  139. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/scripts/render_build_plan.py +48 -43
  140. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/scripts/validate_design_themes.py +190 -0
  141. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/README.md +98 -0
  142. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/airy-media-grid.md +339 -0
  143. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/airy-modular-clarity.md +348 -0
  144. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/airy-structured-clarity.md +344 -0
  145. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/ambient-halo-layered.md +345 -0
  146. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/dark-focus-layered.md +355 -0
  147. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/dark-luminous-modular.md +377 -0
  148. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/deep-stage-duotone.md +352 -0
  149. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/hairline-runway-clarity.md +389 -0
  150. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/high-contrast-modular.md +364 -0
  151. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/index.json +329 -0
  152. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/interlocked-vivid-modules.md +348 -0
  153. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/matrix-grid-focus.md +345 -0
  154. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/media-rail-inspector.md +379 -0
  155. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/mist-layered-signal.md +347 -0
  156. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/modular-rail-signal.md +352 -0
  157. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/mono-grid-signal.md +386 -0
  158. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/ribbon-ledger-lift.md +384 -0
  159. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/segmented-meter-clarity.md +388 -0
  160. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/split-rail-precision.md +341 -0
  161. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/templates/design-themes/status-framed-media-grid.md +361 -0
  162. package/yida-skills/skills/yida-design/workflow/output-design.md +375 -117
  163. package/yida-skills/skills/yida-design/workflow/output-prd.md +185 -0
  164. package/yida-skills/skills/yida-design/workflow/step-1-read-brief.md +1 -1
  165. package/yida-skills/skills/yida-design/workflow/step-2-theme-system.md +29 -33
  166. package/yida-skills/skills/yida-design/workflow/step-4-wireframe-interaction.md +1 -3
  167. package/yida-skills/skills/yida-design/workflow/step-5-visual-states.md +106 -22
  168. package/yida-skills/skills/yida-design/workflow/step-6-handoff.md +22 -15
  169. package/yida-skills/skills/yida-form-permission/SKILL.md +0 -6
  170. package/yida-skills/skills/yida-image-assets/SKILL.md +50 -73
  171. package/yida-skills/skills/yida-image-assets/references/manifest-contract.md +52 -82
  172. package/yida-skills/skills/yida-image-assets/references/source-policy.md +15 -14
  173. package/yida-skills/skills/yida-integration/SKILL.md +0 -1
  174. package/yida-skills/skills/yida-login/SKILL.md +0 -2
  175. package/yida-skills/skills/yida-nav-group/SKILL.md +2 -4
  176. package/yida-skills/skills/yida-nav-shell/SKILL.md +12 -36
  177. package/yida-skills/skills/yida-nav-shell/references/nav-shell-patterns.md +136 -79
  178. package/yida-skills/skills/yida-page-config/SKILL.md +4 -13
  179. package/yida-skills/skills/yida-prd/SKILL.md +3 -5
  180. package/yida-skills/skills/yida-prd/references/app/blueprint.md +4 -4
  181. package/yida-skills/skills/yida-prd/references/app/navigation-patterns.md +3 -6
  182. package/yida-skills/skills/yida-prd/references/app/role-journey.md +3 -5
  183. package/yida-skills/skills/yida-prd/references/plan-content.md +0 -4
  184. package/yida-skills/skills/yida-prd/workflow/output-prd.md +11 -18
  185. package/yida-skills/skills/yida-prd/workflow/plan-business.md +4 -4
  186. package/yida-skills/skills/yida-prd/workflow/step-2-information-architecture.md +8 -11
  187. package/yida-skills/skills/yida-publish-page/SKILL.md +1 -9
  188. package/yida-skills/skills/yida-requirement-analysis/SKILL.md +39 -10
  189. package/yida-skills/skills/yida-requirement-analysis/workflow/prepare-brief.md +71 -40
  190. package/yida-skills/skills-index.json +16 -36
  191. package/lib/app/application-entry-urls.js +0 -31
  192. package/lib/app/application-style.js +0 -69
  193. package/lib/app/canvas-icon-exports.json +0 -6160
  194. package/lib/app/canvas-icon-guard.js +0 -87
  195. package/lib/app/canvas-navigation-guard.js +0 -84
  196. package/lib/app/canvas-path-guard.js +0 -78
  197. package/lib/app/canvas-theme-guard.js +0 -184
  198. package/lib/app/form-data-response-guard.js +0 -57
  199. package/lib/asset/asset-execution.js +0 -79
  200. package/lib/core/css-structure.js +0 -37
  201. package/lib/design/check-design.js +0 -51
  202. package/lib/design/document.js +0 -458
  203. package/lib/design/icon-contrast.js +0 -85
  204. package/lib/design/page-content.js +0 -11
  205. package/lib/design-plan/artifact-updates.js +0 -117
  206. package/lib/design-plan/confirmation.js +0 -13
  207. package/lib/design-plan/entry-navigation.js +0 -97
  208. package/lib/design-plan/navigation-policy.js +0 -38
  209. package/lib/design-plan/rebase.js +0 -60
  210. package/lib/design-plan/themes.js +0 -101
  211. package/lib/design-plan/visual-policy.js +0 -42
  212. package/lib/samples/openyida-scaffold/canvas-admin-entry.jsx +0 -62
  213. package/lib/samples/openyida-scaffold/canvas-navigation.jsx +0 -56
  214. package/lib/samples/openyida-scaffold/canvas-view-state.jsx +0 -74
  215. package/yida-skills/skills/yida-app/references/entry-navigation.md +0 -193
  216. package/yida-skills/skills/yida-canvas-custom-page/references/view-state-recovery.md +0 -52
  217. package/yida-skills/skills/yida-canvas-data-binding/references/business-action-permissions.md +0 -31
  218. package/yida-skills/skills/yida-design/references/application-style-library.md +0 -93
  219. package/yida-skills/skills/yida-design/references/application-theme-consistency.md +0 -150
  220. package/yida-skills/skills/yida-design/references/native-form-styles.md +0 -208
  221. package/yida-skills/skills/yida-design/references/navigation-decision.md +0 -53
  222. package/yida-skills/skills/yida-design/references/page-continuity.md +0 -42
  223. package/yida-skills/skills/yida-design/references/theme/application-style-recipes.css +0 -58
  224. package/yida-skills/skills/yida-design/references/theme-selection.md +0 -67
  225. package/yida-skills/skills/yida-design/scripts/validate_design_themes.py +0 -302
  226. package/yida-skills/skills/yida-design/templates/application-styles.json +0 -398
  227. package/yida-skills/skills/yida-design/templates/design-themes/README.md +0 -73
  228. package/yida-skills/skills/yida-design/templates/design-themes/app-amber/app_theme.css +0 -748
  229. package/yida-skills/skills/yida-design/templates/design-themes/app-amber/design.md +0 -274
  230. package/yida-skills/skills/yida-design/templates/design-themes/app-amber/form-layout.json +0 -15
  231. package/yida-skills/skills/yida-design/templates/design-themes/app-editorial/app_theme.css +0 -748
  232. package/yida-skills/skills/yida-design/templates/design-themes/app-editorial/design.md +0 -274
  233. package/yida-skills/skills/yida-design/templates/design-themes/app-editorial/form-layout.json +0 -14
  234. package/yida-skills/skills/yida-design/templates/design-themes/app-executive/app_theme.css +0 -748
  235. package/yida-skills/skills/yida-design/templates/design-themes/app-executive/design.md +0 -274
  236. package/yida-skills/skills/yida-design/templates/design-themes/app-executive/form-layout.json +0 -13
  237. package/yida-skills/skills/yida-design/templates/design-themes/app-finance/app_theme.css +0 -748
  238. package/yida-skills/skills/yida-design/templates/design-themes/app-finance/design.md +0 -274
  239. package/yida-skills/skills/yida-design/templates/design-themes/app-finance/form-layout.json +0 -14
  240. package/yida-skills/skills/yida-design/templates/design-themes/app-glass/app_theme.css +0 -748
  241. package/yida-skills/skills/yida-design/templates/design-themes/app-glass/design.md +0 -274
  242. package/yida-skills/skills/yida-design/templates/design-themes/app-glass/form-layout.json +0 -14
  243. package/yida-skills/skills/yida-design/templates/design-themes/app-graphite/app_theme.css +0 -748
  244. package/yida-skills/skills/yida-design/templates/design-themes/app-graphite/design.md +0 -274
  245. package/yida-skills/skills/yida-design/templates/design-themes/app-graphite/form-layout.json +0 -14
  246. package/yida-skills/skills/yida-design/templates/design-themes/app-line/app_theme.css +0 -748
  247. package/yida-skills/skills/yida-design/templates/design-themes/app-line/design.md +0 -274
  248. package/yida-skills/skills/yida-design/templates/design-themes/app-line/form-layout.json +0 -13
  249. package/yida-skills/skills/yida-design/templates/design-themes/app-neon/app_theme.css +0 -748
  250. package/yida-skills/skills/yida-design/templates/design-themes/app-neon/design.md +0 -274
  251. package/yida-skills/skills/yida-design/templates/design-themes/app-neon/form-layout.json +0 -14
  252. package/yida-skills/skills/yida-design/templates/design-themes/app-nordic/app_theme.css +0 -754
  253. package/yida-skills/skills/yida-design/templates/design-themes/app-nordic/design.md +0 -279
  254. package/yida-skills/skills/yida-design/templates/design-themes/app-nordic/form-layout.json +0 -13
  255. package/yida-skills/skills/yida-design/templates/design-themes/app-paper/app_theme.css +0 -748
  256. package/yida-skills/skills/yida-design/templates/design-themes/app-paper/design.md +0 -274
  257. package/yida-skills/skills/yida-design/templates/design-themes/app-paper/form-layout.json +0 -13
  258. package/yida-skills/skills/yida-design/templates/design-themes/app-platinum/app_theme.css +0 -748
  259. package/yida-skills/skills/yida-design/templates/design-themes/app-platinum/design.md +0 -274
  260. package/yida-skills/skills/yida-design/templates/design-themes/app-platinum/form-layout.json +0 -14
  261. package/yida-skills/skills/yida-design/templates/design-themes/app-plum/app_theme.css +0 -748
  262. package/yida-skills/skills/yida-design/templates/design-themes/app-plum/design.md +0 -274
  263. package/yida-skills/skills/yida-design/templates/design-themes/app-plum/form-layout.json +0 -14
  264. package/yida-skills/skills/yida-design/templates/design-themes/app-pop/app_theme.css +0 -758
  265. package/yida-skills/skills/yida-design/templates/design-themes/app-pop/design.md +0 -281
  266. package/yida-skills/skills/yida-design/templates/design-themes/app-pop/form-layout.json +0 -14
  267. package/yida-skills/skills/yida-design/templates/design-themes/app-sage/app_theme.css +0 -748
  268. package/yida-skills/skills/yida-design/templates/design-themes/app-sage/design.md +0 -274
  269. package/yida-skills/skills/yida-design/templates/design-themes/app-sage/form-layout.json +0 -14
  270. package/yida-skills/skills/yida-design/templates/design-themes/app-teal/app_theme.css +0 -748
  271. package/yida-skills/skills/yida-design/templates/design-themes/app-teal/design.md +0 -274
  272. package/yida-skills/skills/yida-design/templates/design-themes/app-teal/form-layout.json +0 -14
  273. package/yida-skills/skills/yida-design/templates/design-themes/app-terminal/app_theme.css +0 -754
  274. package/yida-skills/skills/yida-design/templates/design-themes/app-terminal/design.md +0 -279
  275. package/yida-skills/skills/yida-design/templates/design-themes/app-terminal/form-layout.json +0 -14
  276. package/yida-skills/skills/yida-design/templates/design-themes/app-ticket/app_theme.css +0 -752
  277. package/yida-skills/skills/yida-design/templates/design-themes/app-ticket/design.md +0 -278
  278. package/yida-skills/skills/yida-design/templates/design-themes/app-ticket/form-layout.json +0 -13
  279. package/yida-skills/skills/yida-design/templates/design-themes/app-wire/app_theme.css +0 -748
  280. package/yida-skills/skills/yida-design/templates/design-themes/app-wire/design.md +0 -274
  281. package/yida-skills/skills/yida-design/templates/design-themes/app-wire/form-layout.json +0 -14
  282. package/yida-skills/skills/yida-design/templates/design-themes/basic-tokens.json +0 -118
  283. package/yida-skills/skills/yida-design/templates/design-themes/dark-inset-hairline/app_theme.css +0 -690
  284. package/yida-skills/skills/yida-design/templates/design-themes/dark-inset-hairline/design.md +0 -382
  285. package/yida-skills/skills/yida-design/templates/design-themes/dark-inset-hairline/form-layout.json +0 -13
  286. package/yida-skills/skills/yida-design/templates/design-themes/dark-rail-fine-lines/app_theme.css +0 -691
  287. package/yida-skills/skills/yida-design/templates/design-themes/dark-rail-fine-lines/design.md +0 -380
  288. package/yida-skills/skills/yida-design/templates/design-themes/dark-rail-fine-lines/form-layout.json +0 -13
  289. package/yida-skills/skills/yida-design/templates/design-themes/dark-rail-signal-panels/app_theme.css +0 -696
  290. package/yida-skills/skills/yida-design/templates/design-themes/dark-rail-signal-panels/design.md +0 -378
  291. package/yida-skills/skills/yida-design/templates/design-themes/dark-rail-signal-panels/form-layout.json +0 -13
  292. package/yida-skills/skills/yida-design/templates/design-themes/free-creative/app_theme.css +0 -689
  293. package/yida-skills/skills/yida-design/templates/design-themes/free-creative/design.md +0 -238
  294. package/yida-skills/skills/yida-design/templates/design-themes/free-creative/form-layout.json +0 -13
  295. package/yida-skills/skills/yida-design/templates/design-themes/graphite-bevel-grid/app_theme.css +0 -692
  296. package/yida-skills/skills/yida-design/templates/design-themes/graphite-bevel-grid/design.md +0 -375
  297. package/yida-skills/skills/yida-design/templates/design-themes/graphite-bevel-grid/form-layout.json +0 -13
  298. package/yida-skills/skills/yida-design/templates/design-themes/hairline-shared-bands/app_theme.css +0 -691
  299. package/yida-skills/skills/yida-design/templates/design-themes/hairline-shared-bands/design.md +0 -362
  300. package/yida-skills/skills/yida-design/templates/design-themes/hairline-shared-bands/form-layout.json +0 -13
  301. package/yida-skills/skills/yida-design/templates/design-themes/hairline-soft-blocks/app_theme.css +0 -691
  302. package/yida-skills/skills/yida-design/templates/design-themes/hairline-soft-blocks/design.md +0 -409
  303. package/yida-skills/skills/yida-design/templates/design-themes/hairline-soft-blocks/form-layout.json +0 -13
  304. package/yida-skills/skills/yida-design/templates/design-themes/index.json +0 -464
  305. package/yida-skills/skills/yida-design/templates/design-themes/ink-glow-soft-panels/app_theme.css +0 -701
  306. package/yida-skills/skills/yida-design/templates/design-themes/ink-glow-soft-panels/design.md +0 -379
  307. package/yida-skills/skills/yida-design/templates/design-themes/ink-glow-soft-panels/form-layout.json +0 -13
  308. package/yida-skills/skills/yida-design/templates/design-themes/inset-frame-pixel-rhythm/app_theme.css +0 -691
  309. package/yida-skills/skills/yida-design/templates/design-themes/inset-frame-pixel-rhythm/design.md +0 -404
  310. package/yida-skills/skills/yida-design/templates/design-themes/inset-frame-pixel-rhythm/form-layout.json +0 -13
  311. package/yida-skills/skills/yida-design/templates/design-themes/outlined-texture-duotone/app_theme.css +0 -698
  312. package/yida-skills/skills/yida-design/templates/design-themes/outlined-texture-duotone/design.md +0 -389
  313. package/yida-skills/skills/yida-design/templates/design-themes/outlined-texture-duotone/form-layout.json +0 -13
  314. package/yida-skills/skills/yida-design/templates/design-themes/soft-inset-surfaces/app_theme.css +0 -691
  315. package/yida-skills/skills/yida-design/templates/design-themes/soft-inset-surfaces/design.md +0 -372
  316. package/yida-skills/skills/yida-design/templates/design-themes/soft-inset-surfaces/form-layout.json +0 -13
  317. package/yida-skills/skills/yida-design/templates/design-themes/soft-outline-rhythm/app_theme.css +0 -690
  318. package/yida-skills/skills/yida-design/templates/design-themes/soft-outline-rhythm/design.md +0 -455
  319. package/yida-skills/skills/yida-design/templates/design-themes/soft-outline-rhythm/form-layout.json +0 -13
  320. package/yida-skills/skills/yida-design/templates/design-themes/soft-rail-bold-band/app_theme.css +0 -698
  321. package/yida-skills/skills/yida-design/templates/design-themes/soft-rail-bold-band/design.md +0 -394
  322. package/yida-skills/skills/yida-design/templates/design-themes/soft-rail-bold-band/form-layout.json +0 -13
  323. package/yida-skills/skills/yida-design/templates/design-themes/soft-spectral-panels/app_theme.css +0 -692
  324. package/yida-skills/skills/yida-design/templates/design-themes/soft-spectral-panels/design.md +0 -391
  325. package/yida-skills/skills/yida-design/templates/design-themes/soft-spectral-panels/form-layout.json +0 -13
  326. package/yida-skills/skills/yida-design/templates/design-themes/warm-canvas-contrast-panels/app_theme.css +0 -711
  327. package/yida-skills/skills/yida-design/templates/design-themes/warm-canvas-contrast-panels/design.md +0 -408
  328. package/yida-skills/skills/yida-design/templates/design-themes/warm-canvas-contrast-panels/form-layout.json +0 -13
  329. package/yida-skills/skills/yida-design/templates/design-themes/warm-rail-muted-panels/app_theme.css +0 -692
  330. package/yida-skills/skills/yida-design/templates/design-themes/warm-rail-muted-panels/design.md +0 -383
  331. package/yida-skills/skills/yida-design/templates/design-themes/warm-rail-muted-panels/form-layout.json +0 -13
  332. package/yida-skills/skills/yida-design/templates/navigation-styles.json +0 -769
  333. package/yida-skills/skills/yida-requirement-analysis/references/experience-groups.md +0 -79
  334. package/yida-skills/skills/yida-requirement-analysis/references/handoff.md +0 -68
@@ -10,8 +10,6 @@ const { minimumSize, prepareAssetPlan } = require('./asset-plan');
10
10
  const { readImageMetadata, parseImageMetadata } = require('./image-metadata');
11
11
  const { MAX_IMAGE_BYTES, uploadAttachment } = require('./attachment-upload');
12
12
  const { getAssetStatus } = require('./asset-status');
13
- const { t } = require('../core/i18n');
14
- const { verifyImageUrl } = require('./url-verify');
15
13
 
16
14
  const ALLOWED_STOCK_IMAGE_PROVIDERS = Object.freeze({
17
15
  unsplash: Object.freeze(['images.unsplash.com']),
@@ -44,20 +42,8 @@ function getCollectedImageProvider(rawUrl) {
44
42
  return null;
45
43
  }
46
44
 
47
- function deliveryRights(rawUrl, ctx = {}) {
48
- const provider = getCollectedImageProvider(rawUrl) || ctx.provider;
49
- const stock = (ctx.assetSource || 'search') === 'search';
50
- return {
51
- hotlinkAllowed: ctx.hotlinkAllowed ?? (isHttpUrl(rawUrl) && stock && !!ALLOWED_STOCK_IMAGE_PROVIDERS[provider]),
52
- rehostAllowed: ctx.rehostAllowed ?? !(stock && provider === 'unsplash'),
53
- };
54
- }
55
-
56
- function getExternalDeliveryPolicy(rawUrl, ctx = {}) {
57
- if (!isHttpUrl(rawUrl)) {return 'standard';}
58
- const rights = deliveryRights(rawUrl, ctx);
59
- if (rights.hotlinkAllowed && ctx.deliveryMode !== 'upload') {return 'original-url';}
60
- return rights.rehostAllowed ? 'yida-attachment' : 'blocked';
45
+ function getExternalDeliveryPolicy(rawUrl) {
46
+ return isHttpUrl(rawUrl) ? 'yida-attachment' : 'standard';
61
47
  }
62
48
 
63
49
  function extensionFromUrl(rawUrl) {
@@ -194,29 +180,15 @@ async function resolveOne(candidate, ctx = {}) {
194
180
  allowedProviders: Object.keys(ALLOWED_STOCK_IMAGE_PROVIDERS),
195
181
  };
196
182
  }
197
- const deliveryPolicy = getExternalDeliveryPolicy(raw, ctx);
198
- const rights = deliveryRights(raw, ctx);
183
+ const deliveryPolicy = getExternalDeliveryPolicy(raw);
199
184
  const common = { provider: inputProvider || ctx.provider || assetSource };
200
- const original = (metadata, reason = 'ASSET_TOO_LARGE') => {
201
- if (!rights.hotlinkAllowed) {return { ...common, resolved: false, reason };}
185
+ const original = metadata => {
202
186
  const failure = sizeFailure(metadata, ctx);
203
187
  if (failure) {return { ...common, resolved: false, reason: failure };}
204
188
  return { ...common, ...metadata, imageType: metadata.type, resolved: true, url: raw,
205
- source: 'external', reason, deliveryPolicy: 'original-url' };
189
+ source: 'external', reason: 'ASSET_TOO_LARGE', deliveryPolicy: 'original-url' };
206
190
  };
207
- if (deliveryPolicy === 'blocked') {
208
- return { ...common, resolved: false, reason: 'REHOST_NOT_ALLOWED', deliveryPolicy };
209
- }
210
- if (deliveryPolicy === 'original-url') {
211
- const verified = await (ctx.verifyFn || verifyImageUrl)(raw, {
212
- timeout: ctx.timeout, minWidth: ctx.minWidth, minHeight: ctx.minHeight,
213
- allowUrl: assetSource === 'search' ? url => getCollectedImageProvider(url) === inputProvider : undefined,
214
- });
215
- if (!verified.ok) {return { ...common, resolved: false, reason: verified.reason };}
216
- return original({ ...verified, type: verified.imageType }, 'OK_DIRECT');
217
- }
218
191
  let tempPath = '';
219
- let verifiedMetadata;
220
192
  try {
221
193
  tempPath = await (ctx.downloadFn || downloadUrlToTemp)(raw, { timeout: ctx.timeout, stockOnly: assetSource === 'search' });
222
194
  if (fs.statSync(tempPath).size > MAX_IMAGE_BYTES) {return original(readImageMetadata(tempPath));}
@@ -224,20 +196,18 @@ async function resolveOne(candidate, ctx = {}) {
224
196
  const failure = sizeFailure(downloaded, ctx);
225
197
  if (failure) {return { resolved: false, url: raw, source: 'external', reason: failure };}
226
198
  Object.assign(common, downloaded, { contentHash: fileHash(tempPath), imageType: downloaded.type });
227
- verifiedMetadata = { ...common, type: downloaded.type };
228
199
  const reused = await reuseDelivery(raw, common, ctx);
229
200
  if (reused) {return reused;}
230
- if (!ctx.canUpload) {return original(verifiedMetadata, 'YIDA_ATTACHMENT_UNAVAILABLE');}
201
+ if (!ctx.canUpload) {return { resolved: false, url: raw, source: 'external', reason: 'YIDA_ATTACHMENT_UNAVAILABLE' };}
231
202
  const results = await ctx.uploadFn([tempPath]);
232
203
  const hit = (results || []).find(result => result.success && result.originalPath === tempPath)
233
204
  || (results || []).find(result => result.success);
234
205
  if (hit && isHttpUrl(hit.cdnUrl)) {
235
206
  return { ...common, resolved: true, url: hit.cdnUrl, source: 'yida-attachment', reason: 'OK', deliveryPolicy };
236
207
  }
237
- return original(verifiedMetadata, ((results || [])[0] || {}).error || 'UPLOAD_FAILED');
208
+ return { ...common, resolved: false, url: raw, source: 'external', reason: ((results || [])[0] || {}).error || 'UPLOAD_FAILED' };
238
209
  } catch (error) {
239
210
  if (error.message === 'ASSET_TOO_LARGE') {return original(error.metadata || {});}
240
- if (verifiedMetadata) {return original(verifiedMetadata, error.code || error.message || 'UPLOAD_FAILED');}
241
211
  return { ...common, resolved: false, url: raw, source: 'external', reason: error.code || error.message || 'UPLOAD_FAILED' };
242
212
  } finally {
243
213
  if (tempPath) {
@@ -260,7 +230,6 @@ async function resolveOne(candidate, ctx = {}) {
260
230
  allowedProviders: Object.keys(ALLOWED_STOCK_IMAGE_PROVIDERS),
261
231
  };
262
232
  }
263
- if (!deliveryRights(raw, ctx).rehostAllowed) {return { resolved: false, reason: 'REHOST_NOT_ALLOWED' };}
264
233
  const metadata = readImageMetadata(raw);
265
234
  const failure = sizeFailure(metadata, ctx);
266
235
  if (failure) {
@@ -289,9 +258,7 @@ async function resolveOne(candidate, ctx = {}) {
289
258
  }
290
259
  }
291
260
 
292
- return { resolved: false, url: raw, source: 'unknown', reason: 'NOT_FOUND',
293
- message: t('asset.localFileUnavailable', path.resolve(raw)),
294
- details: { input: raw, resolvedPath: path.resolve(raw), baseDir: process.cwd(), pathBase: 'cwd' } };
261
+ return { resolved: false, url: raw, source: 'unknown', reason: 'NOT_FOUND' };
295
262
  }
296
263
 
297
264
  function normalizeSource(source, fallback) {
@@ -317,7 +284,7 @@ function metadataGaps(asset) {
317
284
  }
318
285
 
319
286
  async function resolveAssets(assets = [], options = {}) {
320
- const plan = prepareAssetPlan(assets, options.assetStrategy, options.pageId);
287
+ const plan = prepareAssetPlan(assets, options.assetStrategy);
321
288
  const entries = plan.entries;
322
289
  const online = options.online !== false;
323
290
  const status = options.status || getAssetStatus({ online, env: options.env, runtime: options.runtime });
@@ -345,14 +312,10 @@ async function resolveAssets(assets = [], options = {}) {
345
312
  previous: asset,
346
313
  assetSource: source,
347
314
  provider: asset.provider,
348
- hotlinkAllowed: asset.hotlinkAllowed,
349
- rehostAllowed: asset.rehostAllowed,
350
- deliveryMode: options.uploadAssets ? 'upload' : asset.deliveryMode,
351
315
  online,
352
316
  canUpload,
353
317
  timeout: options.timeout,
354
318
  downloadFn: options.downloadFn,
355
- verifyFn: options.verifyFn,
356
319
  uploadFn,
357
320
  ...size,
358
321
  });
@@ -371,8 +334,6 @@ async function resolveAssets(assets = [], options = {}) {
371
334
  slotId,
372
335
  pageId: asset.pageId || '',
373
336
  input,
374
- deliveryMode: options.uploadAssets ? 'upload' : asset.deliveryMode || 'auto',
375
- ...Object.fromEntries(['hotlinkAllowed', 'rehostAllowed'].filter(key => asset[key] !== undefined).map(key => [key, asset[key]])),
376
337
  ...minimumSize(asset),
377
338
  ...(asset.minSize !== undefined ? { minSize: asset.minSize } : {}),
378
339
  usage: asset.usage || '',
@@ -381,13 +342,9 @@ async function resolveAssets(assets = [], options = {}) {
381
342
  localPath: isLocalFile(input) ? input : '',
382
343
  source,
383
344
  provider,
384
- assetId: asset.assetId || '',
385
345
  sourcePage: asset.sourcePage || '',
386
346
  creator: asset.creator || '',
387
347
  license: asset.license || '',
388
- licenseUrl: asset.licenseUrl || '',
389
- licenseCheckedAt: asset.licenseCheckedAt || '',
390
- authorizationEvidence: [...(asset.authorizationEvidence || [])],
391
348
  attribution: asset.attribution || '',
392
349
  downloadLocation: asset.downloadLocation || '',
393
350
  downloadTracked: asset.downloadTracked === true,
@@ -406,8 +363,7 @@ async function resolveAssets(assets = [], options = {}) {
406
363
  slotId: slotId || `slot-${index + 1}`,
407
364
  pageId: output.pageId,
408
365
  code: result.reason,
409
- message: result.message || `图片未落地:${result.reason}`,
410
- ...(result.details ? { details: result.details } : {}),
366
+ message: `图片未落地:${result.reason}`,
411
367
  });
412
368
  gaps.push(...output.gaps.map(gap => ({ ...gap })));
413
369
  return;
@@ -445,7 +401,6 @@ async function resolveAssets(assets = [], options = {}) {
445
401
  capabilityEvidence: {
446
402
  host: status.hostCapabilities,
447
403
  cdnConfigured: status.cdnConfigured,
448
- deliveryPreference: 'verified-direct-url',
449
404
  uploadTarget: 'yida-attachment',
450
405
  maxUploadBytes: MAX_IMAGE_BYTES,
451
406
  online,
@@ -41,8 +41,8 @@ function getAssetStatus(options = {}) {
41
41
 
42
42
  let recommendedStrategy;
43
43
  if (online) {
44
- recommendedStrategy = STRATEGY.EXTERNAL_URL;
45
- reasons.push('允许外链的图片检查通过后直接使用;上传本地图或需托管的图片时才需要登录态和 appType。');
44
+ recommendedStrategy = STRATEGY.YIDA_ATTACHMENT;
45
+ reasons.push('图片默认上传宜搭附件,需要登录态和 appType;超过 20 MiB 的外链保留原链接。');
46
46
  } else {
47
47
  recommendedStrategy = STRATEGY.LOW_FIDELITY;
48
48
  reasons.push('离线模式不校验外链,也不上传图片。');
@@ -56,9 +56,8 @@ function getAssetStatus(options = {}) {
56
56
  cdnConfigured: valid,
57
57
  canUpload: online,
58
58
  uploadTarget: 'yida-attachment',
59
- requiresLogin: false,
60
- requiresAppType: false,
61
- uploadRequirements: { requiresLogin: true, requiresAppType: true },
59
+ requiresLogin: true,
60
+ requiresAppType: true,
62
61
  canGenerate: generator.available,
63
62
  hostCapabilities,
64
63
  recommendedStrategy,
@@ -1,13 +1,9 @@
1
1
  'use strict';
2
2
 
3
- const { getAssetExecutionContract, selectAssetExecutionMode } = require('./asset-execution');
4
-
5
3
  const CAPABILITY_ENV = Object.freeze({
6
4
  onlineSearch: 'OPENYIDA_AGENT_ONLINE_SEARCH',
7
5
  imageSearch: 'OPENYIDA_AGENT_IMAGE_SEARCH',
8
6
  imageGeneration: 'OPENYIDA_AGENT_IMAGE_GENERATION',
9
- backgroundAgent: 'OPENYIDA_AGENT_BACKGROUND_AGENT',
10
- backgroundShell: 'OPENYIDA_AGENT_BACKGROUND_SHELL',
11
7
  });
12
8
 
13
9
  function readDeclaredCapability(value) {
@@ -67,9 +63,7 @@ function buildHostAssetCapabilities(options = {}) {
67
63
  const onlineSearch = resolveCapability(env[CAPABILITY_ENV.onlineSearch], searchDefault());
68
64
  const imageSearch = resolveCapability(env[CAPABILITY_ENV.imageSearch], searchDefault());
69
65
  const imageGeneration = resolveCapability(env[CAPABILITY_ENV.imageGeneration], generationDefault);
70
- const backgroundAgent = readDeclaredCapability(env[CAPABILITY_ENV.backgroundAgent]);
71
- const backgroundShell = readDeclaredCapability(env[CAPABILITY_ENV.backgroundShell]);
72
- const capabilities = [onlineSearch, imageSearch, imageGeneration, backgroundAgent, backgroundShell];
66
+ const capabilities = [onlineSearch, imageSearch, imageGeneration];
73
67
 
74
68
  return {
75
69
  schema_version: 1,
@@ -82,13 +76,10 @@ function buildHostAssetCapabilities(options = {}) {
82
76
  online_search: onlineSearch,
83
77
  image_search: imageSearch,
84
78
  image_generation: imageGeneration,
85
- background_agent: backgroundAgent,
86
- background_shell: backgroundShell,
87
- execution: { selected_mode: selectAssetExecutionMode(backgroundAgent, backgroundShell), ...getAssetExecutionContract() },
88
79
  requires_host_tool_inventory_check: capabilities.some(item => item.status === 'unknown'),
89
80
  declaration_env: { ...CAPABILITY_ENV },
90
81
  detection_policy:
91
- 'Explicit declarations override runtime defaults. QwenWork provides image generation, and verified non-cloud runtimes provide online and image search. Managed-cloud or unknown runtimes use the host tool inventory. Background agent and shell execution are separate capabilities; neither is inferred from host name. Declarations must match actual nonblocking tool semantics.',
82
+ 'Explicit declarations override runtime defaults. QwenWork provides image generation, and verified non-cloud runtimes provide online and image search. Managed-cloud or unknown runtimes use the host tool inventory.',
92
83
  };
93
84
  }
94
85
 
@@ -43,12 +43,6 @@ function requestOnce(rawUrl, options = {}) {
43
43
  ...(method === 'GET' ? { Range: `bytes=0-${MAX_HEADER_BYTES - 1}` } : {}),
44
44
  },
45
45
  }, (res) => {
46
- // Redirects and denied requests need no response-body download.
47
- if (res.statusCode < 200 || res.statusCode >= 300) {
48
- resolve({ status: res.statusCode || 0, headers: res.headers || {}, body: Buffer.alloc(0) });
49
- res.destroy();
50
- return;
51
- }
52
46
  if (method !== 'GET') {
53
47
  resolve({ status: res.statusCode || 0, headers: res.headers || {}, body: Buffer.alloc(0) });
54
48
  return;
@@ -78,10 +72,7 @@ function requestOnce(rawUrl, options = {}) {
78
72
  });
79
73
  res.on('end', finish);
80
74
  res.on('error', reject);
81
- res.on('aborted', () => reject(new Error('DOWNLOAD_ABORTED')));
82
75
  });
83
- const timer = setTimeout(() => req.destroy(new Error('TIMEOUT')), timeout);
84
- req.on('close', () => clearTimeout(timer));
85
76
  req.setTimeout(timeout, () => req.destroy(new Error('TIMEOUT')));
86
77
  req.on('error', reject);
87
78
  req.end();
@@ -89,12 +80,8 @@ function requestOnce(rawUrl, options = {}) {
89
80
  }
90
81
 
91
82
  async function requestFollow(rawUrl, options, depth = 0) {
92
- if (options.allowUrl && !options.allowUrl(rawUrl)) {throw new Error('STOCK_PROVIDER_REDIRECT_NOT_ALLOWED');}
93
- const timeout = options.deadline - Date.now();
94
- if (timeout <= 0) {throw new Error('TIMEOUT');}
95
- const response = await requestOnce(rawUrl, { ...options, timeout });
96
- if (response.status >= 300 && response.status < 400 && response.headers.location) {
97
- if (depth >= MAX_REDIRECTS) {throw new Error('TOO_MANY_REDIRECTS');}
83
+ const response = await requestOnce(rawUrl, options);
84
+ if (response.status >= 300 && response.status < 400 && response.headers.location && depth < MAX_REDIRECTS) {
98
85
  const next = new URL(response.headers.location, rawUrl).toString();
99
86
  return requestFollow(next, options, depth + 1);
100
87
  }
@@ -121,9 +108,7 @@ async function verifyImageUrl(rawUrl, options = {}) {
121
108
 
122
109
  let response;
123
110
  try {
124
- response = await requestFollow(trimmed, {
125
- method: 'GET', deadline: Date.now() + (options.timeout || DEFAULT_TIMEOUT), allowUrl: options.allowUrl,
126
- });
111
+ response = await requestFollow(trimmed, { method: 'GET', timeout: options.timeout });
127
112
  } catch (error) {
128
113
  return { ...base, url: trimmed, reason: normalizeError(error) };
129
114
  }
@@ -180,7 +165,7 @@ async function verifyImageUrls(urls, options = {}) {
180
165
 
181
166
  function normalizeError(error) {
182
167
  const message = (error && error.message) || String(error);
183
- if (['TIMEOUT', 'INVALID_URL', 'UNSUPPORTED_PROTOCOL', 'STOCK_PROVIDER_REDIRECT_NOT_ALLOWED', 'TOO_MANY_REDIRECTS', 'DOWNLOAD_ABORTED'].includes(message)) {return message;}
168
+ if (['TIMEOUT', 'INVALID_URL', 'UNSUPPORTED_PROTOCOL'].includes(message)) {return message;}
184
169
  return (error && error.code) || 'REQUEST_FAILED';
185
170
  }
186
171
 
@@ -0,0 +1,145 @@
1
+ 'use strict';
2
+
3
+ const { CliError } = require('../core/cli-error');
4
+ const { DINGTALK_OAUTH_CLIENT_ID } = require('../core/env-manager');
5
+ const { requestJson, resolveTokenBaseUrl, normalizeTokenResponse } = require('./token-auth');
6
+ const { isEnvTokenAuthMode, hasEnvTokenCredential, saveDwsTokenSession } = require('./token-store');
7
+
8
+ const FAILURE_STATUSES = new Set([
9
+ 'dws_not_enabled', 'invalid_dws_token', 'unsupported_dws_source', 'insufficient_dws_scope',
10
+ 'dws_identity_unmapped', 'dws_upstream_unavailable', 'dws_policy_rejected', 'dws_session_expired',
11
+ ]);
12
+
13
+ function failure(reason) {
14
+ return new CliError(`DWS sync failed: ${reason}`, {
15
+ code: 'DWS_SYNC_FAILED', details: { reason },
16
+ });
17
+ }
18
+
19
+ function readHandoff(input = process.stdin, timeoutMs = 10000) {
20
+ return new Promise((resolve, reject) => {
21
+ if (input.isTTY) { reject(failure('STDIN_REQUIRED')); return; }
22
+ let chunks = [];
23
+ let size = 0;
24
+ const finish = (error, value) => {
25
+ clearTimeout(timer);
26
+ input.removeListener('data', onData);
27
+ input.removeListener('end', onEnd);
28
+ input.removeListener('error', onError);
29
+ input.pause();
30
+ chunks = [];
31
+ if (error) { reject(error); } else { resolve(value); }
32
+ };
33
+ const onData = (chunk) => {
34
+ const bytes = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
35
+ size += bytes.length;
36
+ if (size > 16384) { finish(failure('HANDOFF_TOO_LARGE')); return; }
37
+ chunks.push(bytes);
38
+ };
39
+ const onError = () => finish(failure('HANDOFF_READ_FAILED'));
40
+ const onEnd = () => {
41
+ let data;
42
+ try { data = JSON.parse(Buffer.concat(chunks).toString('utf8')); } catch {
43
+ finish(failure('INVALID_HANDOFF')); return;
44
+ }
45
+ if (!data || typeof data !== 'object' || Array.isArray(data)
46
+ || Object.keys(data).some((key) => !['accessToken', 'corpId', 'environment'].includes(key))
47
+ || typeof data.accessToken !== 'string' || !data.accessToken || data.accessToken.length > 8192
48
+ || (/\s/.test(data.accessToken) || [...data.accessToken].some((char) => char.charCodeAt(0) < 32 || char.charCodeAt(0) === 127))
49
+ || typeof data.corpId !== 'string' || !data.corpId || data.corpId.length > 256
50
+ || !['pre', 'prod'].includes(data.environment)) {
51
+ finish(failure('INVALID_HANDOFF')); return;
52
+ }
53
+ finish(null, data);
54
+ };
55
+ const timer = setTimeout(() => finish(failure('HANDOFF_TIMEOUT')), timeoutMs);
56
+ input.on('data', onData);
57
+ input.on('end', onEnd);
58
+ input.on('error', onError);
59
+ });
60
+ }
61
+
62
+ async function syncDws(options = {}) {
63
+ const env = options.env || process.env;
64
+ if (isEnvTokenAuthMode(env) || hasEnvTokenCredential(env)
65
+ || options.authProfile || options.profile || options.userId
66
+ || env.OPENYIDA_AUTH_PROFILE || env.OPENYIDA_AUTH_USER_ID || env.OPENYIDA_AUTH_CORP_ID) {
67
+ throw failure('AUTH_OVERRIDE_CONFLICT');
68
+ }
69
+ const clientId = options.clientId || env.OPENYIDA_DINGTALK_CLIENT_ID || DINGTALK_OAUTH_CLIENT_ID;
70
+ if (clientId !== DINGTALK_OAUTH_CLIENT_ID) { throw failure('CLIENT_CONFLICT'); }
71
+ const baseUrl = resolveTokenBaseUrl(options);
72
+ const target = new URL(baseUrl);
73
+ if (target.protocol !== 'https:' || target.username || target.password || target.search || target.hash
74
+ || target.pathname !== '/') { throw failure('TRUSTED_HTTPS_ORIGIN_REQUIRED'); }
75
+ const handoff = await readHandoff(options.input || process.stdin, options.stdinTimeoutMs);
76
+ if (options.corpId && options.corpId !== handoff.corpId) { throw failure('ORG_CONFLICT'); }
77
+ let response;
78
+ try {
79
+ response = await requestJson('POST', `${target.origin}/openapi/cli/v1/auth/dws/token`, {
80
+ corpId: handoff.corpId, environment: handoff.environment,
81
+ }, { Authorization: `Bearer ${handoff.accessToken}` }, { timeoutMs: 30000, maxResponseBytes: 65536 });
82
+ } catch {
83
+ throw failure('EXCHANGE_REQUEST_FAILED');
84
+ } finally {
85
+ delete handoff.accessToken;
86
+ }
87
+ const data = response && (response.data || response.content || response);
88
+ if (!data || response.success === false || response.ok === false || data.status !== 'ok') {
89
+ throw failure(data && FAILURE_STATUSES.has(data.status) ? data.status : 'EXCHANGE_REJECTED');
90
+ }
91
+ const session = normalizeTokenResponse(response, baseUrl, clientId);
92
+ const now = Date.now() / 1000;
93
+ if (typeof data.access_token !== 'string' || !data.access_token
94
+ || typeof data.refresh_token !== 'string' || !data.refresh_token
95
+ || data.client_id !== DINGTALK_OAUTH_CLIENT_ID || data.corp_id !== handoff.corpId
96
+ || typeof data.user_id !== 'string' || !data.user_id
97
+ || data.credential_source !== 'dws' || data.environment !== handoff.environment
98
+ || typeof data.session_id !== 'string' || !/^[a-f0-9-]{36}$/.test(data.session_id)
99
+ || !Number.isInteger(data.session_expires_at) || data.session_expires_at <= now
100
+ || !Number.isInteger(data.expires_in) || data.expires_in <= 0
101
+ || data.expires_in > data.session_expires_at - now + 2) {
102
+ throw failure('INVALID_EXCHANGE_RESPONSE');
103
+ }
104
+ const business = new URL(session.base_url);
105
+ // Token-bearing business requests must remain within this configured environment.
106
+ if (business.origin !== target.origin) { throw failure('ENVIRONMENT_MISMATCH'); }
107
+ delete session.raw;
108
+ delete session.message;
109
+ session.auth_base_url = target.origin;
110
+ session.credential_source = 'dws';
111
+ session.session_id = data.session_id;
112
+ session.session_expires_at = data.session_expires_at;
113
+ session.environment = data.environment;
114
+ let saved;
115
+ try {
116
+ saved = saveDwsTokenSession(session, options);
117
+ } catch {
118
+ // Best-effort revoke only the newly issued session; never touch an existing profile.
119
+ try {
120
+ await requestJson('POST', `${target.origin}/openapi/cli/v1/auth/logout`, {
121
+ refreshToken: session.refresh_token,
122
+ }, { Authorization: `Bearer ${session.access_token}` }, { timeoutMs: 10000, maxResponseBytes: 65536 });
123
+ } catch { /* The fixed server deadline still bounds an unreachable session. */ }
124
+ throw failure('PERSISTENCE_FAILED');
125
+ }
126
+ return { ok: true, status: 'ready', auth_profile: saved.auth_profile,
127
+ corp_id: saved.corp_id, user_id: saved.user_id };
128
+ }
129
+
130
+ async function run(args, options = {}) {
131
+ if (args.length === 2 && args.includes('--capabilities') && args.includes('--json')) {
132
+ const capabilities = { protocol_version: 1, private_stdin: true, independent_profile: true };
133
+ console.log(JSON.stringify(capabilities));
134
+ return capabilities;
135
+ }
136
+ if (!args.includes('--stdin') || !args.includes('--json')
137
+ || args.some((arg) => !['--stdin', '--json'].includes(arg))) {
138
+ throw failure('USE_AUTH_SYNC_DWS_STDIN_JSON');
139
+ }
140
+ const result = await syncDws(options);
141
+ console.log(JSON.stringify(result));
142
+ return result;
143
+ }
144
+
145
+ module.exports = { run, syncDws, readHandoff };
@@ -25,6 +25,7 @@ const {
25
25
  resolveTokenSession,
26
26
  saveBusinessContext,
27
27
  saveTokenSession,
28
+ saveDwsTokenSession,
28
29
  } = require('./token-store');
29
30
 
30
31
  const DEFAULT_AUTH_PATH_PREFIX = '/openapi/cli/v1/auth';
@@ -83,7 +84,7 @@ function resolveDingtalkLoginOrigin(options = {}) {
83
84
  return DINGTALK_LOGIN_ORIGIN;
84
85
  }
85
86
 
86
- function requestJson(method, url, body, headers = {}) {
87
+ function requestJson(method, url, body, headers = {}, options = {}) {
87
88
  return new Promise((resolve, reject) => {
88
89
  const parsedUrl = new URL(url);
89
90
  const data = body === undefined || body === null ? null : Buffer.from(JSON.stringify(body));
@@ -104,7 +105,16 @@ function requestJson(method, url, body, headers = {}) {
104
105
  },
105
106
  }, (response) => {
106
107
  const chunks = [];
107
- response.on('data', (chunk) => chunks.push(chunk));
108
+ let size = 0;
109
+ response.on('error', reject);
110
+ response.on('data', (chunk) => {
111
+ size += chunk.length;
112
+ if (options.maxResponseBytes && size > options.maxResponseBytes) {
113
+ response.destroy(new Error('response_too_large'));
114
+ return;
115
+ }
116
+ chunks.push(chunk);
117
+ });
108
118
  response.on('end', () => {
109
119
  const text = Buffer.concat(chunks).toString('utf8');
110
120
  let payload = null;
@@ -132,6 +142,10 @@ function requestJson(method, url, body, headers = {}) {
132
142
  });
133
143
  });
134
144
 
145
+ if (options.timeoutMs > 0) {
146
+ const timer = setTimeout(() => request.destroy(new Error('request_timeout')), options.timeoutMs);
147
+ request.once('close', () => clearTimeout(timer));
148
+ }
135
149
  request.on('error', reject);
136
150
  if (data) {
137
151
  request.write(data);
@@ -368,6 +382,16 @@ function tokenStatus(options = {}) {
368
382
  }
369
383
  return status;
370
384
  }
385
+ if (session.credential_source === 'dws'
386
+ && (!Number.isInteger(session.session_expires_at) || session.session_expires_at <= Date.now() / 1000)) {
387
+ return {
388
+ ok: false, status: 'expired', can_auto_use: false, auth_mode: 'token',
389
+ auth_source: session.auth_source, auth_store: session.auth_store, auth_profile: session.auth_profile,
390
+ base_url: session.base_url, credential_source: 'dws', environment: session.environment,
391
+ session_expires_at: session.session_expires_at, corp_id: session.corp_id, user_id: session.user_id,
392
+ failure_reason: 'dws_session_expired',
393
+ };
394
+ }
371
395
  if (!session.access_token && session.refresh_token) {
372
396
  return {
373
397
  ok: true,
@@ -381,6 +405,9 @@ function tokenStatus(options = {}) {
381
405
  status: 'ok',
382
406
  can_auto_use: true,
383
407
  refresh_token: maskToken(session.refresh_token),
408
+ credential_source: session.credential_source,
409
+ environment: session.environment,
410
+ session_expires_at: session.session_expires_at,
384
411
  base_url: session.base_url,
385
412
  corp_id: session.corp_id,
386
413
  corp_name: session.corp_name,
@@ -404,6 +431,9 @@ function tokenStatus(options = {}) {
404
431
  access_token: maskToken(session.access_token),
405
432
  refresh_token: maskToken(session.refresh_token),
406
433
  expires_at: session.expires_at ? new Date(session.expires_at).toISOString() : undefined,
434
+ credential_source: session.credential_source,
435
+ environment: session.environment,
436
+ session_expires_at: session.session_expires_at,
407
437
  base_url: session.base_url,
408
438
  corp_id: session.corp_id,
409
439
  corp_name: session.corp_name,
@@ -427,17 +457,31 @@ async function tokenRefresh(options = {}) {
427
457
  // Token exchange follows the active environment endpoint, just like the
428
458
  // legacy login bootstrap. The response may return a different corp base_url
429
459
  // for business requests and generated application links.
430
- const authBaseUrlValue = resolveTokenBaseUrl({
460
+ const authBaseUrlValue = (session.credential_source === 'dws' && session.auth_base_url) || resolveTokenBaseUrl({
431
461
  projectRoot: options.projectRoot,
432
462
  endpoint: options.endpoint,
433
463
  });
434
464
  const authBaseUrl = appendPath(authBaseUrlValue, DEFAULT_AUTH_PATH_PREFIX);
435
465
  const clientId = options.clientId || session.client_id || DINGTALK_OAUTH_CLIENT_ID;
436
- const response = await requestJson('POST', appendPath(authBaseUrl, '/refresh'), {
437
- refreshToken: session.refresh_token,
438
- clientId,
439
- });
440
- requireOkResponse(response);
466
+ let response;
467
+ if (session.credential_source === 'dws') {
468
+ try {
469
+ response = await requestJson('POST', appendPath(authBaseUrl, '/refresh'), {
470
+ refreshToken: session.refresh_token, clientId,
471
+ }, {}, { timeoutMs: 30000, maxResponseBytes: 65536 });
472
+ requireOkResponse(response);
473
+ } catch (error) {
474
+ if (isRefreshAuthRequired(error)) {
475
+ throw createTokenAuthRequiredError('invalid_refresh_token');
476
+ }
477
+ throw createTokenRefreshFailedError('refresh_request_failed');
478
+ }
479
+ } else {
480
+ response = await requestJson('POST', appendPath(authBaseUrl, '/refresh'), {
481
+ refreshToken: session.refresh_token, clientId,
482
+ });
483
+ requireOkResponse(response);
484
+ }
441
485
  const data = getTokenPayload(response);
442
486
  const responseBusinessBaseUrl = data.base_url || data.baseUrl;
443
487
  const businessBaseUrl = session.base_url || authBaseUrlValue;
@@ -450,6 +494,9 @@ async function tokenRefresh(options = {}) {
450
494
  refresh_token: data.refresh_token || data.refreshToken || session.refresh_token,
451
495
  }, businessBaseUrl, clientId);
452
496
  if (!normalized.access_token) {
497
+ if (session.credential_source === 'dws') {
498
+ throw createTokenRefreshFailedError('refresh_response_invalid');
499
+ }
453
500
  return {
454
501
  ...normalized,
455
502
  ok: false,
@@ -458,6 +505,23 @@ async function tokenRefresh(options = {}) {
458
505
  message: normalized.message || 'auth service did not return access_token',
459
506
  };
460
507
  }
508
+ if (session.credential_source === 'dws') {
509
+ if (normalized.corp_id !== session.corp_id || normalized.user_id !== session.user_id
510
+ || data.client_id !== session.client_id || data.credential_source !== 'dws'
511
+ || data.session_id !== session.session_id || data.session_expires_at !== session.session_expires_at
512
+ || data.environment !== session.environment || !data.refresh_token
513
+ || normalized.base_url !== session.base_url
514
+ || !Number.isInteger(data.expires_in) || data.expires_in <= 0
515
+ || data.expires_in > session.session_expires_at - Date.now() / 1000 + 2) {
516
+ throw createTokenAuthRequiredError('dws_refresh_identity_mismatch');
517
+ }
518
+ delete normalized.raw;
519
+ delete normalized.message;
520
+ return saveDwsTokenSession({ ...normalized, credential_source: 'dws',
521
+ auth_base_url: session.auth_base_url, session_id: session.session_id,
522
+ session_expires_at: session.session_expires_at, environment: session.environment,
523
+ }, { ...options, bindProject: false });
524
+ }
461
525
  if (responseBusinessBaseUrl && normalized.corp_id) {
462
526
  try {
463
527
  saveBusinessContext({
@@ -492,7 +556,7 @@ async function revokeTokenSession(session) {
492
556
  return;
493
557
  }
494
558
  try {
495
- await requestJson('POST', appendPath(appendPath(session.base_url, DEFAULT_AUTH_PATH_PREFIX), '/logout'), {
559
+ await requestJson('POST', appendPath(appendPath(session.auth_base_url || session.base_url, DEFAULT_AUTH_PATH_PREFIX), '/logout'), {
496
560
  refreshToken: session.refresh_token,
497
561
  }, session.access_token ? {
498
562
  authorization: `${session.token_type || 'Bearer'} ${session.access_token}`,
@@ -290,6 +290,11 @@ function normalizeTokenSession(session = {}) {
290
290
  open_user_id: session.open_user_id || session.openUserId,
291
291
  scope: session.scope,
292
292
  last_used_at: session.last_used_at || session.lastUsedAt || session.updated_at || session.updatedAt,
293
+ credential_source: session.credential_source,
294
+ session_id: session.session_id,
295
+ session_expires_at: session.session_expires_at,
296
+ environment: session.environment,
297
+ auth_base_url: session.auth_base_url,
293
298
  auth_source: session.auth_source || session.authSource,
294
299
  auth_store: session.auth_store || session.authStore,
295
300
  auth_profile: session.auth_profile || session.authProfile,
@@ -594,6 +599,50 @@ function saveUserTokenSession(session, options = {}) {
594
599
  return profileSession;
595
600
  }
596
601
 
602
+ function saveDwsTokenSession(session, options = {}) {
603
+ const normalized = normalizeTokenSession(session);
604
+ const identity = buildAuthProfileIdentity(normalized);
605
+ if (!identity || normalized.credential_source !== 'dws' || !normalized.session_id
606
+ || !normalized.auth_base_url || !normalized.refresh_token) {
607
+ throw new Error('dws_profile_incomplete');
608
+ }
609
+ // Isolate independent login and each server-side DWS session, including same user/corp.
610
+ const authProfile = crypto.createHash('sha256').update(JSON.stringify({
611
+ ...identity, credential_source: 'dws', session_id: normalized.session_id,
612
+ auth_base_url: normalized.auth_base_url,
613
+ })).digest('hex').slice(0, 32);
614
+ const saved = normalizeTokenSession({ ...normalized, auth_profile: authProfile,
615
+ auth_source: 'user_profile', auth_store: 'user', persistence_scope: 'user' });
616
+ const file = getUserProfileFilePath(authProfile, options);
617
+ const previous = fs.existsSync(file) ? JSON.parse(fs.readFileSync(file, 'utf8')) : null;
618
+ const previousPointer = loadAuthProfilePointer(options);
619
+ try {
620
+ writeJsonFileAtomic(file, saved);
621
+ const readback = loadUserProfileFile(authProfile, options);
622
+ if (!readback || readback.access_token !== saved.access_token || readback.refresh_token !== saved.refresh_token) {
623
+ throw new Error('dws_profile_readback_failed');
624
+ }
625
+ // Refresh a pinned running command's session without switching a newer project binding.
626
+ if (options.bindProject !== false) {
627
+ saveAuthProfilePointer(saved, options);
628
+ const effective = loadTokenSession(options);
629
+ if (!effective || effective.auth_profile !== authProfile || effective.access_token !== saved.access_token) {
630
+ throw new Error('dws_binding_readback_failed');
631
+ }
632
+ }
633
+ return saved;
634
+ } catch (error) {
635
+ const current = loadAuthProfilePointer(options);
636
+ if (current && current.auth_profile === authProfile) {
637
+ if (previousPointer) { writeJsonFileAtomic(getAuthProfilePointerFilePath(options), previousPointer); }
638
+ else { clearAuthProfilePointer(options); }
639
+ }
640
+ if (previous) { writeJsonFileAtomic(file, previous); }
641
+ else if (fs.existsSync(file)) { fs.unlinkSync(file); }
642
+ throw error;
643
+ }
644
+ }
645
+
597
646
  function saveTokenSession(session, options = {}) {
598
647
  const env = options.env || process.env;
599
648
  const normalized = normalizeTokenSession(session);
@@ -995,6 +1044,7 @@ module.exports = {
995
1044
  loadTokenSession,
996
1045
  resolveTokenSession,
997
1046
  saveTokenSession,
1047
+ saveDwsTokenSession,
998
1048
  loadBusinessContext,
999
1049
  saveBusinessContext,
1000
1050
  loadAuthProfilePointer,