@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
@@ -1,35 +1,65 @@
1
+ /**
2
+ * 已登录工作台的公共外壳:导航、当前账号、退出登录、Outlet 和唯一的业务助理。
3
+ * 业务页面经路由模块入口进入 Outlet;系统管理使用独立链接。
4
+ * 助理随页面更新语义快照,账号退出成功后清空查询缓存。
5
+ */
1
6
  // 应用壳组合模块公开入口,只持有导航和会话;表单、筛选、命令留在各业务模块。
2
7
  import { useState } from 'react';
8
+ import { Link, NavLink, Outlet, useLocation } from 'react-router-dom';
3
9
  import { useQueryClient } from '@tanstack/react-query';
4
10
  import { client, currentUser } from '@app/contracts';
5
- import { PurchaseOrdersPage } from '../modules/purchase';
6
- import { InventoryPage } from '../modules/inventory';
7
- import { ApprovalTasksPage, useApprovalTasks } from '../modules/approval';
11
+ import { useApprovalTasks } from '../modules/approval';
12
+ import { errorMessage } from '../shared/lib/error-message';
13
+ import { AssistantScope } from '../shared/ui/assistant-scope';
8
14
 
15
+ /**
16
+ * 渲染工作台公共区域并把子路由放入内容区。
17
+ * @param onLogout SDK 退出成功后通知 app 切换会话状态的回调。
18
+ * 本壳提供固定导航入口;目标路由和服务端分别处理页面访问与真实请求的权限。
19
+ * location.key 标识一次页面导航,用于防止新页面沿用上一张单据的助理上下文。
20
+ */
9
21
  export function WorkspaceLayout({ onLogout }: { onLogout: () => void }) {
10
- const [tab, setTab] = useState<'orders' | 'tasks' | 'stock'>('orders');
22
+ const [error, setError] = useState('');
23
+ const [busy, setBusy] = useState(false);
24
+ const location = useLocation();
25
+ const page = location.pathname.startsWith('/procurement/orders/')
26
+ ? '采购单详情'
27
+ : location.pathname === '/procurement/orders'
28
+ ? '采购单'
29
+ : location.pathname === '/approvals'
30
+ ? '审批待办'
31
+ : location.pathname === '/inventory'
32
+ ? '库存台账'
33
+ : location.pathname === '/workspace'
34
+ ? '工作台'
35
+ : '页面';
11
36
  const tasks = useApprovalTasks();
12
37
  const cache = useQueryClient();
13
38
  return (
39
+ <AssistantScope pageKey={location.key} fallback={{
40
+ context: { page: { id: 'workspace-page', title: page, kind: 'custom', route: location.pathname + location.search } },
41
+ suggestions: ['我在当前页面可以做什么?', '帮我查看待处理的审批'],
42
+ }}>
14
43
  <div className="workspace">
15
44
  <aside>
16
- <a className="brand" href="/">
45
+ <Link className="brand" to="/workspace">
17
46
  cage<span>采购工作台</span>
18
- </a>
47
+ </Link>
19
48
  <span className="nav-caption">工作空间</span>
20
49
  <nav>
21
50
  {(
22
51
  [
23
- ['orders', '01', '采购单'],
24
- ['tasks', '02', '审批待办'],
25
- ['stock', '03', '库存台账'],
52
+ ['/workspace', '00', '工作台'],
53
+ ['/procurement/orders', '01', '采购单'],
54
+ ['/approvals', '02', '审批待办'],
55
+ ['/inventory', '03', '库存台账'],
26
56
  ] as const
27
57
  ).map(([key, no, label]) => (
28
- <button key={key} className={tab === key ? 'selected' : ''} onClick={() => setTab(key)}>
58
+ <NavLink key={key} to={key} className={({ isActive }) => (isActive ? 'selected' : '')}>
29
59
  <span>{no}</span>
30
60
  {label}
31
- {key === 'tasks' && <b>{tasks.data?.length ?? 0}</b>}
32
- </button>
61
+ {key === '/approvals' && <b>{tasks.data?.length ?? 0}</b>}
62
+ </NavLink>
33
63
  ))}
34
64
  </nav>
35
65
  <div className="aside-bottom">
@@ -43,10 +73,15 @@ export function WorkspaceLayout({ onLogout }: { onLogout: () => void }) {
43
73
  </div>
44
74
  <button
45
75
  className="logout"
76
+ disabled={busy}
46
77
  onClick={async () => {
47
- await client.logout();
48
- cache.clear();
49
- onLogout();
78
+ setBusy(true);
79
+ const result = await client.logout();
80
+ setBusy(false);
81
+ if (result.ok) {
82
+ cache.clear();
83
+ onLogout();
84
+ } else setError(errorMessage(result));
50
85
  }}
51
86
  >
52
87
  退出登录
@@ -55,16 +90,20 @@ export function WorkspaceLayout({ onLogout }: { onLogout: () => void }) {
55
90
  </aside>
56
91
  <main className="content">
57
92
  <header>
58
- <span>采购管理 / {tab === 'orders' ? '采购单' : tab === 'tasks' ? '审批待办' : '库存台账'}</span>
93
+ <span>采购管理 / {page}</span>
59
94
  <span className="live-dot">团队工作空间</span>
60
95
  </header>
61
- {tab === 'orders' && <PurchaseOrdersPage pendingTasks={tasks.data?.length} />}
62
- {tab === 'tasks' && <ApprovalTasksPage />}
63
- {tab === 'stock' && <InventoryPage />}
96
+ {error && (
97
+ <p className="error" role="alert">
98
+ {error}
99
+ </p>
100
+ )}
101
+ <Outlet />
64
102
  <div className="page-footer">
65
103
  CAGE / PROCUREMENT WORKSPACE<span>业务操作均受权限与数据范围约束</span>
66
104
  </div>
67
105
  </main>
68
106
  </div>
107
+ </AssistantScope>
69
108
  );
70
109
  }
@@ -1,3 +1,8 @@
1
+ /**
2
+ * 采购 Web 的浏览器启动入口:创建共享查询缓存,将应用路由挂到 root DOM 节点。
3
+ * 契约客户端负责网络与会话协议,页面只在 Provider 内消费 hooks;这里不注册领域或启动后端。
4
+ * 全局样式在此加载,账号切换时的缓存清理由 useSession 和应用壳负责。
5
+ */
1
6
  // 唯一浏览器启动入口:挂载 React、全局 Provider 和样式;业务从 app 组合进入。
2
7
  import { createRoot } from 'react-dom/client';
3
8
  import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
@@ -0,0 +1,61 @@
1
+ /**
2
+ * 人工待办的转办、委派和三种加签操作表单,由审批收件箱按当前任务快照打开。
3
+ * 选择来自业务协作名录,提交携带任务 revision 和必填原因;权限/同节点重复责任由引擎重查。
4
+ * 失败保留选人和原因;成功刷新真实任务并关闭。等待/受托任务不从页面打开本表单,不在前端改流程状态。
5
+ */
6
+ import { useState, type FormEvent } from 'react';
7
+ import { client } from '@app/contracts';
8
+ import type { ApprovalTask, ApprovalTaskAction } from '@yss123/cage-client';
9
+ import { ApprovalMemberPicker } from '../../../shared/ui/approval-member-picker';
10
+ import { errorMessage } from '../../../shared/lib/error-message';
11
+ import { useQueryClient } from '@tanstack/react-query';
12
+
13
+ /** 页面允许发起的人员管理操作,归还/领取/释放在任务行直接处理。 */
14
+ export type PersonnelOperation = 'transfer' | 'delegate' | 'parallel' | 'before' | 'after';
15
+ /** 业务名称与引擎 placement 对应;不引入额外执行步骤或暗示自动授予权限。 */
16
+ const labels = { transfer: '转办审批', delegate: '委派协助', parallel: '并行加签', before: '前加签', after: '后加签' } as const;
17
+ const descriptions = {
18
+ transfer: '将这项审批责任交给另一位人员,你将不再处理此任务。',
19
+ delegate: '请他人核对材料,受托人归还后仍由你决定。',
20
+ parallel: '你与新增人员可以同时处理,所有追加意见都是必签。',
21
+ before: '先请新增人员签署,全部完成后这项任务才回到你手中。',
22
+ after: '你先签署,随后激活新增人员的必签任务。',
23
+ };
24
+
25
+ /**
26
+ * task 与 operation 在打开时固定;任务变化以服务端冲突响应为准,不自动改用新版本重试。
27
+ * close 返回当前收件箱,成功通过查询缓存刷新;无效输入禁用提交,Esc/取消不产生写入。
28
+ */
29
+ export function TaskOperationDialog({ task, operation, close }: { task: ApprovalTask; operation: PersonnelOperation; close: () => void }) {
30
+ const [userIds, setUserIds] = useState<string[]>([]), [reason, setReason] = useState('');
31
+ const [busy, setBusy] = useState(false), [error, setError] = useState('');
32
+ const cache = useQueryClient();
33
+ const single = operation === 'transfer' || operation === 'delegate';
34
+ /**
35
+ * 将人员选择映射为对应动作;每次携带打开弹窗时的 revision,旧任务冲突时保留输入供用户核对。
36
+ * 只在服务端确认成功后刷新并关闭,不能把选中人员或提交请求本身视为已经完成交接。
37
+ */
38
+ async function submit(event: FormEvent) {
39
+ event.preventDefault();
40
+ if (busy || !userIds.length || !reason.trim()) return;
41
+ setBusy(true); setError('');
42
+ const input: ApprovalTaskAction = single
43
+ ? { action: operation, targetUserId: userIds[0], reason, expectedRevision: task.revision }
44
+ : { action: 'addSign', placement: operation, userIds, reason, expectedRevision: task.revision };
45
+ const result = await client.approvalTaskAction(task.id, input);
46
+ setBusy(false);
47
+ if (!result.ok) { setError(errorMessage(result)); return; }
48
+ await cache.invalidateQueries(); close();
49
+ }
50
+ return <div className="modal-backdrop"><section className="modal approval-operation-dialog" role="dialog" aria-modal="true" aria-labelledby="approval-operation-title"
51
+ onKeyDown={event => { if (event.key === 'Escape' && !busy) close(); }}>
52
+ <div className="section-head"><div><h2 id="approval-operation-title">{labels[operation]}</h2><p className="muted">{task.title}</p></div>
53
+ <button type="button" disabled={busy} onClick={close} aria-label="关闭操作">×</button></div>
54
+ <form onSubmit={submit}><p>{descriptions[operation]}</p>
55
+ <ApprovalMemberPicker value={userIds} onChange={setUserIds} max={single ? 1 : 20} exclude={[task.assigneeId, task.ownerId].filter((id): id is string => !!id)} disabled={busy} />
56
+ <label>操作原因<textarea autoFocus rows={3} maxLength={1000} required value={reason} disabled={busy} onChange={event => setReason(event.target.value)} placeholder="说明业务原因,供单据参与者查看" /></label>
57
+ {error && <p className="error" role="alert">{error}</p>}
58
+ <div className="actions"><button type="button" disabled={busy} onClick={close}>取消</button><button className="primary" disabled={busy || !userIds.length || !reason.trim()}>{busy ? '提交中…' : `确认${labels[operation]}`}</button></div>
59
+ </form>
60
+ </section></div>;
61
+ }
@@ -1,18 +1,26 @@
1
+ /**
2
+ * 当前账号本人、候选或等待加签任务的共享查询入口,默认待办供 app 数量组合复用。
3
+ * 任务分配与实际决策授权均来自服务端,不从角色名称在前端自行推导。
4
+ */
1
5
  import { useQuery } from '@tanstack/react-query';
2
6
  import { client } from '@app/contracts';
3
7
  import { errorMessage } from '../../../shared/lib/error-message';
4
8
 
5
- type Task = { id: string; businessKey: string; title: string; createdAt: string };
6
-
7
9
  /**
8
10
  * 审批是框架通用接口,不属于某个聚合的生成方法,因此请求封装在审批模块内。
9
11
  * 待办页面和导航角标复用同一缓存键,调用方不需要了解接口地址或响应形状。
10
12
  */
11
- export function useApprovalTasks() {
13
+ /**
14
+ * 在 React Query 中读取审批待办,非 ok 结果转为查询错误。
15
+ * view 默认 pending,与导航角标共享;candidates/waiting 使用独立缓存,不混入可决定的任务数量。
16
+ * 返回查询状态及 refetch;空数组表示当前结果没有待办,未加载或失败不等同于零条。
17
+ */
18
+ export function useApprovalTasks(view: 'pending' | 'candidates' | 'waiting' = 'pending') {
12
19
  return useQuery({
13
- queryKey: ['tasks'],
20
+ queryKey: ['tasks', view],
14
21
  queryFn: async () => {
15
- const result = await client.get<Task[]>('/api/approval/tasks');
22
+ // 使用框架任务协议保留 revision,避免页面决定丢失任务流转后的并发校验。
23
+ const result = await (view === 'candidates' ? client.approvalCandidateTasks() : client.approvalTasks(view));
16
24
  if (!result.ok) throw new Error(errorMessage(result));
17
25
  return result.data;
18
26
  },
@@ -1,2 +1,6 @@
1
+ /**
2
+ * approval 模块的公开入口,对 app 暴露审批待办页与共享待办查询。
3
+ * 外部组合通过本入口导入,页面、组件与内部 helper 的组织由模块自行维护。
4
+ */
1
5
  export { ApprovalTasksPage } from './pages/approval-tasks-page';
2
6
  export { useApprovalTasks } from './hooks/use-approval-tasks';
@@ -1,53 +1,104 @@
1
- // 审批待办独立成页;结论调用框架审批接口,领域约束仍在后端执行。
1
+ /**
2
+ * 审批收件箱使用 URL 的 view 切换本人、可领取和等待加签任务,刷新/前进后退保留视图。
3
+ * 通过 app 注入详情链接,界面调用客户端完成领取、释放、人员流转与决定;候选身份和版本仍由服务端校验。
4
+ * 原因是行内临时草稿,动作成功后由 useCommand 失效查询并重读;waiting 仅供查看,不显示决定入口。
5
+ */
6
+ import { useState } from 'react';
2
7
  import { client } from '@app/contracts';
3
- import { useCommand } from '../../../shared/hooks/use-command';
8
+ import type { ApprovalTask } from '@yss123/cage-client';
9
+ import { Link, useSearchParams } from 'react-router-dom';
10
+ import { useCommand, type RunCommand } from '../../../shared/hooks/use-command';
4
11
  import { Notice } from '../../../shared/ui/notice';
5
12
  import { PageHeading } from '../../../shared/ui/page-heading';
6
13
  import { useApprovalTasks } from '../hooks/use-approval-tasks';
14
+ import { AssistantPage } from '../../../shared/ui/assistant-scope';
15
+ import './approval-tasks.css';
16
+ import { TaskOperationDialog, type PersonnelOperation } from '../components/task-operation-dialog';
7
17
 
8
- export function ApprovalTasksPage() {
9
- const tasks = useApprovalTasks();
18
+ /** 三种任务视图进入查询参数;只有 pending 会计入原有导航待办数。 */
19
+ const views = { pending: '待我处理', candidates: '可领取', waiting: '等待加签' } as const;
20
+
21
+ /**
22
+ * 为一项任务展示顺序、意见和合法阶段入口。busy 来自整页,提交时防止同页重复操作。
23
+ * 领取/释放/委派归还必须人工填写原因;决定意见可选。每次都提交当前 revision,失败保留草稿供核对。
24
+ * @param task 服务端安全摘要;assigneeId 为空表示尚未领取,不可直接批准。
25
+ * @param orderUrl app 组合的详情 URL 生成器,不访问其他业务模块内部。
26
+ * @param run 统一结果/缓存处理;此组件不乐观修改任务或赋予权限。
27
+ */
28
+ function TaskRow({ task, orderUrl, busy, run }: { task: ApprovalTask; orderUrl: (id: string) => string; busy: boolean; run: RunCommand }) {
29
+ const [reason, setReason] = useState('');
30
+ const [operation, setOperation] = useState<PersonnelOperation | null>(null);
31
+ const waiting = task.status === 'waiting';
32
+ const candidate = task.assigneeId === null;
33
+ const delegated = task.delegation === 'pending';
34
+ const manage = (action: 'claim' | 'unclaim' | 'resolve', success: string) => run(
35
+ () => client.approvalTaskAction(task.id, { action, expectedRevision: task.revision, reason }), success);
36
+ const position = task.signPosition === 'before' ? '前签' : task.signPosition === 'after' ? '后签' : task.taskKind === 'additional' ? '并行加签' : null;
37
+ return (
38
+ <div className="task">
39
+ <div className="approval-task-summary">
40
+ <h3>{task.title}{position && <small className="muted"> · {position}</small>}</h3>
41
+ {!!task.branchPath?.length && <p className="muted">{task.branchPath.map(part => `${part.parallel} · ${part.branch}`).join(' / ')}</p>}
42
+ <p className="mono muted">PO-{task.businessKey.slice(0, 8).toUpperCase()}</p>
43
+ <p className="muted">金额 ¥{String(task.vars.amount ?? '—')}{task.vars.needsSpecialistReview === true ? ' · 含专业会签' : ''}</p>
44
+ <p className="muted">{waiting ? '前置签署完成后恢复处理' : candidate ? '领取后由你负责处理' : delegated ? '受托处理中,请先归还原审批人' : '请核对单据后提交意见'}</p>
45
+ </div>
46
+ <div className="approval-task-controls">
47
+ <div className="actions">
48
+ <Link className="route-link" to={orderUrl(task.businessKey)}>查看采购单 ↗</Link>
49
+ {!waiting && <input aria-label={`${task.title}处理意见`} placeholder={candidate || delegated ? '填写操作原因(必填)' : '审批意见;释放任务时必填'}
50
+ maxLength={1000} value={reason} disabled={busy} onChange={event => setReason(event.target.value)} />}
51
+ </div>
52
+ {!waiting && <div className="actions">
53
+ {candidate ? <button className="primary" disabled={busy || !reason.trim()} onClick={() => void manage('claim', '已领取,请在待我处理中继续')}>领取任务</button>
54
+ : delegated ? <button disabled={busy || !reason.trim()} onClick={() => void manage('resolve', '已归还原审批人')}>归还审批人</button>
55
+ : <>
56
+ {task.assignment === 'candidate' && <button disabled={busy || !reason.trim()} onClick={() => void manage('unclaim', '已释放到候选池')}>释放任务</button>}
57
+ <button disabled={busy} onClick={() => void run(() => client.decideApprovalTask(task.id, 'reject', { expectedRevision: task.revision, comment: reason }), '已驳回')}>驳回</button>
58
+ <button disabled={busy} onClick={() => void run(() => client.decideApprovalTask(task.id, 'return', { expectedRevision: task.revision, comment: reason }), '已退回修改')}>退回修改</button>
59
+ <button disabled={busy} className="primary" onClick={() => void run(() => client.decideApprovalTask(task.id, 'approve', { expectedRevision: task.revision, comment: reason }), '已通过审批')}>通过审批</button>
60
+ {task.actions.transfer && <button disabled={busy} onClick={() => setOperation('transfer')}>转办</button>}
61
+ {task.actions.delegate && <button disabled={busy} onClick={() => setOperation('delegate')}>委派</button>}
62
+ {task.actions.addSign && task.taskKind === 'original' && task.signPositions.map(position => <button key={position} disabled={busy}
63
+ onClick={() => setOperation(position)}>{position === 'before' ? '前加签' : position === 'after' ? '后加签' : '并行加签'}</button>)}
64
+ </>}
65
+ </div>}
66
+ </div>
67
+ {operation && <TaskOperationDialog task={task} operation={operation} close={() => setOperation(null)} />}
68
+ </div>
69
+ );
70
+ }
71
+
72
+ /**
73
+ * 读取当前视图并区分加载、错误与空结果;URL 中未知 view 按默认待办读取,不制造无效请求。
74
+ * @param orderUrl 由 app 将业务主键转为采购详情地址;组件只改变 view 参数,保留其他 URL 参数。
75
+ * 人员操作使用业务协作名录,不读取完整组织用户;动作政策与签序来自实例快照,不按最新声明猜测在途权限。
76
+ */
77
+ export function ApprovalTasksPage({ orderUrl }: { orderUrl: (id: string) => string }) {
78
+ const [params, setParams] = useSearchParams();
79
+ const selected = params.get('view');
80
+ const view = selected === 'candidates' || selected === 'waiting' ? selected : 'pending';
81
+ const tasks = useApprovalTasks(view);
10
82
  const { run, busy, message, clearMessage } = useCommand();
11
83
  return (
12
84
  <>
13
- <PageHeading eyebrow="APPROVAL INBOX" title="审批待办" description="处理分配给你的审批任务。" />
85
+ <AssistantPage context={{ page: { id: 'approval-inbox', title: '审批待办', kind: 'list', route: '/approvals' },
86
+ visibleContent: [{ id: 'visible-tasks', text: tasks.data ? `${views[view]}当前显示 ${tasks.data.length} 项,以重新查询为准。` : '审批任务正在读取或暂时不可用。' }],
87
+ }} suggestions={['查看当前待我处理的审批', '通过、驳回和退回修改有什么区别?']} />
88
+ <PageHeading eyebrow="APPROVAL INBOX" title="审批待办" description="领取、处理和跟进你的审批任务。" />
14
89
  {message && <Notice onClose={clearMessage}>{message}</Notice>}
15
- <section className="panel">
90
+ <section className="panel approval-inbox">
16
91
  <div className="section-head">
17
- <h2>待你处理</h2>
18
- <button onClick={() => void tasks.refetch()}>刷新</button>
92
+ <div className="actions" aria-label="审批任务视图">
93
+ {Object.entries(views).map(([key, label]) => <button key={key} disabled={busy} aria-pressed={key === view} className={key === view ? 'primary' : ''}
94
+ onClick={() => setParams(previous => { const next = new URLSearchParams(previous); if (key === 'pending') next.delete('view'); else next.set('view', key); return next; })}>{label}</button>)}
95
+ </div>
96
+ <button disabled={busy || tasks.isFetching} onClick={() => void tasks.refetch()}>刷新</button>
19
97
  </div>
20
98
  {tasks.isError && <p className="error">{tasks.error.message}</p>}
21
- {tasks.isPending && <p className="empty">正在读取待办…</p>}
22
- {tasks.data?.map((task) => (
23
- <div className="task" key={task.id}>
24
- <div>
25
- <h3>{task.title}</h3>
26
- <p className="mono muted">PO-{task.businessKey.slice(0, 8).toUpperCase()}</p>
27
- </div>
28
- <div className="actions">
29
- <button
30
- disabled={busy}
31
- onClick={() => run(() => client.post(`/api/approval/tasks/${task.id}/reject`), '已驳回')}
32
- >
33
- 驳回
34
- </button>
35
- <button
36
- disabled={busy}
37
- className="primary"
38
- onClick={() => run(() => client.post(`/api/approval/tasks/${task.id}/approve`), '已通过审批')}
39
- >
40
- 通过审批
41
- </button>
42
- </div>
43
- </div>
44
- ))}
45
- {tasks.data?.length === 0 && (
46
- <div className="empty">
47
- <h3>待办已清空</h3>
48
- <p>新任务分配给你后会显示在这里。</p>
49
- </div>
50
- )}
99
+ {tasks.isPending && <p className="empty">正在读取任务…</p>}
100
+ {tasks.data?.map(task => <TaskRow key={`${task.id}:${task.revision}`} task={task} orderUrl={orderUrl} busy={busy} run={run} />)}
101
+ {tasks.data?.length === 0 && <div className="empty"><h3>当前没有{views[view]}的任务</h3><p>任务分配或签署顺序变化后,可刷新查看。</p></div>}
51
102
  </section>
52
103
  </>
53
104
  );
@@ -0,0 +1,18 @@
1
+ /**
2
+ * 审批收件箱局部布局,沿用工作台配色与按钮;将意见、详情及提交分行,避免窄屏压缩链接。
3
+ * 只作用于审批模块,桌面保留事项/操作两栏,空间不足自动换行;等待阶段由组件省略操作控件。
4
+ */
5
+ .approval-inbox .task { flex-wrap: wrap; gap: 20px; }
6
+ .approval-task-summary { flex: 1 1 240px; }
7
+ .approval-task-controls { display: grid; gap: 12px; flex: 0 1 420px; }
8
+ .approval-task-controls .actions { align-items: center; flex-wrap: wrap; }
9
+ .approval-task-controls .route-link { white-space: nowrap; }
10
+ .approval-task-controls input { min-width: 180px; flex: 1; }
11
+ .approval-operation-dialog { width: min(760px, calc(100vw - 32px)); max-height: calc(100vh - 48px); overflow-y: auto; }
12
+ .approval-operation-dialog form { padding: 24px; }
13
+ .approval-operation-dialog textarea { width: 100%; }
14
+ .approval-inbox .section-head { gap: 16px; flex-wrap: wrap; }
15
+ @media (max-width: 660px) {
16
+ .approval-task-controls { flex-basis: 100%; }
17
+ .approval-inbox .task { padding: 20px; }
18
+ }
@@ -1 +1,5 @@
1
+ /**
2
+ * auth 模块的公开入口,对 app 暴露登录页。
3
+ * 外部组合通过本入口导入,页面、组件与内部 helper 的组织由模块自行维护。
4
+ */
1
5
  export { LoginPage } from './pages/login-page';
@@ -1,11 +1,23 @@
1
+ /**
2
+ * 采购应用认证页面,收集账号密码并调用契约客户端登录。
3
+ * 会话协议和当前能力同步由 SDK 负责;成功后的安全回跳交给 app 路由层。
4
+ */
1
5
  // 登录页属于认证模块;表单反馈留在模块内,会话切换由 app 处理。
2
6
  import { useState, type FormEvent } from 'react';
3
7
  import { client } from '@app/contracts';
4
8
  import { errorMessage } from '../../../shared/lib/error-message';
5
9
 
10
+ /**
11
+ * 维护提交中与失败提示,成功调用 onLogin 通知路由切换。
12
+ * 不在组件内持久化密码,不自行跳转未校验的 returnTo。
13
+ */
6
14
  export function LoginPage({ onLogin }: { onLogin: () => void }) {
7
15
  const [error, setError] = useState('');
8
16
  const [busy, setBusy] = useState(false);
17
+ /**
18
+ * 阻止浏览器原生表单跳转,读取本次输入并等待 client.login。
19
+ * 成功后由 app 进入已登录路由;错误通过统一映射显示,输入与凭证不写入日志。
20
+ */
9
21
  async function submit(event: FormEvent<HTMLFormElement>) {
10
22
  event.preventDefault();
11
23
  setBusy(true);
@@ -1 +1,5 @@
1
+ /**
2
+ * inventory 模块的公开入口,对 app 暴露库存页。
3
+ * 外部组合通过本入口导入,页面、组件与内部 helper 的组织由模块自行维护。
4
+ */
1
5
  export { InventoryPage } from './pages/inventory-page';
@@ -1,14 +1,43 @@
1
+ /**
2
+ * 库存示例页,读取库存安全列表并通过生成命令创建库存记录。
3
+ * 这只是采购范例中的库存展示与输入入口,资源占用和释放仍通过领域流程落实。
4
+ */
1
5
  // 库存模块只管理台账页面,登记物料通过生成的 Inventory.create 命令。
2
6
  import { can, inventory, useInventoryList } from '@app/contracts';
3
7
  import { useCommand } from '../../../shared/hooks/use-command';
4
8
  import { Notice } from '../../../shared/ui/notice';
5
9
  import { PageHeading } from '../../../shared/ui/page-heading';
10
+ import { QueryFailure } from '../../../shared/ui/page-state';
11
+ import { AssistantPage } from '../../../shared/ui/assistant-scope';
6
12
 
13
+ /**
14
+ * 读取最多前一百条库存并展示查询失败、加载和空结果;列表不代表系统全部库存。
15
+ * 创建成功后重置表单并刷新查询,失败保留输入。助理上下文只列当前可见记录 ID,服务端仍核验读取范围。
16
+ */
7
17
  export function InventoryPage() {
8
18
  const stock = useInventoryList({ pageSize: 100 });
9
19
  const { run, busy, message, clearMessage } = useCommand();
20
+ if (stock.isPending)
21
+ return (
22
+ <p className="empty" role="status">
23
+ 正在读取库存台账…
24
+ </p>
25
+ );
26
+ // 页面已打开后权限仍可能变化,必须处理安全接口的拒绝,不能把失败展示成空台账。
27
+ if (stock.isError)
28
+ return (
29
+ <QueryFailure
30
+ error={stock.error}
31
+ to="/workspace"
32
+ label="返回工作台"
33
+ retry={() => void stock.refetch()}
34
+ />
35
+ );
10
36
  return (
11
37
  <>
38
+ <AssistantPage context={{ page: { id: 'inventory', title: '库存台账', kind: 'list', route: '/inventory' },
39
+ view: { aggregate: 'Inventory', input: { pageSize: 100 }, visibleIds: stock.data.items.map(item => item.id) },
40
+ }} suggestions={['汇总当前可见的物料库存', '查询库存时有哪些权限限制?']} />
12
41
  <PageHeading eyebrow="INVENTORY" title="库存台账" description="查看物料与当前登记数量。" />
13
42
  {message && <Notice onClose={clearMessage}>{message}</Notice>}
14
43
  <section className="panel">
@@ -48,7 +77,6 @@ export function InventoryPage() {
48
77
  </button>
49
78
  </form>
50
79
  )}
51
- {stock.isError && <p className="error">{stock.error.message}</p>}
52
80
  <table>
53
81
  <thead>
54
82
  <tr>
@@ -0,0 +1,67 @@
1
+ /**
2
+ * 采购单审批轨迹展示,按单据与版本读取服务端整理后的轮次和步骤。
3
+ * AI 与人工状态使用同一记录来源;并行节点按服务端分支路径展示,序号仅定位节点、不代表串行先后。
4
+ * 受限详情不显示理由,不能根据缺少细节推断未执行;该组件只消费框架历史,不实现审批调度。
5
+ */
6
+ import { useInfiniteQuery, useQuery } from '@tanstack/react-query';
7
+ import { client } from '@yss123/cage-client';
8
+ import { useApprovalMembers } from '../../../shared/ui/approval-member-picker';
9
+
10
+ /** 人工操作与引擎自动激活都来自已提交历史;未知动作保留原值,不能伪装成通过。 */
11
+ const actionLabels: Record<string, string> = { transfer: '转办', delegate: '委派协助', resolve: '归还审批人', addSign: '增加签署人', claim: '领取任务', unclaim: '释放任务', approved: '通过审批', rejected: '驳回', returned: '退回修改', cancelled: '取消流程', activated: '激活等待任务', skipped: '结束其余待办', advanced: '推进审批分支', urged: '申请人催办', reminded: '流程时限提醒' };
12
+ const positionLabels: Record<string, string> = { before: '前加签', after: '后加签', parallel: '并行加签' };
13
+
14
+ /**
15
+ * 运行、步骤与人工待办状态的展示映射,未知状态仍由页面按实际值处理。
16
+ */
17
+ const status: Record<string, string> = { queued: '待执行', running: '处理中', passed: '已通过', approved: '已通过', returned: '已退回修改', rejected: '已拒绝', manual: '待人工接管', waiting_manual: '待人工接管', waiting: '待人工审批', cancelled: '已取消', failed: '执行失败', pending: '待处理', skipped: '未执行' };
18
+ /**
19
+ * id 为采购单标识,version 使业务变更后查询重新取数,pending 决定是否每 1500ms 刷新。
20
+ * 只显示历史,不执行审批;detailRestricted 分支尊重服务端裁剪,人工接管也不等于通过。
21
+ */
22
+ export function ApprovalHistory({ id, version, pending }: { id: string; version: number; pending: boolean }) {
23
+ const history = useQuery({ queryKey: ['approval-history', id, version], queryFn: async () => {
24
+ const result = await client.approvalHistory('PurchaseOrder', id);
25
+ if (!result.ok) throw new Error(`审批记录读取失败:${result.code}`);
26
+ return result.data;
27
+ }, refetchInterval: pending ? 1500 : false });
28
+ const members = useApprovalMembers(1, true);
29
+ // 跨轮次动作按服务端游标递增分页;轮询重读已经打开的页,避免只更新首屏或丢失后续意见。
30
+ const actions = useInfiniteQuery({ queryKey: ['approval-task-history', id], initialPageParam: undefined as string | undefined,
31
+ queryFn: async ({ pageParam }) => {
32
+ const result = await client.approvalTaskHistory('po-approval', 'PurchaseOrder', id, { after: pageParam, limit: 50 });
33
+ if (!result.ok) throw new Error(`操作记录读取失败:${result.code}`);
34
+ return result.data;
35
+ }, getNextPageParam: last => last.nextCursor ?? undefined, refetchInterval: pending ? 1500 : false });
36
+ const person = (userId: string | null) => userId ? members.data?.items.find(member => member.userId === userId)?.displayName ?? userId.slice(0, 8) : '系统';
37
+ return <section className="panel approval-history"><div className="section-head"><h2>审批记录</h2><span className="muted">退回后重新提交,从第一步重新审核</span></div>
38
+ {history.isPending && <p className="muted">正在读取审核记录…</p>}
39
+ {history.isError && <p role="alert">{history.error.message}</p>}
40
+ {history.data?.length === 0 && <p className="muted">提交后按已配置流程审批,实际环节和并行分支将在此显示。</p>}
41
+ {history.data?.map((round, index) => <div className="review-round" key={round.id}><h3>第 {history.data.length - index} 轮 · {status[round.status] ?? round.status}</h3>
42
+ {(round.currentSteps?.length ?? 0) > 1 && <p className="muted">当前有 {round.currentSteps!.length} 个审批环节并行办理,全部完成后才继续。</p>}
43
+ {round.steps.map(step => <div className="review-step" key={step.index}><strong>{step.index + 1}. {step.title ?? (step.kind === 'ai' ? 'AI 材料预审' : '人工审批')} · {status[step.status] ?? step.status}</strong>
44
+ {!!step.branchPath?.length && <p className="muted">{step.branchPath.map(part => `${part.parallel} · ${part.branch}`).join(' / ')}</p>}
45
+ {step.detailRestricted ? <p>当前权限无法查看审核解释。</p> : <>{step.decision && <p>{step.decision.reason}</p>}{step.decision?.suggestions.map((text, i) => <p className="review-suggestion" key={i}>{text}</p>)}</>}
46
+ </div>)}
47
+ </div>)}
48
+ <div className="review-actions"><h3>人员流转与处理意见</h3>
49
+ {actions.isPending && <p role="status">正在读取操作记录…</p>}
50
+ {actions.isError && <p role="alert">{actions.error.message} <button onClick={() => void actions.refetch()}>重试</button></p>}
51
+ {actions.data?.pages.flatMap(page => page.items).map(item => {
52
+ const placement = typeof item.details.placement === 'string' ? positionLabels[item.details.placement] : undefined;
53
+ const targets = Array.isArray(item.details.userIds) ? item.details.userIds.filter((value): value is string => typeof value === 'string') : [];
54
+ const to = typeof item.details.to === 'string' ? item.details.to : null;
55
+ const roundIndex = history.data?.findIndex(round => round.id === item.instanceId) ?? -1;
56
+ return <article className="review-step" key={item.id}>
57
+ <strong>{person(item.actorId)} · {placement ?? actionLabels[item.action] ?? item.action}</strong>
58
+ <small className="muted">{roundIndex >= 0 ? `第 ${history.data!.length - roundIndex} 轮 · ` : ''}{new Date(item.createdAt).toLocaleString('zh-CN')}</small>
59
+ {targets.length > 0 ? <p>签署人:{targets.map(person).join('、')}</p> : to && ['transfer', 'delegate', 'resolve'].includes(item.action) ? <p>交给:{person(to)}</p> : null}
60
+ {item.reason && <p>{item.reason}</p>}
61
+ </article>;
62
+ })}
63
+ {actions.data?.pages[0].items.length === 0 && <p className="muted">尚无人工操作记录。</p>}
64
+ {actions.hasNextPage && <button disabled={actions.isFetchingNextPage} onClick={() => void actions.fetchNextPage()}>加载后续记录</button>}
65
+ </div>
66
+ </section>;
67
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * 采购详情的附件展示与草稿编辑区,将上传准备和领域关联保存明确分开。
3
+ * 读取到新版本后重新采用服务端附件列表并收起编辑,避免旧草稿覆盖已变化记录。
4
+ */
5
+ import { useEffect, useState } from 'react';
6
+ import { can, purchaseOrder, PurchaseOrderFileFields, type PurchaseOrder } from '@app/contracts';
7
+ import { AttachmentUpload, FileLink } from '../../../shared/ui/attachment-upload';
8
+ import { useCommand } from '../../../shared/hooks/use-command';
9
+
10
+ /**
11
+ * order 为已读取的采购记录,包含版本、状态和已绑定附件 ID。
12
+ * 仅草稿且具有 setAttachments 能力时显示编辑入口;保存传入 id 与 version,服务端重新校验。
13
+ * value 是临时选择列表,移除或上传不会自动修改单据;成功后的缓存刷新带回正式结果。
14
+ */
15
+ export function OrderAttachments({ order }: { order: PurchaseOrder }) {
16
+ const [editing, setEditing] = useState(false);
17
+ const [value, setValue] = useState(order.attachments);
18
+ const [uploading, setUploading] = useState(false);
19
+ const { run, busy, message } = useCommand();
20
+ useEffect(() => { setValue(order.attachments); setEditing(false); }, [order.version, order.attachments]);
21
+ return <section aria-label="采购附件">
22
+ <div className="section-head"><h2>采购附件</h2>{order.status === 'draft' && can('PurchaseOrder.setAttachments') && <button type="button" onClick={() => setEditing(!editing)}>{editing ? '收起编辑' : '编辑附件'}</button>}</div>
23
+ {editing ? <>
24
+ <AttachmentUpload command="PurchaseOrder.setAttachments" field="attachments" targetId={order.id} policy={PurchaseOrderFileFields.attachments} value={value} onChange={setValue} onBusyChange={setUploading} />
25
+ <button type="button" disabled={uploading || busy} onClick={() => run(() => purchaseOrder.setAttachments(order.id, { attachments: value }, order.version), '附件已保存')}>保存附件</button>
26
+ {message && <p role="status">{message}</p>}
27
+ </> : order.attachments.length ? <ul>{order.attachments.map(id => <li key={id}><FileLink id={id} /></li>)}</ul> : <p className="muted">暂无附件</p>}
28
+ </section>;
29
+ }