@yss123/cage-cli 0.2.0 → 0.3.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 (629) hide show
  1. package/README.md +47 -3
  2. package/bin/cage.js +5 -0
  3. package/bin/create-cage-app.js +5 -0
  4. package/dist/analyze.d.ts +16 -0
  5. package/dist/analyze.js +18 -2
  6. package/dist/analyze.js.map +1 -1
  7. package/dist/approval-tree.d.ts +88 -0
  8. package/dist/approval-tree.js +18 -0
  9. package/dist/approval-tree.js.map +1 -0
  10. package/dist/baseline.d.ts +8 -0
  11. package/dist/baseline.js +13 -0
  12. package/dist/baseline.js.map +1 -1
  13. package/dist/bootstrap.d.ts +20 -0
  14. package/dist/bootstrap.js +75 -0
  15. package/dist/bootstrap.js.map +1 -0
  16. package/dist/budget.d.ts +7 -0
  17. package/dist/budget.js +49 -5
  18. package/dist/budget.js.map +1 -1
  19. package/dist/capabilities.d.ts +38 -0
  20. package/dist/capabilities.js +148 -0
  21. package/dist/capabilities.js.map +1 -0
  22. package/dist/config.d.ts +31 -2
  23. package/dist/config.js +22 -0
  24. package/dist/config.js.map +1 -1
  25. package/dist/context.d.ts +14 -0
  26. package/dist/context.js +35 -2
  27. package/dist/context.js.map +1 -1
  28. package/dist/create-prompt.d.ts +7 -0
  29. package/dist/create-prompt.js +12 -0
  30. package/dist/create-prompt.js.map +1 -1
  31. package/dist/create.d.ts +21 -1
  32. package/dist/create.js +23 -1
  33. package/dist/create.js.map +1 -1
  34. package/dist/derive.d.ts +23 -0
  35. package/dist/derive.js +40 -0
  36. package/dist/derive.js.map +1 -1
  37. package/dist/dev.d.ts +6 -0
  38. package/dist/dev.js +11 -0
  39. package/dist/dev.js.map +1 -1
  40. package/dist/doctor.d.ts +98 -0
  41. package/dist/doctor.js +93 -0
  42. package/dist/doctor.js.map +1 -0
  43. package/dist/env.d.ts +6 -0
  44. package/dist/env.js +11 -0
  45. package/dist/env.js.map +1 -1
  46. package/dist/findings.d.ts +27 -0
  47. package/dist/findings.js +20 -0
  48. package/dist/findings.js.map +1 -1
  49. package/dist/gen/contracts.d.ts +28 -0
  50. package/dist/gen/contracts.js +52 -12
  51. package/dist/gen/contracts.js.map +1 -1
  52. package/dist/gen/index.d.ts +26 -0
  53. package/dist/gen/index.js +69 -1
  54. package/dist/gen/index.js.map +1 -1
  55. package/dist/gen/zod-code.d.ts +42 -0
  56. package/dist/gen/zod-code.js +178 -16
  57. package/dist/gen/zod-code.js.map +1 -1
  58. package/dist/graph-approvals.d.ts +70 -0
  59. package/dist/graph-approvals.js +93 -0
  60. package/dist/graph-approvals.js.map +1 -0
  61. package/dist/graph-business.d.ts +135 -0
  62. package/dist/graph-business.js +404 -0
  63. package/dist/graph-business.js.map +1 -0
  64. package/dist/graph-command.d.ts +17 -0
  65. package/dist/graph-command.js +21 -0
  66. package/dist/graph-command.js.map +1 -1
  67. package/dist/graph-model.d.ts +44 -0
  68. package/dist/graph-model.js +36 -3
  69. package/dist/graph-model.js.map +1 -1
  70. package/dist/graph-presentation.d.ts +16 -0
  71. package/dist/graph-presentation.js +10 -1
  72. package/dist/graph-presentation.js.map +1 -1
  73. package/dist/graph-query.d.ts +95 -0
  74. package/dist/graph-query.js +62 -0
  75. package/dist/graph-query.js.map +1 -1
  76. package/dist/graph-relations.d.ts +20 -0
  77. package/dist/graph-relations.js +42 -10
  78. package/dist/graph-relations.js.map +1 -1
  79. package/dist/graph-search.d.ts +35 -0
  80. package/dist/graph-search.js +36 -0
  81. package/dist/graph-search.js.map +1 -1
  82. package/dist/graph-snapshot.d.ts +26 -0
  83. package/dist/graph-snapshot.js +30 -1
  84. package/dist/graph-snapshot.js.map +1 -1
  85. package/dist/graph.d.ts +13 -2
  86. package/dist/graph.js +61 -4
  87. package/dist/graph.js.map +1 -1
  88. package/dist/impact.d.ts +50 -0
  89. package/dist/impact.js +62 -2
  90. package/dist/impact.js.map +1 -1
  91. package/dist/index.d.ts +10 -0
  92. package/dist/index.js +10 -0
  93. package/dist/index.js.map +1 -1
  94. package/dist/init.d.ts +12 -0
  95. package/dist/init.js +15 -0
  96. package/dist/init.js.map +1 -1
  97. package/dist/load.d.ts +10 -0
  98. package/dist/load.js +15 -0
  99. package/dist/load.js.map +1 -1
  100. package/dist/main.d.ts +6 -0
  101. package/dist/main.js +93 -5
  102. package/dist/main.js.map +1 -1
  103. package/dist/migrate.d.ts +12 -0
  104. package/dist/migrate.js +17 -0
  105. package/dist/migrate.js.map +1 -1
  106. package/dist/ontology.d.ts +67 -2
  107. package/dist/ontology.js +94 -4
  108. package/dist/ontology.js.map +1 -1
  109. package/dist/process-rules.d.ts +21 -0
  110. package/dist/process-rules.js +100 -0
  111. package/dist/process-rules.js.map +1 -0
  112. package/dist/process.d.ts +32 -0
  113. package/dist/process.js +32 -0
  114. package/dist/process.js.map +1 -1
  115. package/dist/project-structure.d.ts +5 -0
  116. package/dist/project-structure.js +10 -0
  117. package/dist/project-structure.js.map +1 -1
  118. package/dist/registration.d.ts +16 -0
  119. package/dist/registration.js +56 -0
  120. package/dist/registration.js.map +1 -0
  121. package/dist/rules.d.ts +52 -0
  122. package/dist/rules.js +58 -0
  123. package/dist/rules.js.map +1 -1
  124. package/dist/runtime-diagnostics.d.ts +27 -0
  125. package/dist/runtime-diagnostics.js +60 -0
  126. package/dist/runtime-diagnostics.js.map +1 -0
  127. package/dist/snapshots.d.ts +40 -0
  128. package/dist/snapshots.js +62 -0
  129. package/dist/snapshots.js.map +1 -0
  130. package/dist/static-check.d.ts +33 -0
  131. package/dist/static-check.js +37 -1
  132. package/dist/static-check.js.map +1 -1
  133. package/dist/sync.d.ts +11 -0
  134. package/dist/sync.js +66 -9
  135. package/dist/sync.js.map +1 -1
  136. package/dist/upgrade.d.ts +16 -0
  137. package/dist/upgrade.js +21 -0
  138. package/dist/upgrade.js.map +1 -1
  139. package/dist/verify.d.ts +14 -0
  140. package/dist/verify.js +19 -0
  141. package/dist/verify.js.map +1 -1
  142. package/dist/version.js +5 -0
  143. package/dist/version.js.map +1 -1
  144. package/graph-ui/app.js +321 -27
  145. package/graph-ui/approval-flow.js +185 -0
  146. package/graph-ui/approval-parallel.js +110 -0
  147. package/graph-ui/approval-tree.js +17 -0
  148. package/graph-ui/business.css +1011 -0
  149. package/graph-ui/business.js +566 -0
  150. package/graph-ui/flowchart-interaction.js +177 -0
  151. package/graph-ui/flowchart.js +1059 -0
  152. package/graph-ui/graph-approvals.js +92 -0
  153. package/graph-ui/graph-business.js +403 -0
  154. package/graph-ui/graph-model.js +36 -3
  155. package/graph-ui/graph-relations.js +42 -10
  156. package/graph-ui/graph-search.js +36 -0
  157. package/graph-ui/index.html +26 -12
  158. package/graph-ui/model.js +28 -0
  159. package/graph-ui/relations.js +4 -0
  160. package/graph-ui/structure.js +44 -0
  161. package/graph-ui/style.css +12 -0
  162. package/package.json +6 -4
  163. package/templates/app/.dockerignore +2 -0
  164. package/templates/app/.env.example +10 -0
  165. package/templates/app/AGENTS.md +50 -10
  166. package/templates/app/README.md +9 -5
  167. package/templates/app/_gitignore +1 -0
  168. package/templates/app/apps/api/package.json +2 -2
  169. package/templates/app/apps/api/src/main.ts +5 -1
  170. package/templates/app/apps/api/src/worker.ts +3 -0
  171. package/templates/app/apps/web/index.html +1 -0
  172. package/templates/app/apps/web/package.json +7 -3
  173. package/templates/app/apps/web/src/app/app.tsx +122 -12
  174. package/templates/app/apps/web/src/app/styles/global.css +88 -8
  175. package/templates/app/apps/web/src/app/use-session.ts +43 -0
  176. package/templates/app/apps/web/src/app/workspace-layout.tsx +58 -19
  177. package/templates/app/apps/web/src/main.tsx +5 -0
  178. package/templates/app/apps/web/src/modules/approval/components/task-operation-dialog.tsx +61 -0
  179. package/templates/app/apps/web/src/modules/approval/hooks/use-approval-tasks.ts +13 -5
  180. package/templates/app/apps/web/src/modules/approval/index.ts +4 -0
  181. package/templates/app/apps/web/src/modules/approval/pages/approval-tasks-page.tsx +89 -38
  182. package/templates/app/apps/web/src/modules/approval/pages/approval-tasks.css +18 -0
  183. package/templates/app/apps/web/src/modules/auth/index.ts +4 -0
  184. package/templates/app/apps/web/src/modules/auth/pages/login-page.tsx +12 -0
  185. package/templates/app/apps/web/src/modules/inventory/index.ts +4 -0
  186. package/templates/app/apps/web/src/modules/inventory/pages/inventory-page.tsx +29 -1
  187. package/templates/app/apps/web/src/modules/purchase/components/approval-history.tsx +67 -0
  188. package/templates/app/apps/web/src/modules/purchase/components/order-attachments.tsx +29 -0
  189. package/templates/app/apps/web/src/modules/purchase/components/order-reviewers.tsx +38 -0
  190. package/templates/app/apps/web/src/modules/purchase/components/purchase-assistant-context.tsx +17 -0
  191. package/templates/app/apps/web/src/modules/purchase/components/purchase-order-form.css +6 -0
  192. package/templates/app/apps/web/src/modules/purchase/components/purchase-order-form.tsx +32 -3
  193. package/templates/app/apps/web/src/modules/purchase/index.ts +5 -0
  194. package/templates/app/apps/web/src/modules/purchase/lib/presentation.ts +20 -0
  195. package/templates/app/apps/web/src/modules/purchase/pages/purchase-intelligence.css +17 -0
  196. package/templates/app/apps/web/src/modules/purchase/pages/purchase-order-detail-page.tsx +156 -0
  197. package/templates/app/apps/web/src/modules/purchase/pages/purchase-orders-page.tsx +54 -22
  198. package/templates/app/apps/web/src/modules/workspace/index.ts +5 -0
  199. package/templates/app/apps/web/src/modules/workspace/pages/home-page.tsx +44 -0
  200. package/templates/app/apps/web/src/shared/hooks/use-command.ts +13 -0
  201. package/templates/app/apps/web/src/shared/lib/error-message.ts +15 -1
  202. package/templates/app/apps/web/src/shared/lib/navigation.ts +21 -0
  203. package/templates/app/apps/web/src/shared/ui/approval-member-picker.css +10 -0
  204. package/templates/app/apps/web/src/shared/ui/approval-member-picker.tsx +51 -0
  205. package/templates/app/apps/web/src/shared/ui/assistant-markdown.tsx +19 -0
  206. package/templates/app/apps/web/src/shared/ui/assistant-panel.css +134 -0
  207. package/templates/app/apps/web/src/shared/ui/assistant-panel.tsx +200 -0
  208. package/templates/app/apps/web/src/shared/ui/assistant-scope.tsx +72 -0
  209. package/templates/app/apps/web/src/shared/ui/attachment-upload.css +28 -0
  210. package/templates/app/apps/web/src/shared/ui/attachment-upload.tsx +163 -0
  211. package/templates/app/apps/web/src/shared/ui/notice.tsx +7 -0
  212. package/templates/app/apps/web/src/shared/ui/page-heading.tsx +7 -0
  213. package/templates/app/apps/web/src/shared/ui/page-state.css +47 -0
  214. package/templates/app/apps/web/src/shared/ui/page-state.tsx +76 -0
  215. package/templates/app/apps/web/src/shared/ui/require-capability.tsx +34 -0
  216. package/templates/app/apps/web/vite.config.ts +5 -0
  217. package/templates/app/cage.config.json +23 -0
  218. package/templates/app/db/migrations/0002_draft.sql +12 -0
  219. package/templates/app/db/migrations/0003_draft.sql +8 -0
  220. package/templates/app/db/migrations/0004_draft.sql +27 -0
  221. package/templates/app/deploy/nginx.conf +52 -0
  222. package/templates/app/docs/ai/README.md +28 -2
  223. package/templates/app/docs/ai/approvals.md +260 -0
  224. package/templates/app/docs/ai/architecture.md +26 -0
  225. package/templates/app/docs/ai/commenting.md +203 -0
  226. package/templates/app/docs/ai/diagnostics.md +80 -0
  227. package/templates/app/docs/ai/files.md +93 -0
  228. package/templates/app/docs/ai/intelligence.md +348 -0
  229. package/templates/app/docs/ai/ontology-context.md +59 -4
  230. package/templates/app/docs/ai/primitives.md +34 -1
  231. package/templates/app/docs/ai/project-structure.md +8 -3
  232. package/templates/app/docs/ai/purchase-example.md +35 -7
  233. package/templates/app/docs/ai/recipes.md +10 -2
  234. package/templates/app/docs/ai/routing.md +86 -0
  235. package/templates/app/docs/ai/troubleshooting.md +5 -0
  236. package/templates/app/docs/ai/workflow.md +24 -11
  237. package/templates/app/docs/errors/CAGE-AI-001.md +61 -0
  238. package/templates/app/docs/errors/CAGE-APPR-001.md +13 -9
  239. package/templates/app/docs/errors/CAGE-APPR-002.md +2 -2
  240. package/templates/app/docs/errors/CAGE-APPR-003.md +1 -1
  241. package/templates/app/docs/errors/CAGE-APPR-004.md +4 -4
  242. package/templates/app/docs/errors/CAGE-APPR-005.md +4 -4
  243. package/templates/app/docs/errors/CAGE-APPR-006.md +29 -8
  244. package/templates/app/docs/errors/CAGE-APPR-007.md +9 -7
  245. package/templates/app/docs/errors/CAGE-APPR-010.md +5 -5
  246. package/templates/app/docs/errors/CAGE-AUDIT-001.md +53 -0
  247. package/templates/app/docs/errors/CAGE-AUTH-001.md +1 -1
  248. package/templates/app/docs/errors/CAGE-BIZ-001.md +51 -0
  249. package/templates/app/docs/errors/CAGE-BIZ-002.md +49 -0
  250. package/templates/app/docs/errors/CAGE-BUDGET-001.md +1 -1
  251. package/templates/app/docs/errors/CAGE-BUDGET-002.md +1 -1
  252. package/templates/app/docs/errors/CAGE-BUDGET-003.md +1 -1
  253. package/templates/app/docs/errors/CAGE-CMD-002.md +1 -1
  254. package/templates/app/docs/errors/CAGE-CMD-003.md +1 -1
  255. package/templates/app/docs/errors/CAGE-CONN-001.md +3 -3
  256. package/templates/app/docs/errors/CAGE-CONN-002.md +1 -1
  257. package/templates/app/docs/errors/CAGE-CONN-003.md +1 -1
  258. package/templates/app/docs/errors/CAGE-CONN-004.md +1 -1
  259. package/templates/app/docs/errors/CAGE-CONN-005.md +1 -1
  260. package/templates/app/docs/errors/CAGE-CONN-006.md +1 -1
  261. package/templates/app/docs/errors/CAGE-CONN-007.md +6 -6
  262. package/templates/app/docs/errors/CAGE-CONN-008.md +5 -5
  263. package/templates/app/docs/errors/CAGE-CONN-009.md +6 -6
  264. package/templates/app/docs/errors/CAGE-CONN-010.md +6 -6
  265. package/templates/app/docs/errors/CAGE-CONN-011.md +1 -1
  266. package/templates/app/docs/errors/CAGE-CONN-012.md +1 -1
  267. package/templates/app/docs/errors/CAGE-CONN-013.md +49 -0
  268. package/templates/app/docs/errors/CAGE-CONN-014.md +48 -0
  269. package/templates/app/docs/errors/CAGE-CONN-015.md +49 -0
  270. package/templates/app/docs/errors/CAGE-CREATE-001.md +10 -9
  271. package/templates/app/docs/errors/CAGE-DECL-001.md +2 -2
  272. package/templates/app/docs/errors/CAGE-DECL-002.md +7 -6
  273. package/templates/app/docs/errors/CAGE-DECL-003.md +1 -1
  274. package/templates/app/docs/errors/CAGE-DECL-004.md +1 -1
  275. package/templates/app/docs/errors/CAGE-DEP-001.md +2 -2
  276. package/templates/app/docs/errors/CAGE-DEP-002.md +1 -1
  277. package/templates/app/docs/errors/CAGE-DEP-003.md +2 -2
  278. package/templates/app/docs/errors/CAGE-DEP-004.md +1 -1
  279. package/templates/app/docs/errors/CAGE-DEP-005.md +1 -1
  280. package/templates/app/docs/errors/CAGE-DIAG-001.md +53 -0
  281. package/templates/app/docs/errors/CAGE-DLQ-001.md +2 -2
  282. package/templates/app/docs/errors/CAGE-ENV-001.md +4 -4
  283. package/templates/app/docs/errors/CAGE-ENV-002.md +51 -0
  284. package/templates/app/docs/errors/CAGE-ENV-003.md +48 -0
  285. package/templates/app/docs/errors/CAGE-EVENT-001.md +1 -1
  286. package/templates/app/docs/errors/CAGE-EVENT-002.md +7 -7
  287. package/templates/app/docs/errors/CAGE-FIELD-001.md +2 -2
  288. package/templates/app/docs/errors/CAGE-FIELD-002.md +1 -1
  289. package/templates/app/docs/errors/CAGE-FIELD-003.md +1 -1
  290. package/templates/app/docs/errors/CAGE-FIELD-004.md +1 -1
  291. package/templates/app/docs/errors/CAGE-FILE-001.md +56 -0
  292. package/templates/app/docs/errors/CAGE-GEN-001.md +2 -2
  293. package/templates/app/docs/errors/CAGE-GEN-002.md +1 -1
  294. package/templates/app/docs/errors/CAGE-GEN-003.md +53 -0
  295. package/templates/app/docs/errors/CAGE-GRANT-001.md +3 -3
  296. package/templates/app/docs/errors/CAGE-GRANT-002.md +2 -2
  297. package/templates/app/docs/errors/CAGE-GRANT-003.md +7 -6
  298. package/templates/app/docs/errors/CAGE-IMPACT-001.md +2 -2
  299. package/templates/app/docs/errors/CAGE-IMPACT-002.md +52 -0
  300. package/templates/app/docs/errors/CAGE-INIT-001.md +1 -1
  301. package/templates/app/docs/errors/CAGE-INIT-002.md +1 -1
  302. package/templates/app/docs/errors/CAGE-INIT-003.md +2 -2
  303. package/templates/app/docs/errors/CAGE-INIT-004.md +1 -1
  304. package/templates/app/docs/errors/CAGE-INIT-005.md +52 -0
  305. package/templates/app/docs/errors/CAGE-JOB-001.md +1 -1
  306. package/templates/app/docs/errors/CAGE-JOB-002.md +1 -1
  307. package/templates/app/docs/errors/CAGE-JOB-003.md +1 -1
  308. package/templates/app/docs/errors/CAGE-LINT-001.md +1 -1
  309. package/templates/app/docs/errors/CAGE-MIG-001.md +1 -1
  310. package/templates/app/docs/errors/CAGE-MIG-002.md +1 -1
  311. package/templates/app/docs/errors/CAGE-MIG-005.md +1 -1
  312. package/templates/app/docs/errors/CAGE-NAME-001.md +1 -1
  313. package/templates/app/docs/errors/CAGE-NAME-002.md +1 -1
  314. package/templates/app/docs/errors/CAGE-NAME-003.md +3 -3
  315. package/templates/app/docs/errors/CAGE-NAME-004.md +1 -1
  316. package/templates/app/docs/errors/CAGE-NAME-005.md +1 -1
  317. package/templates/app/docs/errors/CAGE-NAME-006.md +1 -1
  318. package/templates/app/docs/errors/CAGE-ORG-001.md +7 -6
  319. package/templates/app/docs/errors/CAGE-PAIR-002.md +6 -5
  320. package/templates/app/docs/errors/CAGE-QUERY-001.md +1 -1
  321. package/templates/app/docs/errors/CAGE-QUERY-002.md +2 -2
  322. package/templates/app/docs/errors/CAGE-QUERY-003.md +7 -6
  323. package/templates/app/docs/errors/CAGE-REACT-001.md +3 -3
  324. package/templates/app/docs/errors/CAGE-REACT-002.md +1 -1
  325. package/templates/app/docs/errors/CAGE-REACT-003.md +50 -0
  326. package/templates/app/docs/errors/CAGE-READS-001.md +9 -6
  327. package/templates/app/docs/errors/CAGE-REG-001.md +13 -12
  328. package/templates/app/docs/errors/CAGE-REG-002.md +2 -1
  329. package/templates/app/docs/errors/CAGE-REG-003.md +1 -1
  330. package/templates/app/docs/errors/CAGE-REL-001.md +14 -14
  331. package/templates/app/docs/errors/CAGE-ROUTE-001.md +7 -6
  332. package/templates/app/docs/errors/CAGE-SCOPE-001.md +1 -1
  333. package/templates/app/docs/errors/CAGE-SCOPE-002.md +2 -2
  334. package/templates/app/docs/errors/CAGE-SECRET-001.md +2 -2
  335. package/templates/app/docs/errors/CAGE-SECRET-002.md +1 -1
  336. package/templates/app/docs/errors/CAGE-SENS-001.md +5 -5
  337. package/templates/app/docs/errors/CAGE-SQL-001.md +1 -1
  338. package/templates/app/docs/errors/CAGE-SQL-002.md +1 -1
  339. package/templates/app/docs/errors/CAGE-STATE-001.md +3 -3
  340. package/templates/app/docs/errors/CAGE-STATE-002.md +1 -1
  341. package/templates/app/docs/errors/CAGE-STATE-003.md +1 -1
  342. package/templates/app/docs/errors/CAGE-STATE-004.md +1 -1
  343. package/templates/app/docs/errors/CAGE-STATE-005.md +3 -2
  344. package/templates/app/docs/errors/CAGE-STATE-010.md +5 -5
  345. package/templates/app/docs/errors/CAGE-STATE-011.md +5 -5
  346. package/templates/app/docs/errors/CAGE-STRUCT-001.md +1 -1
  347. package/templates/app/docs/errors/CAGE-STRUCT-002.md +1 -1
  348. package/templates/app/docs/errors/CAGE-SYNC-001.md +3 -2
  349. package/templates/app/docs/errors/CAGE-TEST-001.md +1 -1
  350. package/templates/app/docs/errors/CAGE-TEST-002.md +50 -0
  351. package/templates/app/docs/errors/CAGE-TEST-003.md +52 -0
  352. package/templates/app/docs/errors/CAGE-UNSAFE-001.md +3 -2
  353. package/templates/app/docs/errors/CAGE-UPGRADE-001.md +2 -2
  354. package/templates/app/docs/errors/CAGE-WORKER-001.md +48 -0
  355. package/templates/app/docs/errors/CAGE-WORKER-002.md +50 -0
  356. package/templates/app/docs/errors/CAGE-WORKER-003.md +48 -0
  357. package/templates/app/docs/errors/README.md +52 -2
  358. package/templates/app/package.json +3 -3
  359. package/templates/app/packages/contracts/package.json +1 -1
  360. package/templates/app/packages/contracts/src/aggregates/approval-member/index.ts +70 -0
  361. package/templates/app/packages/contracts/src/aggregates/dept/index.ts +10 -10
  362. package/templates/app/packages/contracts/src/aggregates/inventory/index.ts +5 -5
  363. package/templates/app/packages/contracts/src/aggregates/inventory-lock/index.ts +4 -4
  364. package/templates/app/packages/contracts/src/aggregates/purchase-order/index.ts +34 -12
  365. package/templates/app/packages/contracts/src/aggregates/role/index.ts +15 -15
  366. package/templates/app/packages/contracts/src/aggregates/user/index.ts +16 -16
  367. package/templates/app/packages/contracts/src/index.ts +16 -1
  368. package/templates/app/packages/contracts/src/queries/index.ts +2 -2
  369. package/templates/app/packages/domain/package.json +5 -4
  370. package/templates/app/packages/domain/src/index.ts +4 -0
  371. package/templates/app/packages/domain/src/integrations/erp.ts +15 -0
  372. package/templates/app/packages/domain/src/integrations/intelligence.ts +20 -0
  373. package/templates/app/packages/domain/src/modules/inventory/index.ts +1 -0
  374. package/templates/app/packages/domain/src/modules/inventory/inventory.ts +12 -0
  375. package/templates/app/packages/domain/src/modules/purchase/approval-members.ts +54 -0
  376. package/templates/app/packages/domain/src/modules/purchase/approvals.ts +38 -6
  377. package/templates/app/packages/domain/src/modules/purchase/index.ts +2 -0
  378. package/templates/app/packages/domain/src/modules/purchase/intelligence.test.ts +224 -0
  379. package/templates/app/packages/domain/src/modules/purchase/jobs.ts +5 -0
  380. package/templates/app/packages/domain/src/modules/purchase/purchase-order.test.ts +9 -0
  381. package/templates/app/packages/domain/src/modules/purchase/purchase-order.ts +125 -4
  382. package/templates/app/packages/domain/src/modules/purchase/queries.ts +5 -0
  383. package/templates/app/packages/domain/src/workflows/purchase-inventory.ts +6 -0
  384. package/templates/app/packages/domain/src/workflows/purchase-process.ts +42 -0
  385. package/templates/blank/.dockerignore +2 -0
  386. package/templates/blank/.env.example +10 -0
  387. package/templates/blank/AGENTS.md +50 -10
  388. package/templates/blank/README.md +4 -1
  389. package/templates/blank/_gitignore +1 -0
  390. package/templates/blank/apps/api/package.json +1 -1
  391. package/templates/blank/apps/api/src/main.ts +4 -1
  392. package/templates/blank/apps/api/src/worker.ts +2 -0
  393. package/templates/blank/apps/web/index.html +1 -0
  394. package/templates/blank/apps/web/package.json +7 -3
  395. package/templates/blank/apps/web/src/app/app.tsx +80 -18
  396. package/templates/blank/apps/web/src/app/styles/global.css +90 -0
  397. package/templates/blank/apps/web/src/app/use-session.ts +43 -0
  398. package/templates/blank/apps/web/src/app/workspace-layout.tsx +30 -5
  399. package/templates/blank/apps/web/src/main.tsx +5 -0
  400. package/templates/blank/apps/web/src/modules/auth/index.ts +4 -0
  401. package/templates/blank/apps/web/src/modules/auth/pages/login-page.tsx +18 -1
  402. package/templates/blank/apps/web/src/modules/directory/index.ts +7 -0
  403. package/templates/blank/apps/web/src/modules/directory/pages/user-detail-page.tsx +78 -0
  404. package/templates/blank/apps/web/src/modules/directory/pages/users-page.tsx +93 -0
  405. package/templates/blank/apps/web/src/modules/workspace/index.ts +4 -0
  406. package/templates/blank/apps/web/src/modules/workspace/pages/home-page.tsx +17 -0
  407. package/templates/blank/apps/web/src/shared/lib/error-message.ts +11 -0
  408. package/templates/blank/apps/web/src/shared/lib/navigation.ts +21 -0
  409. package/templates/blank/apps/web/src/shared/ui/brand.tsx +10 -2
  410. package/templates/blank/apps/web/src/shared/ui/page-state.css +47 -0
  411. package/templates/blank/apps/web/src/shared/ui/page-state.tsx +76 -0
  412. package/templates/blank/apps/web/src/shared/ui/require-capability.tsx +34 -0
  413. package/templates/blank/apps/web/vite.config.ts +5 -0
  414. package/templates/blank/deploy/nginx.conf +52 -0
  415. package/templates/blank/docs/ai/README.md +28 -2
  416. package/templates/blank/docs/ai/approvals.md +260 -0
  417. package/templates/blank/docs/ai/architecture.md +26 -0
  418. package/templates/blank/docs/ai/commenting.md +203 -0
  419. package/templates/blank/docs/ai/diagnostics.md +80 -0
  420. package/templates/blank/docs/ai/files.md +93 -0
  421. package/templates/blank/docs/ai/intelligence.md +348 -0
  422. package/templates/blank/docs/ai/ontology-context.md +59 -4
  423. package/templates/blank/docs/ai/primitives.md +34 -1
  424. package/templates/blank/docs/ai/project-structure.md +8 -3
  425. package/templates/blank/docs/ai/purchase-example.md +35 -7
  426. package/templates/blank/docs/ai/recipes.md +10 -2
  427. package/templates/blank/docs/ai/routing.md +86 -0
  428. package/templates/blank/docs/ai/troubleshooting.md +5 -0
  429. package/templates/blank/docs/ai/workflow.md +24 -11
  430. package/templates/blank/docs/errors/CAGE-AI-001.md +61 -0
  431. package/templates/blank/docs/errors/CAGE-APPR-001.md +13 -9
  432. package/templates/blank/docs/errors/CAGE-APPR-002.md +2 -2
  433. package/templates/blank/docs/errors/CAGE-APPR-003.md +1 -1
  434. package/templates/blank/docs/errors/CAGE-APPR-004.md +4 -4
  435. package/templates/blank/docs/errors/CAGE-APPR-005.md +4 -4
  436. package/templates/blank/docs/errors/CAGE-APPR-006.md +29 -8
  437. package/templates/blank/docs/errors/CAGE-APPR-007.md +9 -7
  438. package/templates/blank/docs/errors/CAGE-APPR-010.md +5 -5
  439. package/templates/blank/docs/errors/CAGE-AUDIT-001.md +53 -0
  440. package/templates/blank/docs/errors/CAGE-AUTH-001.md +1 -1
  441. package/templates/blank/docs/errors/CAGE-BIZ-001.md +51 -0
  442. package/templates/blank/docs/errors/CAGE-BIZ-002.md +49 -0
  443. package/templates/blank/docs/errors/CAGE-BUDGET-001.md +1 -1
  444. package/templates/blank/docs/errors/CAGE-BUDGET-002.md +1 -1
  445. package/templates/blank/docs/errors/CAGE-BUDGET-003.md +1 -1
  446. package/templates/blank/docs/errors/CAGE-CMD-002.md +1 -1
  447. package/templates/blank/docs/errors/CAGE-CMD-003.md +1 -1
  448. package/templates/blank/docs/errors/CAGE-CONN-001.md +3 -3
  449. package/templates/blank/docs/errors/CAGE-CONN-002.md +1 -1
  450. package/templates/blank/docs/errors/CAGE-CONN-003.md +1 -1
  451. package/templates/blank/docs/errors/CAGE-CONN-004.md +1 -1
  452. package/templates/blank/docs/errors/CAGE-CONN-005.md +1 -1
  453. package/templates/blank/docs/errors/CAGE-CONN-006.md +1 -1
  454. package/templates/blank/docs/errors/CAGE-CONN-007.md +6 -6
  455. package/templates/blank/docs/errors/CAGE-CONN-008.md +5 -5
  456. package/templates/blank/docs/errors/CAGE-CONN-009.md +6 -6
  457. package/templates/blank/docs/errors/CAGE-CONN-010.md +6 -6
  458. package/templates/blank/docs/errors/CAGE-CONN-011.md +1 -1
  459. package/templates/blank/docs/errors/CAGE-CONN-012.md +1 -1
  460. package/templates/blank/docs/errors/CAGE-CONN-013.md +49 -0
  461. package/templates/blank/docs/errors/CAGE-CONN-014.md +48 -0
  462. package/templates/blank/docs/errors/CAGE-CONN-015.md +49 -0
  463. package/templates/blank/docs/errors/CAGE-CREATE-001.md +10 -9
  464. package/templates/blank/docs/errors/CAGE-DECL-001.md +2 -2
  465. package/templates/blank/docs/errors/CAGE-DECL-002.md +7 -6
  466. package/templates/blank/docs/errors/CAGE-DECL-003.md +1 -1
  467. package/templates/blank/docs/errors/CAGE-DECL-004.md +1 -1
  468. package/templates/blank/docs/errors/CAGE-DEP-001.md +2 -2
  469. package/templates/blank/docs/errors/CAGE-DEP-002.md +1 -1
  470. package/templates/blank/docs/errors/CAGE-DEP-003.md +2 -2
  471. package/templates/blank/docs/errors/CAGE-DEP-004.md +1 -1
  472. package/templates/blank/docs/errors/CAGE-DEP-005.md +1 -1
  473. package/templates/blank/docs/errors/CAGE-DIAG-001.md +53 -0
  474. package/templates/blank/docs/errors/CAGE-DLQ-001.md +2 -2
  475. package/templates/blank/docs/errors/CAGE-ENV-001.md +4 -4
  476. package/templates/blank/docs/errors/CAGE-ENV-002.md +51 -0
  477. package/templates/blank/docs/errors/CAGE-ENV-003.md +48 -0
  478. package/templates/blank/docs/errors/CAGE-EVENT-001.md +1 -1
  479. package/templates/blank/docs/errors/CAGE-EVENT-002.md +7 -7
  480. package/templates/blank/docs/errors/CAGE-FIELD-001.md +2 -2
  481. package/templates/blank/docs/errors/CAGE-FIELD-002.md +1 -1
  482. package/templates/blank/docs/errors/CAGE-FIELD-003.md +1 -1
  483. package/templates/blank/docs/errors/CAGE-FIELD-004.md +1 -1
  484. package/templates/blank/docs/errors/CAGE-FILE-001.md +56 -0
  485. package/templates/blank/docs/errors/CAGE-GEN-001.md +2 -2
  486. package/templates/blank/docs/errors/CAGE-GEN-002.md +1 -1
  487. package/templates/blank/docs/errors/CAGE-GEN-003.md +53 -0
  488. package/templates/blank/docs/errors/CAGE-GRANT-001.md +3 -3
  489. package/templates/blank/docs/errors/CAGE-GRANT-002.md +2 -2
  490. package/templates/blank/docs/errors/CAGE-GRANT-003.md +7 -6
  491. package/templates/blank/docs/errors/CAGE-IMPACT-001.md +2 -2
  492. package/templates/blank/docs/errors/CAGE-IMPACT-002.md +52 -0
  493. package/templates/blank/docs/errors/CAGE-INIT-001.md +1 -1
  494. package/templates/blank/docs/errors/CAGE-INIT-002.md +1 -1
  495. package/templates/blank/docs/errors/CAGE-INIT-003.md +2 -2
  496. package/templates/blank/docs/errors/CAGE-INIT-004.md +1 -1
  497. package/templates/blank/docs/errors/CAGE-INIT-005.md +52 -0
  498. package/templates/blank/docs/errors/CAGE-JOB-001.md +1 -1
  499. package/templates/blank/docs/errors/CAGE-JOB-002.md +1 -1
  500. package/templates/blank/docs/errors/CAGE-JOB-003.md +1 -1
  501. package/templates/blank/docs/errors/CAGE-LINT-001.md +1 -1
  502. package/templates/blank/docs/errors/CAGE-MIG-001.md +1 -1
  503. package/templates/blank/docs/errors/CAGE-MIG-002.md +1 -1
  504. package/templates/blank/docs/errors/CAGE-MIG-005.md +1 -1
  505. package/templates/blank/docs/errors/CAGE-NAME-001.md +1 -1
  506. package/templates/blank/docs/errors/CAGE-NAME-002.md +1 -1
  507. package/templates/blank/docs/errors/CAGE-NAME-003.md +3 -3
  508. package/templates/blank/docs/errors/CAGE-NAME-004.md +1 -1
  509. package/templates/blank/docs/errors/CAGE-NAME-005.md +1 -1
  510. package/templates/blank/docs/errors/CAGE-NAME-006.md +1 -1
  511. package/templates/blank/docs/errors/CAGE-ORG-001.md +7 -6
  512. package/templates/blank/docs/errors/CAGE-PAIR-002.md +6 -5
  513. package/templates/blank/docs/errors/CAGE-QUERY-001.md +1 -1
  514. package/templates/blank/docs/errors/CAGE-QUERY-002.md +2 -2
  515. package/templates/blank/docs/errors/CAGE-QUERY-003.md +7 -6
  516. package/templates/blank/docs/errors/CAGE-REACT-001.md +3 -3
  517. package/templates/blank/docs/errors/CAGE-REACT-002.md +1 -1
  518. package/templates/blank/docs/errors/CAGE-REACT-003.md +50 -0
  519. package/templates/blank/docs/errors/CAGE-READS-001.md +9 -6
  520. package/templates/blank/docs/errors/CAGE-REG-001.md +13 -12
  521. package/templates/blank/docs/errors/CAGE-REG-002.md +2 -1
  522. package/templates/blank/docs/errors/CAGE-REG-003.md +1 -1
  523. package/templates/blank/docs/errors/CAGE-REL-001.md +14 -14
  524. package/templates/blank/docs/errors/CAGE-ROUTE-001.md +7 -6
  525. package/templates/blank/docs/errors/CAGE-SCOPE-001.md +1 -1
  526. package/templates/blank/docs/errors/CAGE-SCOPE-002.md +2 -2
  527. package/templates/blank/docs/errors/CAGE-SECRET-001.md +2 -2
  528. package/templates/blank/docs/errors/CAGE-SECRET-002.md +1 -1
  529. package/templates/blank/docs/errors/CAGE-SENS-001.md +5 -5
  530. package/templates/blank/docs/errors/CAGE-SQL-001.md +1 -1
  531. package/templates/blank/docs/errors/CAGE-SQL-002.md +1 -1
  532. package/templates/blank/docs/errors/CAGE-STATE-001.md +3 -3
  533. package/templates/blank/docs/errors/CAGE-STATE-002.md +1 -1
  534. package/templates/blank/docs/errors/CAGE-STATE-003.md +1 -1
  535. package/templates/blank/docs/errors/CAGE-STATE-004.md +1 -1
  536. package/templates/blank/docs/errors/CAGE-STATE-005.md +3 -2
  537. package/templates/blank/docs/errors/CAGE-STATE-010.md +5 -5
  538. package/templates/blank/docs/errors/CAGE-STATE-011.md +5 -5
  539. package/templates/blank/docs/errors/CAGE-STRUCT-001.md +1 -1
  540. package/templates/blank/docs/errors/CAGE-STRUCT-002.md +1 -1
  541. package/templates/blank/docs/errors/CAGE-SYNC-001.md +3 -2
  542. package/templates/blank/docs/errors/CAGE-TEST-001.md +1 -1
  543. package/templates/blank/docs/errors/CAGE-TEST-002.md +50 -0
  544. package/templates/blank/docs/errors/CAGE-TEST-003.md +52 -0
  545. package/templates/blank/docs/errors/CAGE-UNSAFE-001.md +3 -2
  546. package/templates/blank/docs/errors/CAGE-UPGRADE-001.md +2 -2
  547. package/templates/blank/docs/errors/CAGE-WORKER-001.md +48 -0
  548. package/templates/blank/docs/errors/CAGE-WORKER-002.md +50 -0
  549. package/templates/blank/docs/errors/CAGE-WORKER-003.md +48 -0
  550. package/templates/blank/docs/errors/README.md +52 -2
  551. package/templates/blank/docs/examples/purchase-admin/apps/api/src/main.ts +5 -1
  552. package/templates/blank/docs/examples/purchase-admin/apps/api/src/worker.ts +3 -0
  553. package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/app.tsx +122 -12
  554. package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/styles/global.css +88 -8
  555. package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/use-session.ts +43 -0
  556. package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/workspace-layout.tsx +58 -19
  557. package/templates/blank/docs/examples/purchase-admin/apps/web/src/main.tsx +5 -0
  558. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/approval/components/task-operation-dialog.tsx +61 -0
  559. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/approval/hooks/use-approval-tasks.ts +13 -5
  560. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/approval/index.ts +4 -0
  561. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/approval/pages/approval-tasks-page.tsx +89 -38
  562. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/approval/pages/approval-tasks.css +18 -0
  563. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/auth/index.ts +4 -0
  564. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/auth/pages/login-page.tsx +12 -0
  565. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/inventory/index.ts +4 -0
  566. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/inventory/pages/inventory-page.tsx +29 -1
  567. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/approval-history.tsx +67 -0
  568. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/order-attachments.tsx +29 -0
  569. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/order-reviewers.tsx +38 -0
  570. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/purchase-assistant-context.tsx +17 -0
  571. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/purchase-order-form.css +6 -0
  572. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/purchase-order-form.tsx +32 -3
  573. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/index.ts +5 -0
  574. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/lib/presentation.ts +20 -0
  575. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/pages/purchase-intelligence.css +17 -0
  576. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/pages/purchase-order-detail-page.tsx +156 -0
  577. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/pages/purchase-orders-page.tsx +54 -22
  578. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/workspace/index.ts +5 -0
  579. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/workspace/pages/home-page.tsx +44 -0
  580. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/hooks/use-command.ts +13 -0
  581. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/lib/error-message.ts +15 -1
  582. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/lib/navigation.ts +21 -0
  583. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/approval-member-picker.css +10 -0
  584. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/approval-member-picker.tsx +51 -0
  585. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/assistant-markdown.tsx +19 -0
  586. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/assistant-panel.css +134 -0
  587. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/assistant-panel.tsx +200 -0
  588. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/assistant-scope.tsx +72 -0
  589. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/attachment-upload.css +28 -0
  590. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/attachment-upload.tsx +163 -0
  591. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/notice.tsx +7 -0
  592. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/page-heading.tsx +7 -0
  593. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/page-state.css +47 -0
  594. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/page-state.tsx +76 -0
  595. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/require-capability.tsx +34 -0
  596. package/templates/blank/docs/examples/purchase-admin/cage.config.json +23 -0
  597. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/approval-member/index.ts +70 -0
  598. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/dept/index.ts +10 -10
  599. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/inventory/index.ts +5 -5
  600. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/inventory-lock/index.ts +4 -4
  601. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/purchase-order/index.ts +34 -12
  602. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/role/index.ts +15 -15
  603. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/user/index.ts +16 -16
  604. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/index.ts +16 -1
  605. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/queries/index.ts +2 -2
  606. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/index.ts +4 -0
  607. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/integrations/erp.ts +15 -0
  608. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/integrations/intelligence.ts +20 -0
  609. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/inventory/index.ts +1 -0
  610. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/inventory/inventory.ts +12 -0
  611. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/approval-members.ts +54 -0
  612. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/approvals.ts +38 -6
  613. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/index.ts +2 -0
  614. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/intelligence.test.ts +224 -0
  615. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/jobs.ts +5 -0
  616. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/purchase-order.test.ts +9 -0
  617. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/purchase-order.ts +125 -4
  618. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/queries.ts +5 -0
  619. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/workflows/purchase-inventory.ts +6 -0
  620. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/workflows/purchase-process.ts +42 -0
  621. package/templates/blank/package.json +3 -3
  622. package/templates/blank/packages/contracts/package.json +1 -1
  623. package/templates/blank/packages/contracts/src/aggregates/dept/index.ts +10 -10
  624. package/templates/blank/packages/contracts/src/aggregates/role/index.ts +15 -15
  625. package/templates/blank/packages/contracts/src/aggregates/user/index.ts +16 -16
  626. package/templates/blank/packages/contracts/src/index.ts +1 -1
  627. package/templates/blank/packages/contracts/src/queries/index.ts +1 -1
  628. package/templates/blank/packages/domain/package.json +5 -4
  629. package/templates/blank/packages/domain/src/index.ts +2 -1
