@yss123/cage-cli 0.1.0 → 0.3.0

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