package/graph-ui/app.js CHANGED
@@ -1,9 +1,14 @@
1
1
  import { kinds, nodeLabel, projectGraph, neighborhood, isSystem, layoutGraph, edgePath, NODE_WIDTH, NODE_HEIGHT, } from './model.js';
2
2
  import { explainEdge } from './relations.js';
3
3
  import { searchGraphNodes as rankGraphNodes } from './graph-search.js';
4
+ import { businessBlocks, businessConstraintLabel, businessJourneys } from './graph-business.js';
5
+ import { renderBusiness, disposeBusiness, sourcePreview } from './business.js';
4
6
  import { tableCards, tableOwner, layoutTables, tableEdgePath, fieldType, TABLE_WIDTH, TABLE_HEADER, TABLE_ROW, } from './structure.js';
5
7
  // 页面不引入图形框架或远程 CDN。百级声明图使用 SVG,即可保留清晰缩放、
6
8
  // 键盘选择和可检查的节点语义;所有数据都由本地 CLI 抽取服务提供。
9
+ /**
10
+ * 获取 index.html 约定的固定 DOM 锚点并标注调用方类型;这些 ID 由静态骨架提供。
11
+ */
7
12
  const element = (id) => document.getElementById(id);
8
13
  const svg = document.getElementById('graph');
9
14
  const viewport = document.getElementById('viewport');
@@ -20,7 +25,7 @@ let selectedEdge = null;
20
25
  let emphasizeSelection = false;
21
26
  let aggregate = null;
22
27
  let focus = null;
23
- let mode = 'structure';
28
+ let mode = 'business';
24
29
  let cards = [];
25
30
  let visibleCards = [];
26
31
  let searchTarget = null;
@@ -30,12 +35,18 @@ const businessKinds = Object.keys(kinds).filter((k) => !['field', 'state', 'capa
30
35
  let enabled = new Set(businessKinds);
31
36
  const nodeElements = new Map();
32
37
  const edgeElements = new Map();
38
+ /**
39
+ * 创建页面元素并用 textContent 写文本,避免把抽取文案当作 HTML 执行;返回未挂载节点。
40
+ */
33
41
  function html(tag, className = '', text = '') {
34
42
  const node = document.createElement(tag);
35
43
  node.className = className;
36
44
  node.textContent = text;
37
45
  return node;
38
46
  }
47
+ /**
48
+ * 创建 SVG 命名空间元素并设置属性/文本,供节点和连线绘制;不进行布局计算。
49
+ */
39
50
  function vector(tag, attrs = {}, text = '') {
40
51
  const node = document.createElementNS(ns, tag);
41
52
  for (const [key, value] of Object.entries(attrs))
@@ -43,9 +54,71 @@ function vector(tag, attrs = {}, text = '') {
43
54
  node.textContent = text;
44
55
  return node;
45
56
  }
57
+ /**
58
+ * 在当前展示模型按完整 key 查找节点;调用者只传入模型或检索结果中的已知 key。
59
+ */
46
60
  const byKey = (key) => model.nodes.find((n) => n.key === key);
61
+ /**
62
+ * 使用当前快照的中文覆盖获取显示名,保留底层业务 ID。
63
+ */
47
64
  const displayName = (node) => nodeLabel(node, snapshot.presentation.labels);
65
+ /**
66
+ * 按 patch 修改当前查询参数,null 表示移除,并按 replace 决定替换或新增历史。
67
+ * 不自行重渲染;调用方必须同步页面状态,避免地址和视图分离。
68
+ */
69
+ function address(patch, replace = false) {
70
+ const url = new URL(location.href);
71
+ for (const [key, value] of Object.entries(patch)) {
72
+ if (value === null)
73
+ url.searchParams.delete(key);
74
+ else
75
+ url.searchParams.set(key, value);
76
+ }
77
+ if (url.href !== location.href)
78
+ history[replace ? 'replaceState' : 'pushState'](null, '', url);
79
+ }
80
+ /**
81
+ * 切回业务视图并更新 URL、筛选及画布;仅换场景时滚到入口,窄屏选步骤时滚到详情。
82
+ */
83
+ function navigateBusiness(patch) {
84
+ const previousScene = element('business-view').dataset.scene;
85
+ mode = 'business';
86
+ selectedEdge = null;
87
+ address({ view: 'business', node: null, object: null, ...patch });
88
+ renderFilters();
89
+ renderGraph();
90
+ if (previousScene !== element('business-view').dataset.scene)
91
+ element('explorer').scrollIntoView({ block: 'start' });
92
+ if (patch.step && matchMedia('(max-width: 800px)').matches)
93
+ element('business-view').querySelector('.business-detail')?.scrollIntoView({ block: 'start' });
94
+ }
95
+ /**
96
+ * 从 URL 恢复可用视图、选中对象与系统开关,删除或无效节点不被强行选中。
97
+ * 清除临时聚焦和边选择,供首次加载及浏览器前进后退复用。
98
+ */
99
+ function restoreAddress() {
100
+ const params = new URLSearchParams(location.search);
101
+ const view = params.get('view');
102
+ mode = view === 'structure' || view === 'all' ? view : 'business';
103
+ const node = params.get('node');
104
+ if (node && byKey(node))
105
+ selected = node;
106
+ if (mode === 'structure' && selected)
107
+ selected =
108
+ tableOwner(cards, selected)?.node.key ?? cards.find((card) => !isSystem(card.node))?.node.key ?? null;
109
+ const object = params.get('object');
110
+ aggregate = model.nodes.some((n) => n.kind === 'aggregate' && n.id === object) ? object : null;
111
+ showSystem = params.get('system') === '1';
112
+ if (selected && mode !== 'business')
113
+ showSystem ||= isSystem(byKey(selected));
114
+ focus = null;
115
+ selectedEdge = null;
116
+ enabled = new Set(mode === 'all' ? Object.keys(kinds) : businessKinds);
117
+ }
48
118
  // 中文字符约占两个半角字宽,不能沿用英文按字符数截断,否则标题会溢出卡片。
119
+ /**
120
+ * 按半角/中文近似宽度截断画布短标题,超限添加省略号;不是精确字体测量。
121
+ */
49
122
  function shortName(text, width = 23) {
50
123
  let result = '', used = 0;
51
124
  for (const char of text) {
@@ -56,16 +129,26 @@ function shortName(text, width = 23) {
56
129
  }
57
130
  return result;
58
131
  }
132
+ /**
133
+ * 将详情中的业务标识转换为可读名称;可指定类型消歧,未命中节点时尝试显示覆盖,最终保留原始值。
134
+ */
59
135
  const named = (id, kind) => {
60
136
  const node = model.nodes.find((n) => n.id === id && (!kind || n.kind === kind));
61
137
  return node
62
138
  ? displayName(node)
63
139
  : ((kind ? snapshot.presentation.labels[`${kind}:${id}`] : undefined) ?? String(id));
64
140
  };
141
+ /**
142
+ * 更新页面状态提示,空文本隐藏区域;不把错误提示写进本体快照。
143
+ */
65
144
  function notify(message) {
66
145
  element('notice').textContent = message;
67
146
  element('notice').hidden = !message;
68
147
  }
148
+ /**
149
+ * 读取或重新抽取快照,再重建投影、卡片与详情。
150
+ * refresh 为 true 时调用 POST;期间禁用刷新按钮,失败保留旧图并提示其来源,finally 恢复按钮。
151
+ */
69
152
  async function load(refresh = false) {
70
153
  const button = element('refresh');
71
154
  button.disabled = true;
@@ -95,6 +178,8 @@ async function load(refresh = false) {
95
178
  const commands = (a) => model.nodes.filter((n) => n.kind === 'command' && n.id.startsWith(`${a.id}.`)).length;
96
179
  selected = aggregates.sort((a, b) => commands(b) - commands(a))[0]?.key ?? model.nodes[0]?.key ?? null;
97
180
  }
181
+ if (!refresh)
182
+ restoreAddress();
98
183
  renderSummary();
99
184
  renderFilters();
100
185
  renderGraph();
@@ -115,6 +200,9 @@ async function load(refresh = false) {
115
200
  element('loading').hidden = true;
116
201
  }
117
202
  }
203
+ /**
204
+ * 从当前快照更新项目标题、节点统计和规则状态;通过只表示声明规则,不表示业务测试通过。
205
+ */
118
206
  function renderSummary() {
119
207
  element('project-name').textContent = snapshot.presentation.title;
120
208
  element('project-name').title = snapshot.project;
@@ -134,13 +222,25 @@ function renderSummary() {
134
222
  element('show-findings').hidden = !snapshot.findings.length;
135
223
  const time = new Date(snapshot.generatedAt).toLocaleTimeString('zh-CN', { hour12: false });
136
224
  element('updated').textContent = `最近抽取 ${time}`;
225
+ const health = element('business-health');
226
+ health.replaceChildren(html('span', '', `${element('health').textContent} · 最近抽取 ${time}`));
227
+ if (snapshot.findings.length) {
228
+ const findings = html('button', 'text-button', '查看声明问题 ↗');
229
+ findings.onclick = () => element('findings-dialog').showModal();
230
+ health.append(findings);
231
+ }
137
232
  }
233
+ /**
234
+ * 按当前视图重建板块/对象与类型筛选,回调更新内存状态并请求重绘,不修改声明。
235
+ */
138
236
  function renderFilters() {
139
- element('types-heading').hidden = mode === 'structure';
140
- element('type-filters').hidden = mode === 'structure';
237
+ element('types-heading').hidden = mode !== 'all';
238
+ element('type-filters').hidden = mode !== 'all';
141
239
  element('structure-note').hidden = mode !== 'structure';
142
240
  const aggregates = model.nodes.filter((n) => n.kind === 'aggregate' && (showSystem || !isSystem(n)));
143
- element('aggregate-total').textContent = String(aggregates.length);
241
+ const blocks = businessBlocks(model, snapshot.presentation.labels, showSystem);
242
+ element('objects-heading-label').textContent = mode === 'business' ? '业务板块' : '业务对象';
243
+ element('aggregate-total').textContent = String(mode === 'business' ? blocks.length : aggregates.length);
144
244
  const list = element('aggregate-list');
145
245
  list.replaceChildren();
146
246
  const addAggregate = (id, label, count) => {
@@ -150,14 +250,42 @@ function renderFilters() {
150
250
  button.onclick = () => {
151
251
  aggregate = id;
152
252
  focus = null;
253
+ address({ view: mode, object: id });
153
254
  renderFilters();
154
255
  renderGraph();
155
256
  };
156
257
  list.append(button);
157
258
  };
158
- addAggregate(null, '全部业务', aggregates.length);
159
- for (const a of aggregates)
160
- addAggregate(a.id, displayName(a), model.nodes.filter((n) => n.id.startsWith(`${a.id}.`)).length);
259
+ if (mode === 'business') {
260
+ const selectedBlock = new URLSearchParams(location.search).get('block');
261
+ for (const block of [{ id: null, title: '全部业务', count: blocks.length }, ...blocks.map(b => ({ id: b.id, title: b.title, count: businessJourneys(b, model).length }))]) {
262
+ const button = html('a', `aggregate-button${selectedBlock === block.id ? ' active' : ''}`);
263
+ const url = new URL(location.href);
264
+ for (const key of ['flow', 'step', 'source', 'tab', 'node', 'object'])
265
+ url.searchParams.delete(key);
266
+ url.searchParams.set('view', 'business');
267
+ if (block.id)
268
+ url.searchParams.set('block', block.id);
269
+ else
270
+ url.searchParams.delete('block');
271
+ button.href = url.pathname + url.search;
272
+ button.append(html('span', '', block.id ? '◇' : '⊞'), html('span', '', block.title), html('b', '', String(block.count)));
273
+ button.onclick = (event) => {
274
+ if (event.button || event.ctrlKey || event.metaKey || event.shiftKey || event.altKey)
275
+ return;
276
+ event.preventDefault();
277
+ navigateBusiness({ block: block.id, flow: null, step: null, tab: null, source: null });
278
+ element('sidebar').classList.remove('open');
279
+ element('toggle-sidebar').setAttribute('aria-expanded', 'false');
280
+ };
281
+ list.append(button);
282
+ }
283
+ }
284
+ else {
285
+ addAggregate(null, '全部业务', aggregates.length);
286
+ for (const a of aggregates)
287
+ addAggregate(a.id, displayName(a), model.nodes.filter((n) => n.id.startsWith(`${a.id}.`)).length);
288
+ }
161
289
  const filters = element('type-filters');
162
290
  filters.replaceChildren();
163
291
  for (const [kind, meta] of Object.entries(kinds)) {
@@ -190,6 +318,9 @@ function renderFilters() {
190
318
  }
191
319
  /** 选一个聚合时,先纳入它自己的声明,再沿真实关系扩展业务链。
192
320
  * 不沿其他聚合的归属边扩散,避免选采购单却展开所有组织管理命令。 */
321
+ /**
322
+ * 围绕指定聚合沿有限三跳显式关系收集相关节点,避免归属虚线扩散为所有组织命令。
323
+ */
193
324
  function aggregateNodes(id) {
194
325
  const keys = new Set(model.nodes.filter((n) => n.id === id || n.id.startsWith(`${id}.`)).map((n) => n.key));
195
326
  for (let hop = 0; hop < 3; hop++) {
@@ -203,7 +334,47 @@ function aggregateNodes(id) {
203
334
  }
204
335
  return keys;
205
336
  }
337
+ /**
338
+ * 按业务、结构或完整模式重建可见画布,应用类型/系统/对象/邻域筛选。
339
+ * resetLayout 决定是否重新排布;切走业务视图先释放专属监听器,绘制不修改语义图。
340
+ */
206
341
  function renderGraph(resetLayout = true) {
342
+ const business = mode === 'business';
343
+ element('explorer').classList.toggle('business-mode', business);
344
+ element('main').classList.toggle('business-page', business);
345
+ element('business-view').hidden = !business;
346
+ element('page-title').textContent = business ? '业务地图' : '本体图谱';
347
+ element('page-description').textContent = business
348
+ ? '先理解业务,再沿流程找到实现。'
349
+ : '从声明出发,看见业务如何连接。';
350
+ element('metric-first-label').textContent = business ? '业务板块' : '业务对象';
351
+ element('metric-second-label').textContent = business ? '业务流程' : '声明节点';
352
+ element('metric-third-label').textContent = business ? '业务对象' : '声明关系';
353
+ const blocks = businessBlocks(model, snapshot.presentation.labels, showSystem);
354
+ element('metric-aggregates').textContent = String(business ? blocks.length : cards.length);
355
+ element('metric-nodes').textContent = String(business ? new Set(blocks.flatMap((b) => businessJourneys(b, model).map((n) => n.key))).size : snapshot.graph.nodes.length);
356
+ element('metric-edges').textContent = String(business ? blocks.flatMap((b) => b.objects).length : snapshot.graph.edges.length);
357
+ if (business) {
358
+ renderBusiness(element('business-view'), model, snapshot, {
359
+ showSystem,
360
+ navigate: navigateBusiness,
361
+ inspect: (key, view) => {
362
+ mode = view;
363
+ enabled = new Set(Object.keys(kinds));
364
+ selected = key;
365
+ selectedEdge = null;
366
+ focus = null;
367
+ aggregate = view === 'structure' ? byKey(key).id : null;
368
+ showSystem ||= isSystem(byKey(key));
369
+ address({ view, node: key, object: aggregate, system: showSystem ? '1' : null });
370
+ renderFilters();
371
+ renderGraph();
372
+ renderInspector();
373
+ },
374
+ });
375
+ return;
376
+ }
377
+ disposeBusiness(element('business-view'));
207
378
  searchTarget = null;
208
379
  const scope = aggregate ? aggregateNodes(aggregate) : null;
209
380
  const focused = focus ? neighborhood(model, focus) : null;
@@ -347,6 +518,10 @@ function renderGraph(resetLayout = true) {
347
518
  }
348
519
  /** 绿色表头、逐行字段和表名保持在同一 SVG 卡片里。字段是可选择的原始节点,
349
520
  * 表头负责拖动卡片,字段点击不会误触画布拖动或把数据结构重新拆散。 */
521
+ /**
522
+ * 为一个真实聚合绘制字段卡片,保留字段身份供点击、键盘和关系解释使用。
523
+ * 卡片尺寸来自字段数量,敏感/可选/关系标记只展示声明事实。
524
+ */
350
525
  function renderTable(card) {
351
526
  const { node, fields, height } = card;
352
527
  const group = vector('g', {
@@ -421,9 +596,16 @@ function renderTable(card) {
421
596
  nodeLayer.append(group);
422
597
  nodeElements.set(node.key, group);
423
598
  }
599
+ /**
600
+ * 按当前视图返回节点尺寸:对象卡片使用字段数算出的高度,普通图使用固定节点规格。
601
+ */
424
602
  const nodeSize = (key) => mode === 'structure'
425
603
  ? { width: TABLE_WIDTH, height: tableOwner(visibleCards, key).height }
426
604
  : { width: NODE_WIDTH, height: NODE_HEIGHT };
605
+ /**
606
+ * 将内存节点位置同步到 SVG 并重算连线,随后在候选线段位置选择碰撞较少的标签落点。
607
+ * 标签仍贴近对应线,拖动只变展示坐标,不保存后端数据。
608
+ */
427
609
  function updatePositions() {
428
610
  for (const n of visibleNodes) {
429
611
  const p = positions.get(n.key);
@@ -456,6 +638,9 @@ function updatePositions() {
456
638
  occupied.push(box);
457
639
  }
458
640
  }
641
+ /**
642
+ * 同步节点/边选择高亮及无障碍状态,结构视图保留其他字段的可读对比度。
643
+ */
459
644
  function highlight() {
460
645
  const connected = selectedEdge
461
646
  ? new Set([selectedEdge.from, selectedEdge.to])
@@ -493,14 +678,41 @@ function highlight() {
493
678
  path.setAttribute('marker-end', active ? 'url(#arrow-active)' : 'url(#arrow)');
494
679
  }
495
680
  }
681
+ /**
682
+ * 根据节点选择切到合适业务入口或技术视图,必要时显式解除隐藏筛选再定位。
683
+ * reveal 请求把目标带入视口,不代表执行该节点的业务操作。
684
+ */
496
685
  function selectNode(key, reveal = false) {
686
+ if (mode === 'business') {
687
+ const node = byKey(key);
688
+ const processKey = node.kind === 'stage' ? `process:${node.attrs.process}` : key;
689
+ const blocks = businessBlocks(model, snapshot.presentation.labels, showSystem || isSystem(byKey(key)));
690
+ const block = blocks.find((b) => b.objects.some((n) => n.key === key) || b.flows.some((n) => n.key === key) || b.processes.some(n => n.key === processKey));
691
+ if (block) {
692
+ showSystem ||= block.system;
693
+ navigateBusiness({
694
+ block: block.id,
695
+ flow: node.kind === 'aggregate' ? (businessJourneys(block, model).some(n => n.key === key) ? key : null) : processKey,
696
+ step: node.kind === 'stage' ? key : null,
697
+ branches: node.kind === 'stage' ? '1' : null,
698
+ tab: null,
699
+ source: null,
700
+ system: showSystem ? '1' : null,
701
+ });
702
+ return;
703
+ }
704
+ mode = 'all';
705
+ enabled = new Set(Object.keys(kinds));
706
+ renderFilters();
707
+ renderGraph();
708
+ }
497
709
  searchTarget = null;
498
710
  selectedEdge = null;
499
711
  selected = key;
500
712
  emphasizeSelection = true;
501
713
  if (mode === 'structure' && !tableOwner(cards, key)) {
502
- mode = ['state', 'capability', 'entry'].includes(byKey(key).kind) ? 'all' : 'business';
503
- enabled = new Set(mode === 'all' ? Object.keys(kinds) : businessKinds);
714
+ mode = 'all';
715
+ enabled = new Set(Object.keys(kinds));
504
716
  aggregate = null;
505
717
  focus = null;
506
718
  renderFilters();
@@ -518,6 +730,7 @@ function selectNode(key, reveal = false) {
518
730
  }
519
731
  highlight();
520
732
  renderInspector();
733
+ address({ view: mode, node: key, object: aggregate, system: showSystem ? '1' : null });
521
734
  if (reveal && mode === 'structure') {
522
735
  searchTarget = key;
523
736
  requestAnimationFrame(centerSearchResult);
@@ -525,6 +738,9 @@ function selectNode(key, reveal = false) {
525
738
  }
526
739
  /** 搜索到长画布下方的字段时将该行移入视口。窄屏详情高度变化可能再次触发
527
740
  * ResizeObserver,适应画布后仍需保留搜索位置,否则字段会瞬间跳回屏幕外。 */
741
+ /**
742
+ * 把结构视图搜索到的具体字段行移入视口,保留 resize 后的阅读目标;目标已清除则忽略旧帧。
743
+ */
528
744
  function centerSearchResult() {
529
745
  // 等待绘制期间切换视图会清除目标,这一帧就不再执行旧的搜索定位。
530
746
  if (!searchTarget)
@@ -539,6 +755,9 @@ function centerSearchResult() {
539
755
  camera.y = svg.clientHeight / 2 - (position.y + offset) * camera.scale;
540
756
  applyCamera();
541
757
  }
758
+ /**
759
+ * 选中真实关系并确保两端可见;结构模式不能表达的关系切到完整本体,随后刷新解释面板。
760
+ */
542
761
  function selectEdge(edge) {
543
762
  searchTarget = null;
544
763
  selectedEdge = edge;
@@ -567,6 +786,9 @@ function selectEdge(edge) {
567
786
  renderInspector();
568
787
  element('inspector').scrollTop = 0;
569
788
  }
789
+ /**
790
+ * 渲染连线原因、用途、端点及源码依据,解释复用 CLI 的共享规则,不按布局猜测执行关系。
791
+ */
570
792
  function renderEdgeInspector(panel, edge) {
571
793
  const explanation = explainEdge(edge, model, snapshot.presentation.labels);
572
794
  const top = html('div', 'inspector-top');
@@ -603,7 +825,13 @@ function renderEdgeInspector(panel, edge) {
603
825
  ? `${location.file}:${location.line ?? 1}${location !== node ? '(所属业务对象声明)' : ''}`
604
826
  : '来自框架包,当前项目未记录源码位置。'));
605
827
  }
828
+ /**
829
+ * 重建技术详情面板,优先显示选中边,再按节点类型显示字段、规则、实现与关联入口。
830
+ * 业务视图有独立详情故直接返回;所有动态文字通过 DOM 文本节点呈现。
831
+ */
606
832
  function renderInspector() {
833
+ if (mode === 'business')
834
+ return;
607
835
  const panel = element('inspector');
608
836
  panel.replaceChildren();
609
837
  if (selectedEdge) {
@@ -739,6 +967,9 @@ function renderInspector() {
739
967
  for (const [key, label] of Object.entries({
740
968
  event: '事件',
741
969
  command: '调用命令',
970
+ tx: '事务边界',
971
+ order: '同事件执行顺序',
972
+ collection: '有界集合',
742
973
  process: '审批流程',
743
974
  cron: '调度表达式',
744
975
  connector: '连接器',
@@ -750,6 +981,7 @@ function renderInspector() {
750
981
  through: '自动中间表',
751
982
  virtual: '不占主表列',
752
983
  readOnly: '只读关联',
984
+ filePolicy: '文件限制',
753
985
  optional: '可选字段',
754
986
  acquires: '获取资源',
755
987
  releases: '释放资源',
@@ -773,6 +1005,7 @@ function renderInspector() {
773
1005
  }
774
1006
  else
775
1007
  source.append(html('p', 'source-note', node.kind === 'entry' ? '由新建命令的迁移关系推导。' : '来自框架包,当前项目未记录源码位置。'));
1008
+ source.append(sourcePreview(node.key, false));
776
1009
  const relations = model.edges.filter((e) => e.from === node.key || e.to === node.key);
777
1010
  const relationSection = section('关联关系', relations.length);
778
1011
  if (relations.length)
@@ -798,7 +1031,16 @@ function renderInspector() {
798
1031
  }
799
1032
  /** 把会直接影响阅读理解的属性值翻译为业务名称;SQL 表名、cron 和折叠的
800
1033
  * 原始元数据仍保持技术原文,方便开发者核对实现。 */
1034
+ /**
1035
+ * 把节点属性转成可读值,特别保留事务、集合上限和资源标签语义;未知值按字符串展示。
1036
+ */
801
1037
  function detailValue(key, value) {
1038
+ if (key === 'collection') {
1039
+ const collection = value;
1040
+ return `最多 ${collection.maxItems} 项,按 ${collection.orderBy} 排序;串行执行,失败遵循事务边界`;
1041
+ }
1042
+ if (key === 'tx')
1043
+ return value === 'same' ? '与触发命令共同提交或回滚' : '异步 outbox';
802
1044
  if (typeof value === 'boolean')
803
1045
  return value ? '是' : '否';
804
1046
  if (key === 'event' || key === 'command')
@@ -838,23 +1080,15 @@ function detailValue(key, value) {
838
1080
  };
839
1081
  return ['kind', 'sensitive'].includes(key) ? (types[String(value)] ?? String(value)) : String(value);
840
1082
  }
1083
+ /**
1084
+ * 将约束中文解释委托共享业务规则,保证技术详情和业务地图用同一字段/额度口径。
1085
+ */
841
1086
  function constraintLabel(name, aggregateId) {
842
- const ceiling = /^ceiling\((.+)\)$/.exec(name);
843
- if (ceiling)
844
- return `${named(`${aggregateId}.${ceiling[1]}`, 'field')}不超过审批额度`;
845
- const sod = /^sod\.notSameAs\((.+)\)$/.exec(name);
846
- if (sod)
847
- return `审批人与${named(`${aggregateId}.${sod[1]}`, 'field')}不同`;
848
- const builtins = {
849
- stepUp: '需要二次认证',
850
- knownCapability: '能力点必须已声明',
851
- noEscalation: '不能授予超出自身的能力',
852
- noWiderScope: '不能授予超出自身的数据范围',
853
- noEscalationViaRoles: '不能通过分配角色提权',
854
- };
855
- return builtins[name] ?? name;
1087
+ return businessConstraintLabel(name, aggregateId, snapshot.presentation.labels);
856
1088
  }
857
1089
  const descriptions = {
1090
+ process: '引用真实业务声明的完整流程,区分人工下一步、自动触发和等待。',
1091
+ stage: '业务流程中的一个阶段,可展开查看规则、业务对象与实现代码。',
858
1092
  aggregate: '统一管理字段、状态、业务操作和数据范围的业务对象。',
859
1093
  command: '受权限和状态约束的业务写入入口。',
860
1094
  event: '命令产生的领域事件,用于连接后续业务协作。',
@@ -871,6 +1105,9 @@ const descriptions = {
871
1105
  capability: '从聚合声明派生的访问能力点。',
872
1106
  entry: '新建命令进入初始业务状态的虚拟起点。',
873
1107
  };
1108
+ /**
1109
+ * 按当前快照展示规则错误码、原因、修复建议和位置,不自动修复源码。
1110
+ */
874
1111
  function renderFindings() {
875
1112
  const list = element('findings-list');
876
1113
  list.replaceChildren();
@@ -884,6 +1121,10 @@ function renderFindings() {
884
1121
  list.append(item);
885
1122
  }
886
1123
  }
1124
+ /**
1125
+ * 复用共享排名检索节点并同时检索板块,显示有限候选和命中依据。
1126
+ * 点击候选更新导航并清空搜索框;未命中只提示换关键词,不判定业务不存在。
1127
+ */
887
1128
  function searchNodes() {
888
1129
  const query = element('search').value.trim().toLowerCase();
889
1130
  const results = element('search-results');
@@ -894,6 +1135,19 @@ function searchNodes() {
894
1135
  const matches = rankGraphNodes(model, query, snapshot.presentation.labels, {
895
1136
  descriptions: snapshot.presentation.descriptions,
896
1137
  });
1138
+ const matchingBlocks = businessBlocks(model, snapshot.presentation.labels, showSystem).filter((block) => block.title.toLowerCase().includes(query) || block.id.toLowerCase().includes(query));
1139
+ for (const block of matchingBlocks.slice(0, 5)) {
1140
+ const button = html('button', 'search-result');
1141
+ const names = html('span', 'search-names');
1142
+ names.append(html('strong', '', block.title), html('span', '', `${businessJourneys(block, model).length} 个业务流程`));
1143
+ button.append(html('small', '', '业务板块'), names);
1144
+ button.onclick = () => {
1145
+ navigateBusiness({ block: block.id, flow: null, step: null, tab: null, source: null });
1146
+ results.hidden = true;
1147
+ element('search').value = '';
1148
+ };
1149
+ results.append(button);
1150
+ }
897
1151
  for (const hit of matches.slice(0, 30)) {
898
1152
  const n = byKey(hit.key);
899
1153
  const button = html('button', 'search-result');
@@ -910,13 +1164,19 @@ function searchNodes() {
910
1164
  };
911
1165
  results.append(button);
912
1166
  }
913
- if (!matches.length)
914
- results.append(html('div', 'search-empty', '没有匹配的声明,试试命令名或字段名。'));
1167
+ if (!matches.length && !matchingBlocks.length)
1168
+ results.append(html('div', 'search-empty', '没有匹配的业务,试试业务名称、操作或代码标识。'));
915
1169
  }
1170
+ /**
1171
+ * 把当前平移和缩放应用到 SVG 并更新百分比显示,节点业务坐标保持不变。
1172
+ */
916
1173
  function applyCamera() {
917
1174
  viewport.setAttribute('transform', `translate(${camera.x},${camera.y}) scale(${camera.scale})`);
918
1175
  element('zoom-level').textContent = `${Math.round(camera.scale * 100)}%`;
919
1176
  }
1177
+ /**
1178
+ * 依据可见节点实际尺寸计算居中缩放;结构视图保持字段可读下限并保留搜索行定位。
1179
+ */
920
1180
  function fit() {
921
1181
  if (!visibleNodes.length)
922
1182
  return;
@@ -938,6 +1198,9 @@ function fit() {
938
1198
  if (mode === 'structure' && searchTarget)
939
1199
  centerSearchResult();
940
1200
  }
1201
+ /**
1202
+ * 以屏幕锚点缩放并限制倍率范围,清除临时搜索吸附,避免缩放时图像突然跳到别处。
1203
+ */
941
1204
  function zoom(factor, x = svg.clientWidth / 2, y = svg.clientHeight / 2) {
942
1205
  searchTarget = null;
943
1206
  const scale = Math.min(2.5, Math.max(0.15, camera.scale * factor));
@@ -986,6 +1249,9 @@ svg.addEventListener('pointermove', (event) => {
986
1249
  applyCamera();
987
1250
  }
988
1251
  });
1252
+ /**
1253
+ * 结束本次指针拖动;只有正常 pointerup 且未移动才按点击选择,取消不触发选择。
1254
+ */
989
1255
  const endDrag = (event) => {
990
1256
  if (!drag || drag.id !== event.pointerId)
991
1257
  return;
@@ -1010,7 +1276,7 @@ svg.addEventListener('wheel', (event) => {
1010
1276
  zoom(Math.exp(-event.deltaY * 0.0015), event.clientX - rect.left, event.clientY - rect.top);
1011
1277
  }, { passive: false });
1012
1278
  new ResizeObserver(() => {
1013
- if (snapshot) {
1279
+ if (snapshot && mode !== 'business') {
1014
1280
  if (mode === 'structure') {
1015
1281
  positions = layoutTables(visibleCards, visibleEdges, svg.clientWidth < 680 ? 1 : 2);
1016
1282
  updatePositions();
@@ -1018,12 +1284,26 @@ new ResizeObserver(() => {
1018
1284
  fit();
1019
1285
  }
1020
1286
  }).observe(svg);
1287
+ /**
1288
+ * 恢复业务首页并清除 URL 中板块、流程、步骤及技术选择,保留当前抽取快照。
1289
+ */
1021
1290
  function resetView() {
1022
- mode = 'structure';
1291
+ mode = 'business';
1023
1292
  aggregate = null;
1024
1293
  focus = null;
1025
1294
  showSystem = false;
1026
1295
  enabled = new Set(businessKinds);
1296
+ address({
1297
+ view: 'business',
1298
+ block: null,
1299
+ flow: null,
1300
+ step: null,
1301
+ tab: null,
1302
+ source: null,
1303
+ node: null,
1304
+ object: null,
1305
+ system: null,
1306
+ });
1027
1307
  renderFilters();
1028
1308
  renderGraph();
1029
1309
  }
@@ -1041,6 +1321,7 @@ element('system-toggle').onchange = (event) => {
1041
1321
  showSystem = event.target.checked;
1042
1322
  aggregate = null;
1043
1323
  focus = null;
1324
+ address({ system: showSystem ? '1' : null });
1044
1325
  renderFilters();
1045
1326
  renderGraph();
1046
1327
  };
@@ -1053,11 +1334,24 @@ document.querySelectorAll('[data-mode]').forEach((button) => {
1053
1334
  if (mode === 'structure' && selected)
1054
1335
  selected =
1055
1336
  tableOwner(cards, selected)?.node.key ?? cards.find((card) => !isSystem(card.node))?.node.key ?? null;
1337
+ address({
1338
+ view: mode,
1339
+ node: mode === 'business' ? null : selected,
1340
+ object: mode === 'business' ? null : aggregate,
1341
+ });
1056
1342
  renderFilters();
1057
1343
  renderGraph();
1058
1344
  renderInspector();
1059
1345
  };
1060
1346
  });
1347
+ window.addEventListener('popstate', () => {
1348
+ if (!snapshot)
1349
+ return;
1350
+ restoreAddress();
1351
+ renderFilters();
1352
+ renderGraph();
1353
+ renderInspector();
1354
+ });
1061
1355
  element('refresh').onclick = () => void load(true);
1062
1356
  element('search').addEventListener('input', searchNodes);
1063
1357
  element('search').addEventListener('focus', searchNodes);