@yss123/cage-cli 0.0.0-stage → 0.2.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 (499) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +40 -2
  3. package/bin/cage.js +6 -0
  4. package/bin/create-cage-app.js +6 -0
  5. package/dist/analyze.d.ts +18 -0
  6. package/dist/analyze.js +28 -0
  7. package/dist/analyze.js.map +1 -0
  8. package/dist/baseline.d.ts +5 -0
  9. package/dist/baseline.js +50 -0
  10. package/dist/baseline.js.map +1 -0
  11. package/dist/budget.d.ts +7 -0
  12. package/dist/budget.js +52 -0
  13. package/dist/budget.js.map +1 -0
  14. package/dist/config.d.ts +30 -0
  15. package/dist/config.js +46 -0
  16. package/dist/config.js.map +1 -0
  17. package/dist/context.d.ts +72 -0
  18. package/dist/context.js +202 -0
  19. package/dist/context.js.map +1 -0
  20. package/dist/create-prompt.d.ts +5 -0
  21. package/dist/create-prompt.js +50 -0
  22. package/dist/create-prompt.js.map +1 -0
  23. package/dist/create.d.ts +18 -0
  24. package/dist/create.js +64 -0
  25. package/dist/create.js.map +1 -0
  26. package/dist/derive.d.ts +14 -0
  27. package/dist/derive.js +163 -0
  28. package/dist/derive.js.map +1 -0
  29. package/dist/dev.d.ts +2 -0
  30. package/dist/dev.js +116 -0
  31. package/dist/dev.js.map +1 -0
  32. package/dist/env.d.ts +1 -0
  33. package/dist/env.js +15 -0
  34. package/dist/env.js.map +1 -0
  35. package/dist/findings.d.ts +11 -0
  36. package/dist/findings.js +13 -0
  37. package/dist/findings.js.map +1 -0
  38. package/dist/gen/contracts.d.ts +6 -0
  39. package/dist/gen/contracts.js +188 -0
  40. package/dist/gen/contracts.js.map +1 -0
  41. package/dist/gen/index.d.ts +19 -0
  42. package/dist/gen/index.js +177 -0
  43. package/dist/gen/index.js.map +1 -0
  44. package/dist/gen/zod-code.d.ts +7 -0
  45. package/dist/gen/zod-code.js +163 -0
  46. package/dist/gen/zod-code.js.map +1 -0
  47. package/dist/graph-command.d.ts +11 -0
  48. package/dist/graph-command.js +67 -0
  49. package/dist/graph-command.js.map +1 -0
  50. package/dist/graph-model.d.ts +21 -0
  51. package/dist/graph-model.js +101 -0
  52. package/dist/graph-model.js.map +1 -0
  53. package/dist/graph-presentation.d.ts +11 -0
  54. package/dist/graph-presentation.js +25 -0
  55. package/dist/graph-presentation.js.map +1 -0
  56. package/dist/graph-query.d.ts +171 -0
  57. package/dist/graph-query.js +242 -0
  58. package/dist/graph-query.js.map +1 -0
  59. package/dist/graph-relations.d.ts +14 -0
  60. package/dist/graph-relations.js +142 -0
  61. package/dist/graph-relations.js.map +1 -0
  62. package/dist/graph-search.d.ts +21 -0
  63. package/dist/graph-search.js +63 -0
  64. package/dist/graph-search.js.map +1 -0
  65. package/dist/graph-snapshot.d.ts +11 -0
  66. package/dist/graph-snapshot.js +29 -0
  67. package/dist/graph-snapshot.js.map +1 -0
  68. package/dist/graph.d.ts +11 -0
  69. package/dist/graph.js +105 -0
  70. package/dist/graph.js.map +1 -0
  71. package/dist/impact.d.ts +34 -0
  72. package/dist/impact.js +235 -0
  73. package/dist/impact.js.map +1 -0
  74. package/dist/index.d.ts +20 -0
  75. package/dist/index.js +22 -0
  76. package/dist/index.js.map +1 -0
  77. package/dist/init.d.ts +6 -0
  78. package/dist/init.js +131 -0
  79. package/dist/init.js.map +1 -0
  80. package/dist/load.d.ts +6 -0
  81. package/dist/load.js +17 -0
  82. package/dist/load.js.map +1 -0
  83. package/dist/main.d.ts +1 -0
  84. package/dist/main.js +221 -0
  85. package/dist/main.js.map +1 -0
  86. package/dist/migrate.d.ts +4 -0
  87. package/dist/migrate.js +30 -0
  88. package/dist/migrate.js.map +1 -0
  89. package/dist/ontology.d.ts +43 -0
  90. package/dist/ontology.js +280 -0
  91. package/dist/ontology.js.map +1 -0
  92. package/dist/process.d.ts +6 -0
  93. package/dist/process.js +39 -0
  94. package/dist/process.js.map +1 -0
  95. package/dist/project-structure.d.ts +8 -0
  96. package/dist/project-structure.js +94 -0
  97. package/dist/project-structure.js.map +1 -0
  98. package/dist/rules.d.ts +23 -0
  99. package/dist/rules.js +251 -0
  100. package/dist/rules.js.map +1 -0
  101. package/dist/static-check.d.ts +23 -0
  102. package/dist/static-check.js +222 -0
  103. package/dist/static-check.js.map +1 -0
  104. package/dist/sync.d.ts +5 -0
  105. package/dist/sync.js +118 -0
  106. package/dist/sync.js.map +1 -0
  107. package/dist/upgrade.d.ts +10 -0
  108. package/dist/upgrade.js +81 -0
  109. package/dist/upgrade.js.map +1 -0
  110. package/dist/verify.d.ts +7 -0
  111. package/dist/verify.js +88 -0
  112. package/dist/verify.js.map +1 -0
  113. package/dist/version.d.ts +4 -0
  114. package/dist/version.js +6 -0
  115. package/dist/version.js.map +1 -0
  116. package/graph-ui/app.js +1103 -0
  117. package/graph-ui/graph-model.js +100 -0
  118. package/graph-ui/graph-relations.js +141 -0
  119. package/graph-ui/graph-search.js +62 -0
  120. package/graph-ui/index.html +197 -0
  121. package/graph-ui/model.js +83 -0
  122. package/graph-ui/relations.js +2 -0
  123. package/graph-ui/structure.js +77 -0
  124. package/graph-ui/style.css +1719 -0
  125. package/package.json +60 -3
  126. package/templates/app/.dockerignore +10 -0
  127. package/templates/app/.env.example +61 -0
  128. package/templates/app/.github/workflows/cage.yml +44 -0
  129. package/templates/app/AGENTS.md +96 -0
  130. package/templates/app/Dockerfile +25 -0
  131. package/templates/app/README.md +88 -0
  132. package/templates/app/_gitignore +8 -0
  133. package/templates/app/apps/api/package.json +16 -0
  134. package/templates/app/apps/api/src/main.ts +10 -0
  135. package/templates/app/apps/api/src/worker.ts +14 -0
  136. package/templates/app/apps/api/tsconfig.json +5 -0
  137. package/templates/app/apps/web/index.html +13 -0
  138. package/templates/app/apps/web/package.json +22 -0
  139. package/templates/app/apps/web/src/app/app.tsx +18 -0
  140. package/templates/app/apps/web/src/app/styles/global.css +663 -0
  141. package/templates/app/apps/web/src/app/workspace-layout.tsx +70 -0
  142. package/templates/app/apps/web/src/main.tsx +13 -0
  143. package/templates/app/apps/web/src/modules/approval/hooks/use-approval-tasks.ts +20 -0
  144. package/templates/app/apps/web/src/modules/approval/index.ts +2 -0
  145. package/templates/app/apps/web/src/modules/approval/pages/approval-tasks-page.tsx +54 -0
  146. package/templates/app/apps/web/src/modules/auth/index.ts +1 -0
  147. package/templates/app/apps/web/src/modules/auth/pages/login-page.tsx +59 -0
  148. package/templates/app/apps/web/src/modules/inventory/index.ts +1 -0
  149. package/templates/app/apps/web/src/modules/inventory/pages/inventory-page.tsx +74 -0
  150. package/templates/app/apps/web/src/modules/purchase/components/purchase-order-form.tsx +60 -0
  151. package/templates/app/apps/web/src/modules/purchase/index.ts +2 -0
  152. package/templates/app/apps/web/src/modules/purchase/pages/purchase-orders-page.tsx +210 -0
  153. package/templates/app/apps/web/src/shared/hooks/use-command.ts +29 -0
  154. package/templates/app/apps/web/src/shared/lib/error-message.ts +15 -0
  155. package/templates/app/apps/web/src/shared/ui/notice.tsx +13 -0
  156. package/templates/app/apps/web/src/shared/ui/page-heading.tsx +28 -0
  157. package/templates/app/apps/web/tsconfig.json +11 -0
  158. package/templates/app/apps/web/vite.config.ts +19 -0
  159. package/templates/app/cage.config.json +114 -0
  160. package/templates/app/db/migrations/0001_init.sql +112 -0
  161. package/templates/app/docs/ai/README.md +77 -0
  162. package/templates/app/docs/ai/architecture.md +122 -0
  163. package/templates/app/docs/ai/ontology-context.md +117 -0
  164. package/templates/app/docs/ai/primitives.md +249 -0
  165. package/templates/app/docs/ai/project-structure.md +123 -0
  166. package/templates/app/docs/ai/purchase-example.md +97 -0
  167. package/templates/app/docs/ai/recipes.md +81 -0
  168. package/templates/app/docs/ai/relations.md +160 -0
  169. package/templates/app/docs/ai/transfers.md +92 -0
  170. package/templates/app/docs/ai/troubleshooting.md +60 -0
  171. package/templates/app/docs/ai/workflow.md +139 -0
  172. package/templates/app/docs/errors/CAGE-APPR-001.md +47 -0
  173. package/templates/app/docs/errors/CAGE-APPR-002.md +47 -0
  174. package/templates/app/docs/errors/CAGE-APPR-003.md +47 -0
  175. package/templates/app/docs/errors/CAGE-APPR-004.md +47 -0
  176. package/templates/app/docs/errors/CAGE-APPR-005.md +47 -0
  177. package/templates/app/docs/errors/CAGE-APPR-006.md +47 -0
  178. package/templates/app/docs/errors/CAGE-APPR-007.md +50 -0
  179. package/templates/app/docs/errors/CAGE-APPR-010.md +48 -0
  180. package/templates/app/docs/errors/CAGE-AUTH-001.md +47 -0
  181. package/templates/app/docs/errors/CAGE-BUDGET-001.md +47 -0
  182. package/templates/app/docs/errors/CAGE-BUDGET-002.md +47 -0
  183. package/templates/app/docs/errors/CAGE-BUDGET-003.md +47 -0
  184. package/templates/app/docs/errors/CAGE-CMD-002.md +47 -0
  185. package/templates/app/docs/errors/CAGE-CMD-003.md +47 -0
  186. package/templates/app/docs/errors/CAGE-CONN-001.md +47 -0
  187. package/templates/app/docs/errors/CAGE-CONN-002.md +47 -0
  188. package/templates/app/docs/errors/CAGE-CONN-003.md +47 -0
  189. package/templates/app/docs/errors/CAGE-CONN-004.md +47 -0
  190. package/templates/app/docs/errors/CAGE-CONN-005.md +47 -0
  191. package/templates/app/docs/errors/CAGE-CONN-006.md +47 -0
  192. package/templates/app/docs/errors/CAGE-CONN-007.md +47 -0
  193. package/templates/app/docs/errors/CAGE-CONN-008.md +47 -0
  194. package/templates/app/docs/errors/CAGE-CONN-009.md +47 -0
  195. package/templates/app/docs/errors/CAGE-CONN-010.md +47 -0
  196. package/templates/app/docs/errors/CAGE-CONN-011.md +47 -0
  197. package/templates/app/docs/errors/CAGE-CONN-012.md +47 -0
  198. package/templates/app/docs/errors/CAGE-CREATE-001.md +52 -0
  199. package/templates/app/docs/errors/CAGE-DECL-001.md +48 -0
  200. package/templates/app/docs/errors/CAGE-DECL-002.md +47 -0
  201. package/templates/app/docs/errors/CAGE-DECL-003.md +47 -0
  202. package/templates/app/docs/errors/CAGE-DECL-004.md +47 -0
  203. package/templates/app/docs/errors/CAGE-DEP-001.md +48 -0
  204. package/templates/app/docs/errors/CAGE-DEP-002.md +47 -0
  205. package/templates/app/docs/errors/CAGE-DEP-003.md +47 -0
  206. package/templates/app/docs/errors/CAGE-DEP-004.md +47 -0
  207. package/templates/app/docs/errors/CAGE-DEP-005.md +47 -0
  208. package/templates/app/docs/errors/CAGE-DLQ-001.md +48 -0
  209. package/templates/app/docs/errors/CAGE-ENV-001.md +52 -0
  210. package/templates/app/docs/errors/CAGE-EVENT-001.md +47 -0
  211. package/templates/app/docs/errors/CAGE-EVENT-002.md +50 -0
  212. package/templates/app/docs/errors/CAGE-FIELD-001.md +47 -0
  213. package/templates/app/docs/errors/CAGE-FIELD-002.md +47 -0
  214. package/templates/app/docs/errors/CAGE-FIELD-003.md +47 -0
  215. package/templates/app/docs/errors/CAGE-FIELD-004.md +47 -0
  216. package/templates/app/docs/errors/CAGE-GEN-001.md +48 -0
  217. package/templates/app/docs/errors/CAGE-GEN-002.md +47 -0
  218. package/templates/app/docs/errors/CAGE-GRANT-001.md +49 -0
  219. package/templates/app/docs/errors/CAGE-GRANT-002.md +48 -0
  220. package/templates/app/docs/errors/CAGE-GRANT-003.md +47 -0
  221. package/templates/app/docs/errors/CAGE-IMPACT-001.md +48 -0
  222. package/templates/app/docs/errors/CAGE-INIT-001.md +47 -0
  223. package/templates/app/docs/errors/CAGE-INIT-002.md +49 -0
  224. package/templates/app/docs/errors/CAGE-INIT-003.md +48 -0
  225. package/templates/app/docs/errors/CAGE-INIT-004.md +48 -0
  226. package/templates/app/docs/errors/CAGE-JOB-001.md +47 -0
  227. package/templates/app/docs/errors/CAGE-JOB-002.md +47 -0
  228. package/templates/app/docs/errors/CAGE-JOB-003.md +47 -0
  229. package/templates/app/docs/errors/CAGE-LINT-001.md +47 -0
  230. package/templates/app/docs/errors/CAGE-MIG-001.md +47 -0
  231. package/templates/app/docs/errors/CAGE-MIG-002.md +47 -0
  232. package/templates/app/docs/errors/CAGE-MIG-003.md +5 -0
  233. package/templates/app/docs/errors/CAGE-MIG-004.md +5 -0
  234. package/templates/app/docs/errors/CAGE-MIG-005.md +47 -0
  235. package/templates/app/docs/errors/CAGE-NAME-001.md +47 -0
  236. package/templates/app/docs/errors/CAGE-NAME-002.md +47 -0
  237. package/templates/app/docs/errors/CAGE-NAME-003.md +47 -0
  238. package/templates/app/docs/errors/CAGE-NAME-004.md +47 -0
  239. package/templates/app/docs/errors/CAGE-NAME-005.md +47 -0
  240. package/templates/app/docs/errors/CAGE-NAME-006.md +47 -0
  241. package/templates/app/docs/errors/CAGE-ORG-001.md +49 -0
  242. package/templates/app/docs/errors/CAGE-PAIR-002.md +50 -0
  243. package/templates/app/docs/errors/CAGE-QUERY-001.md +47 -0
  244. package/templates/app/docs/errors/CAGE-QUERY-002.md +47 -0
  245. package/templates/app/docs/errors/CAGE-QUERY-003.md +49 -0
  246. package/templates/app/docs/errors/CAGE-REACT-001.md +47 -0
  247. package/templates/app/docs/errors/CAGE-REACT-002.md +47 -0
  248. package/templates/app/docs/errors/CAGE-READS-001.md +47 -0
  249. package/templates/app/docs/errors/CAGE-REG-001.md +53 -0
  250. package/templates/app/docs/errors/CAGE-REG-002.md +48 -0
  251. package/templates/app/docs/errors/CAGE-REG-003.md +47 -0
  252. package/templates/app/docs/errors/CAGE-REL-001.md +64 -0
  253. package/templates/app/docs/errors/CAGE-ROUTE-001.md +47 -0
  254. package/templates/app/docs/errors/CAGE-SCOPE-001.md +47 -0
  255. package/templates/app/docs/errors/CAGE-SCOPE-002.md +47 -0
  256. package/templates/app/docs/errors/CAGE-SECRET-001.md +48 -0
  257. package/templates/app/docs/errors/CAGE-SECRET-002.md +47 -0
  258. package/templates/app/docs/errors/CAGE-SENS-001.md +48 -0
  259. package/templates/app/docs/errors/CAGE-SQL-001.md +47 -0
  260. package/templates/app/docs/errors/CAGE-SQL-002.md +47 -0
  261. package/templates/app/docs/errors/CAGE-STATE-001.md +49 -0
  262. package/templates/app/docs/errors/CAGE-STATE-002.md +47 -0
  263. package/templates/app/docs/errors/CAGE-STATE-003.md +47 -0
  264. package/templates/app/docs/errors/CAGE-STATE-004.md +47 -0
  265. package/templates/app/docs/errors/CAGE-STATE-005.md +48 -0
  266. package/templates/app/docs/errors/CAGE-STATE-010.md +48 -0
  267. package/templates/app/docs/errors/CAGE-STATE-011.md +48 -0
  268. package/templates/app/docs/errors/CAGE-STRUCT-001.md +51 -0
  269. package/templates/app/docs/errors/CAGE-STRUCT-002.md +51 -0
  270. package/templates/app/docs/errors/CAGE-SYNC-001.md +48 -0
  271. package/templates/app/docs/errors/CAGE-TEST-001.md +47 -0
  272. package/templates/app/docs/errors/CAGE-UNSAFE-001.md +48 -0
  273. package/templates/app/docs/errors/CAGE-UPGRADE-001.md +48 -0
  274. package/templates/app/docs/errors/README.md +307 -0
  275. package/templates/app/docs/errors/runtime.md +50 -0
  276. package/templates/app/package.json +22 -0
  277. package/templates/app/packages/contracts/package.json +16 -0
  278. package/templates/app/packages/contracts/src/aggregates/dept/index.ts +74 -0
  279. package/templates/app/packages/contracts/src/aggregates/inventory/index.ts +57 -0
  280. package/templates/app/packages/contracts/src/aggregates/inventory-lock/index.ts +52 -0
  281. package/templates/app/packages/contracts/src/aggregates/purchase-order/index.ts +72 -0
  282. package/templates/app/packages/contracts/src/aggregates/role/index.ts +85 -0
  283. package/templates/app/packages/contracts/src/aggregates/user/index.ts +89 -0
  284. package/templates/app/packages/contracts/src/index.ts +81 -0
  285. package/templates/app/packages/contracts/src/queries/index.ts +17 -0
  286. package/templates/app/packages/contracts/tsconfig.json +5 -0
  287. package/templates/app/packages/domain/package.json +23 -0
  288. package/templates/app/packages/domain/src/index.ts +6 -0
  289. package/templates/app/packages/domain/src/integrations/erp.ts +36 -0
  290. package/templates/app/packages/domain/src/modules/inventory/index.ts +2 -0
  291. package/templates/app/packages/domain/src/modules/inventory/inventory.ts +43 -0
  292. package/templates/app/packages/domain/src/modules/purchase/approvals.ts +18 -0
  293. package/templates/app/packages/domain/src/modules/purchase/index.ts +6 -0
  294. package/templates/app/packages/domain/src/modules/purchase/jobs.ts +13 -0
  295. package/templates/app/packages/domain/src/modules/purchase/purchase-order.test.ts +137 -0
  296. package/templates/app/packages/domain/src/modules/purchase/purchase-order.ts +122 -0
  297. package/templates/app/packages/domain/src/modules/purchase/queries.ts +10 -0
  298. package/templates/app/packages/domain/src/workflows/purchase-inventory.ts +24 -0
  299. package/templates/app/packages/domain/tsconfig.json +5 -0
  300. package/templates/app/pnpm-workspace.yaml +10 -0
  301. package/templates/app/renovate.json +5 -0
  302. package/templates/app/tsconfig.base.json +8 -0
  303. package/templates/blank/.dockerignore +10 -0
  304. package/templates/blank/.env.example +61 -0
  305. package/templates/blank/.github/workflows/cage.yml +44 -0
  306. package/templates/blank/AGENTS.md +96 -0
  307. package/templates/blank/Dockerfile +25 -0
  308. package/templates/blank/README.md +37 -0
  309. package/templates/blank/_gitignore +8 -0
  310. package/templates/blank/apps/api/package.json +15 -0
  311. package/templates/blank/apps/api/src/main.ts +11 -0
  312. package/templates/blank/apps/api/src/worker.ts +8 -0
  313. package/templates/blank/apps/api/tsconfig.json +5 -0
  314. package/templates/blank/apps/web/index.html +13 -0
  315. package/templates/blank/apps/web/package.json +22 -0
  316. package/templates/blank/apps/web/src/app/app.tsx +44 -0
  317. package/templates/blank/apps/web/src/app/styles/global.css +516 -0
  318. package/templates/blank/apps/web/src/app/workspace-layout.tsx +70 -0
  319. package/templates/blank/apps/web/src/main.tsx +13 -0
  320. package/templates/blank/apps/web/src/modules/auth/index.ts +1 -0
  321. package/templates/blank/apps/web/src/modules/auth/pages/login-page.tsx +87 -0
  322. package/templates/blank/apps/web/src/modules/workspace/index.ts +1 -0
  323. package/templates/blank/apps/web/src/modules/workspace/pages/home-page.tsx +45 -0
  324. package/templates/blank/apps/web/src/shared/lib/error-message.ts +11 -0
  325. package/templates/blank/apps/web/src/shared/ui/brand.tsx +11 -0
  326. package/templates/blank/apps/web/tsconfig.json +11 -0
  327. package/templates/blank/apps/web/vite.config.ts +19 -0
  328. package/templates/blank/cage.config.json +14 -0
  329. package/templates/blank/db/migrations/0001_init.sql +63 -0
  330. package/templates/blank/docs/ai/README.md +77 -0
  331. package/templates/blank/docs/ai/architecture.md +122 -0
  332. package/templates/blank/docs/ai/ontology-context.md +117 -0
  333. package/templates/blank/docs/ai/primitives.md +249 -0
  334. package/templates/blank/docs/ai/project-structure.md +123 -0
  335. package/templates/blank/docs/ai/purchase-example.md +97 -0
  336. package/templates/blank/docs/ai/recipes.md +81 -0
  337. package/templates/blank/docs/ai/relations.md +160 -0
  338. package/templates/blank/docs/ai/transfers.md +92 -0
  339. package/templates/blank/docs/ai/troubleshooting.md +60 -0
  340. package/templates/blank/docs/ai/workflow.md +139 -0
  341. package/templates/blank/docs/errors/CAGE-APPR-001.md +47 -0
  342. package/templates/blank/docs/errors/CAGE-APPR-002.md +47 -0
  343. package/templates/blank/docs/errors/CAGE-APPR-003.md +47 -0
  344. package/templates/blank/docs/errors/CAGE-APPR-004.md +47 -0
  345. package/templates/blank/docs/errors/CAGE-APPR-005.md +47 -0
  346. package/templates/blank/docs/errors/CAGE-APPR-006.md +47 -0
  347. package/templates/blank/docs/errors/CAGE-APPR-007.md +50 -0
  348. package/templates/blank/docs/errors/CAGE-APPR-010.md +48 -0
  349. package/templates/blank/docs/errors/CAGE-AUTH-001.md +47 -0
  350. package/templates/blank/docs/errors/CAGE-BUDGET-001.md +47 -0
  351. package/templates/blank/docs/errors/CAGE-BUDGET-002.md +47 -0
  352. package/templates/blank/docs/errors/CAGE-BUDGET-003.md +47 -0
  353. package/templates/blank/docs/errors/CAGE-CMD-002.md +47 -0
  354. package/templates/blank/docs/errors/CAGE-CMD-003.md +47 -0
  355. package/templates/blank/docs/errors/CAGE-CONN-001.md +47 -0
  356. package/templates/blank/docs/errors/CAGE-CONN-002.md +47 -0
  357. package/templates/blank/docs/errors/CAGE-CONN-003.md +47 -0
  358. package/templates/blank/docs/errors/CAGE-CONN-004.md +47 -0
  359. package/templates/blank/docs/errors/CAGE-CONN-005.md +47 -0
  360. package/templates/blank/docs/errors/CAGE-CONN-006.md +47 -0
  361. package/templates/blank/docs/errors/CAGE-CONN-007.md +47 -0
  362. package/templates/blank/docs/errors/CAGE-CONN-008.md +47 -0
  363. package/templates/blank/docs/errors/CAGE-CONN-009.md +47 -0
  364. package/templates/blank/docs/errors/CAGE-CONN-010.md +47 -0
  365. package/templates/blank/docs/errors/CAGE-CONN-011.md +47 -0
  366. package/templates/blank/docs/errors/CAGE-CONN-012.md +47 -0
  367. package/templates/blank/docs/errors/CAGE-CREATE-001.md +52 -0
  368. package/templates/blank/docs/errors/CAGE-DECL-001.md +48 -0
  369. package/templates/blank/docs/errors/CAGE-DECL-002.md +47 -0
  370. package/templates/blank/docs/errors/CAGE-DECL-003.md +47 -0
  371. package/templates/blank/docs/errors/CAGE-DECL-004.md +47 -0
  372. package/templates/blank/docs/errors/CAGE-DEP-001.md +48 -0
  373. package/templates/blank/docs/errors/CAGE-DEP-002.md +47 -0
  374. package/templates/blank/docs/errors/CAGE-DEP-003.md +47 -0
  375. package/templates/blank/docs/errors/CAGE-DEP-004.md +47 -0
  376. package/templates/blank/docs/errors/CAGE-DEP-005.md +47 -0
  377. package/templates/blank/docs/errors/CAGE-DLQ-001.md +48 -0
  378. package/templates/blank/docs/errors/CAGE-ENV-001.md +52 -0
  379. package/templates/blank/docs/errors/CAGE-EVENT-001.md +47 -0
  380. package/templates/blank/docs/errors/CAGE-EVENT-002.md +50 -0
  381. package/templates/blank/docs/errors/CAGE-FIELD-001.md +47 -0
  382. package/templates/blank/docs/errors/CAGE-FIELD-002.md +47 -0
  383. package/templates/blank/docs/errors/CAGE-FIELD-003.md +47 -0
  384. package/templates/blank/docs/errors/CAGE-FIELD-004.md +47 -0
  385. package/templates/blank/docs/errors/CAGE-GEN-001.md +48 -0
  386. package/templates/blank/docs/errors/CAGE-GEN-002.md +47 -0
  387. package/templates/blank/docs/errors/CAGE-GRANT-001.md +49 -0
  388. package/templates/blank/docs/errors/CAGE-GRANT-002.md +48 -0
  389. package/templates/blank/docs/errors/CAGE-GRANT-003.md +47 -0
  390. package/templates/blank/docs/errors/CAGE-IMPACT-001.md +48 -0
  391. package/templates/blank/docs/errors/CAGE-INIT-001.md +47 -0
  392. package/templates/blank/docs/errors/CAGE-INIT-002.md +49 -0
  393. package/templates/blank/docs/errors/CAGE-INIT-003.md +48 -0
  394. package/templates/blank/docs/errors/CAGE-INIT-004.md +48 -0
  395. package/templates/blank/docs/errors/CAGE-JOB-001.md +47 -0
  396. package/templates/blank/docs/errors/CAGE-JOB-002.md +47 -0
  397. package/templates/blank/docs/errors/CAGE-JOB-003.md +47 -0
  398. package/templates/blank/docs/errors/CAGE-LINT-001.md +47 -0
  399. package/templates/blank/docs/errors/CAGE-MIG-001.md +47 -0
  400. package/templates/blank/docs/errors/CAGE-MIG-002.md +47 -0
  401. package/templates/blank/docs/errors/CAGE-MIG-003.md +5 -0
  402. package/templates/blank/docs/errors/CAGE-MIG-004.md +5 -0
  403. package/templates/blank/docs/errors/CAGE-MIG-005.md +47 -0
  404. package/templates/blank/docs/errors/CAGE-NAME-001.md +47 -0
  405. package/templates/blank/docs/errors/CAGE-NAME-002.md +47 -0
  406. package/templates/blank/docs/errors/CAGE-NAME-003.md +47 -0
  407. package/templates/blank/docs/errors/CAGE-NAME-004.md +47 -0
  408. package/templates/blank/docs/errors/CAGE-NAME-005.md +47 -0
  409. package/templates/blank/docs/errors/CAGE-NAME-006.md +47 -0
  410. package/templates/blank/docs/errors/CAGE-ORG-001.md +49 -0
  411. package/templates/blank/docs/errors/CAGE-PAIR-002.md +50 -0
  412. package/templates/blank/docs/errors/CAGE-QUERY-001.md +47 -0
  413. package/templates/blank/docs/errors/CAGE-QUERY-002.md +47 -0
  414. package/templates/blank/docs/errors/CAGE-QUERY-003.md +49 -0
  415. package/templates/blank/docs/errors/CAGE-REACT-001.md +47 -0
  416. package/templates/blank/docs/errors/CAGE-REACT-002.md +47 -0
  417. package/templates/blank/docs/errors/CAGE-READS-001.md +47 -0
  418. package/templates/blank/docs/errors/CAGE-REG-001.md +53 -0
  419. package/templates/blank/docs/errors/CAGE-REG-002.md +48 -0
  420. package/templates/blank/docs/errors/CAGE-REG-003.md +47 -0
  421. package/templates/blank/docs/errors/CAGE-REL-001.md +64 -0
  422. package/templates/blank/docs/errors/CAGE-ROUTE-001.md +47 -0
  423. package/templates/blank/docs/errors/CAGE-SCOPE-001.md +47 -0
  424. package/templates/blank/docs/errors/CAGE-SCOPE-002.md +47 -0
  425. package/templates/blank/docs/errors/CAGE-SECRET-001.md +48 -0
  426. package/templates/blank/docs/errors/CAGE-SECRET-002.md +47 -0
  427. package/templates/blank/docs/errors/CAGE-SENS-001.md +48 -0
  428. package/templates/blank/docs/errors/CAGE-SQL-001.md +47 -0
  429. package/templates/blank/docs/errors/CAGE-SQL-002.md +47 -0
  430. package/templates/blank/docs/errors/CAGE-STATE-001.md +49 -0
  431. package/templates/blank/docs/errors/CAGE-STATE-002.md +47 -0
  432. package/templates/blank/docs/errors/CAGE-STATE-003.md +47 -0
  433. package/templates/blank/docs/errors/CAGE-STATE-004.md +47 -0
  434. package/templates/blank/docs/errors/CAGE-STATE-005.md +48 -0
  435. package/templates/blank/docs/errors/CAGE-STATE-010.md +48 -0
  436. package/templates/blank/docs/errors/CAGE-STATE-011.md +48 -0
  437. package/templates/blank/docs/errors/CAGE-STRUCT-001.md +51 -0
  438. package/templates/blank/docs/errors/CAGE-STRUCT-002.md +51 -0
  439. package/templates/blank/docs/errors/CAGE-SYNC-001.md +48 -0
  440. package/templates/blank/docs/errors/CAGE-TEST-001.md +47 -0
  441. package/templates/blank/docs/errors/CAGE-UNSAFE-001.md +48 -0
  442. package/templates/blank/docs/errors/CAGE-UPGRADE-001.md +48 -0
  443. package/templates/blank/docs/errors/README.md +307 -0
  444. package/templates/blank/docs/errors/runtime.md +50 -0
  445. package/templates/blank/docs/examples/purchase-admin/README.md +5 -0
  446. package/templates/blank/docs/examples/purchase-admin/apps/api/src/main.ts +10 -0
  447. package/templates/blank/docs/examples/purchase-admin/apps/api/src/worker.ts +14 -0
  448. package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/app.tsx +18 -0
  449. package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/styles/global.css +663 -0
  450. package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/workspace-layout.tsx +70 -0
  451. package/templates/blank/docs/examples/purchase-admin/apps/web/src/main.tsx +13 -0
  452. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/approval/hooks/use-approval-tasks.ts +20 -0
  453. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/approval/index.ts +2 -0
  454. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/approval/pages/approval-tasks-page.tsx +54 -0
  455. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/auth/index.ts +1 -0
  456. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/auth/pages/login-page.tsx +59 -0
  457. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/inventory/index.ts +1 -0
  458. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/inventory/pages/inventory-page.tsx +74 -0
  459. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/purchase-order-form.tsx +60 -0
  460. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/index.ts +2 -0
  461. package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/pages/purchase-orders-page.tsx +210 -0
  462. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/hooks/use-command.ts +29 -0
  463. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/lib/error-message.ts +15 -0
  464. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/notice.tsx +13 -0
  465. package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/page-heading.tsx +28 -0
  466. package/templates/blank/docs/examples/purchase-admin/cage.config.json +114 -0
  467. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/dept/index.ts +74 -0
  468. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/inventory/index.ts +57 -0
  469. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/inventory-lock/index.ts +52 -0
  470. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/purchase-order/index.ts +72 -0
  471. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/role/index.ts +85 -0
  472. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/user/index.ts +89 -0
  473. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/index.ts +81 -0
  474. package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/queries/index.ts +17 -0
  475. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/index.ts +6 -0
  476. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/integrations/erp.ts +36 -0
  477. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/inventory/index.ts +2 -0
  478. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/inventory/inventory.ts +43 -0
  479. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/approvals.ts +18 -0
  480. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/index.ts +6 -0
  481. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/jobs.ts +13 -0
  482. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/purchase-order.test.ts +137 -0
  483. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/purchase-order.ts +122 -0
  484. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/queries.ts +10 -0
  485. package/templates/blank/docs/examples/purchase-admin/packages/domain/src/workflows/purchase-inventory.ts +24 -0
  486. package/templates/blank/package.json +22 -0
  487. package/templates/blank/packages/contracts/package.json +16 -0
  488. package/templates/blank/packages/contracts/src/aggregates/dept/index.ts +74 -0
  489. package/templates/blank/packages/contracts/src/aggregates/role/index.ts +85 -0
  490. package/templates/blank/packages/contracts/src/aggregates/user/index.ts +89 -0
  491. package/templates/blank/packages/contracts/src/index.ts +55 -0
  492. package/templates/blank/packages/contracts/src/queries/index.ts +13 -0
  493. package/templates/blank/packages/contracts/tsconfig.json +5 -0
  494. package/templates/blank/packages/domain/package.json +23 -0
  495. package/templates/blank/packages/domain/src/index.ts +4 -0
  496. package/templates/blank/packages/domain/tsconfig.json +5 -0
  497. package/templates/blank/pnpm-workspace.yaml +10 -0
  498. package/templates/blank/renovate.json +5 -0
  499. package/templates/blank/tsconfig.base.json +8 -0
package/package.json CHANGED
@@ -1,6 +1,63 @@
1
1
  {
2
2
  "name": "@yss123/cage-cli",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.2.0",
4
+ "description": "cage 命令行:init、gen、check、graph、context、impact、test、verify、budget、sync、upgrade、dev、migrate",
5
+ "type": "module",
6
+ "bin": {
7
+ "cage": "./bin/cage.js",
8
+ "create-cage-app": "./bin/create-cage-app.js"
9
+ },
10
+ "main": "dist/index.js",
11
+ "types": "dist/index.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "default": "./dist/index.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "bin",
21
+ "graph-ui",
22
+ "templates"
23
+ ],
24
+ "dependencies": {
25
+ "@clack/prompts": "^1.8.1",
26
+ "dependency-cruiser": "^17.0.1",
27
+ "eslint": "^9.35.0",
28
+ "pg": "^8.16.3",
29
+ "ts-morph": "^26.0.0",
30
+ "tsx": "^4.20.5",
31
+ "typescript": "~5.9.3",
32
+ "vitest": "^4.1.12",
33
+ "zod": "^4.1.5",
34
+ "@yss123/cage-kernel": "0.2.0",
35
+ "@yss123/cage-lint": "0.2.0",
36
+ "@yss123/cage-testkit": "0.2.0"
37
+ },
38
+ "devDependencies": {
39
+ "@types/pg": "^8.15.5"
40
+ },
41
+ "license": "MIT",
42
+ "repository": {
43
+ "type": "git",
44
+ "url": "git+https://github.com/shunshunyue/cage.git",
45
+ "directory": "packages/cli"
46
+ },
47
+ "homepage": "https://github.com/shunshunyue/cage#readme",
48
+ "bugs": {
49
+ "url": "https://github.com/shunshunyue/cage/issues"
50
+ },
51
+ "publishConfig": {
52
+ "access": "public",
53
+ "registry": "https://registry.npmjs.org/"
54
+ },
55
+ "engines": {
56
+ "node": ">=24"
57
+ },
58
+ "scripts": {
59
+ "build": "node scripts/clean-dist.ts && tsc -p tsconfig.json && tsc -p ui/tsconfig.json && node scripts/build-graph.ts && node scripts/copy-assets.ts",
60
+ "typecheck": "tsc -p tsconfig.json --noEmit && tsc -p ui/tsconfig.json",
61
+ "test": "vitest run"
62
+ }
6
63
  }
@@ -0,0 +1,10 @@
1
+ node_modules
2
+ **/node_modules
3
+ **/dist
4
+ .git
5
+ .cage
6
+ **/.cage
7
+ generated
8
+ .env
9
+ .env.*
10
+ *.log
@@ -0,0 +1,61 @@
1
+ # Cage 业务项目配置:复制此文件为同目录的 .env,首次只填写管理员数据库连接。
2
+ # .env 位于业务项目根目录,与 package.json、cage.config.json 同级。
3
+ # pnpm exec cage init / pnpm dev / pnpm migrate 自动读取它;同名外部环境变量优先。
4
+ # 修改后重启 dev;migrate 在下次执行时读取新值。不要把 .env 提交到 Git。
5
+ # 数据库需已经存在并能连接;框架不安装 PostgreSQL、不创建数据库、不管理 Docker。
6
+
7
+ # ===== 第一步:提供已有数据库的管理员连接,执行 pnpm exec cage init =====
8
+ # 格式:postgresql://用户名:密码@主机:端口/数据库名
9
+ # 将 127.0.0.1、5432、business_db 换成实际地址、端口和已有数据库名。
10
+ # 密码中的特殊字符必须 URL 编码,例如 @ 写成 %40、# 写成 %23、% 写成 %25。
11
+ # [首次初始化必填] 管理员通常叫 postgres;若你的管理员叫 root,使用实际账号名。
12
+ # 管理员需要创建角色、schema 和授权的权限。连接的数据库必须已经存在。
13
+ # 将下面的管理员密码、主机、端口和库名改为实际值,再执行 pnpm exec cage init。
14
+ # init 会创建框架账号、生成独立随机密码和 Cookie 密钥,并自动填好下面的配置。
15
+ # 成功后管理员连接会从 .env 移除;日常开发不用再提供管理员密码。
16
+ CAGE_ADMIN_DATABASE_URL=postgresql://postgres:REPLACE_WITH_ADMIN_PASSWORD@127.0.0.1:5432/business_db
17
+
18
+ # ===== 第二步:以下配置由 init 自动填充,无需手动创建账号或编写授权 SQL =====
19
+ # 三个连接使用同一个数据库,主机、端口、库名一致,账号权限不同。
20
+ # 重复 init 会验证并复用已保存的账号,不重置密码。
21
+ # 若集群已有 Cage 账号且本项目未保存连接,需复用原凭证,不能仅凭管理员重置其他项目的密码。
22
+
23
+ # [必填] 业务写入账号 cage_app:API 和 worker 执行命令、审计和后台任务使用。
24
+ # 它有业务所需读写权限,不应使用 postgres 超级用户替代。
25
+ # CAGE_APP_DATABASE_URL=
26
+
27
+ # [必填] 安全查询账号 cage_read:仅通过安全视图读取,经数据范围过滤和敏感字段掩码。
28
+ # 不要与写入账号混用,否则会破坏读写权限隔离。
29
+ # CAGE_READ_DATABASE_URL=
30
+
31
+ # [执行迁移时必填] 迁移账号 cage_migrate:pnpm migrate 用它更新表、索引、视图和权限。
32
+ # 它连接上述同一个数据库;迁移只在手动执行命令时发生,dev 不自动执行迁移。
33
+ # 生产环境只给迁移任务配置此项,API / worker 无需获得此账号。
34
+ # CAGE_MIGRATE_DATABASE_URL=
35
+
36
+ # ===== 应用配置 =====
37
+ # [init 自动生成] Cookie 签名密钥,不是数据库密码,也不是网页登录密码。
38
+ # 自动生成 32 字节随机值;已有值保留。同一应用的多个实例使用同一值。
39
+ # CAGE_COOKIE_SECRET=
40
+
41
+ # [可选,开发默认 fake] 第三方连接器阶段:fake 使用模拟实现;test / prod 使用真实适配器。
42
+ # 本项只影响第三方外部服务,fake 阶段仍连接真实 PostgreSQL。
43
+ # test / prod 需另行配置业务连接器要求的地址与密钥,不是修改此值就完成对接。
44
+ CAGE_STAGE=fake
45
+
46
+ # [可选,Vite 默认 5173] 本地 Web 页面端口。这里选 15173,减少 Windows 保留端口冲突。
47
+ # 多个应用同时运行时,各选一个空闲端口;它与数据库端口无关。
48
+ CAGE_WEB_PORT=15173
49
+
50
+ # [可选,默认 3000] API 服务端口;本地 Web 代理自动转发到这个端口。
51
+ PORT=3000
52
+
53
+ # [可选,范例默认 0.0.0.0] API 监听地址;这里使用 127.0.0.1,仅允许本机访问。
54
+ # 需要容器内或局域网访问时改为 0.0.0.0,并按部署环境配置网络访问权限。
55
+ HOST=127.0.0.1
56
+
57
+ # ===== 仅执行数据库测试时使用;正常启动不需要 =====
58
+ # [可选] 独立、可丢弃 PostgreSQL 测试集群的管理连接,需有建库和管理角色权限。
59
+ # 测试会创建/删除临时库、初始化集群级角色;不能指向业务或生产数据库所在的集群。
60
+ # 不填写时测试工具使用内嵌真实 PostgreSQL;这仅是测试行为,dev 不会自动启动数据库。
61
+ # CAGE_TEST_DATABASE_URL=postgresql://test_admin:REPLACE_WITH_TEST_PASSWORD@127.0.0.1:5433/postgres
@@ -0,0 +1,44 @@
1
+ # 尚未配置框架发布地址时直接调用同一个 CLI 门禁。
2
+ # 框架发布后可将此任务替换为远端 app-verify.yml 的 uses 引用。
3
+ name: Cage application
4
+ on: [push, pull_request]
5
+ permissions:
6
+ contents: read
7
+ jobs:
8
+ verify:
9
+ runs-on: ubuntu-latest
10
+ services:
11
+ postgres:
12
+ image: postgres:18
13
+ env: { POSTGRES_PASSWORD: cage_ci }
14
+ ports: ['5432:5432']
15
+ options: --health-cmd "pg_isready -U postgres" --health-interval 5s --health-timeout 5s --health-retries 10
16
+ env:
17
+ CAGE_TEST_DATABASE_URL: postgres://postgres:cage_ci@localhost:5432/postgres
18
+ steps:
19
+ - uses: actions/checkout@v4
20
+ with: { fetch-depth: 0 }
21
+ - uses: pnpm/action-setup@v4
22
+ with: { version: 10.14.0 }
23
+ - uses: actions/setup-node@v4
24
+ with: { node-version: 24 }
25
+ - run: pnpm install --frozen-lockfile
26
+ - run: pnpm build:app
27
+ - run: pnpm cage verify
28
+ - name: Pull request impact
29
+ if: github.event_name == 'pull_request'
30
+ env:
31
+ BASE_SHA: ${{ github.event.pull_request.base.sha }}
32
+ run: |
33
+ pnpm cage impact --base "$BASE_SHA" --format md --out .cage/impact.md
34
+ cat .cage/impact.md >> "$GITHUB_STEP_SUMMARY"
35
+ - run: pnpm audit --prod --audit-level high
36
+ - uses: actions/upload-artifact@v4
37
+ if: always()
38
+ with:
39
+ name: cage-report
40
+ include-hidden-files: true
41
+ path: |
42
+ .cage/verify.json
43
+ .cage/test-results.json
44
+ .cage/impact.md
@@ -0,0 +1,96 @@
1
+ # 本项目的业务开发说明
2
+
3
+ 这是 create-cage-app 生成的业务项目,当前包含采购演示,可逐步替换成客户业务。业务源码在本项目,框架通过 @yss123/cage-* 依赖提供。
4
+
5
+ 先读 [业务开发指南](docs/ai/README.md),按需求查 [任务配方](docs/ai/recipes.md)、[完整采购范例](docs/ai/purchase-example.md) 和 [错误码册](docs/errors/README.md)。这些资料就在项目内,无需克隆框架仓库。
6
+
7
+ ## 项目自己的业务约定
8
+
9
+ 客户术语、角色权限、状态规则、第三方协议和验收标准写在本节或独立业务文档,再从这里链接。新增业务以用户需求为准,不因模板包含采购示例就固定实现采购流程。
10
+
11
+ 本节位于托管区之外,cage sync 会保留。下面的托管区提供框架工作方法。
12
+
13
+ <!-- cage:begin v0.2.0 -->
14
+ ## Cage 业务开发约定(框架托管)
15
+
16
+ ### 先读,再按需求改业务
17
+
18
+ 本项目由 create-cage-app 创建。框架来自 `@yss123/cage-*` 依赖,业务写在本项目;不需要克隆框架仓库,也不要复制框架内部实现。
19
+
20
+ 先读项目说明指定的学习资料,默认入口为 `docs/ai/README.md`。第一次读 `architecture.md`、`project-structure.md` 和 `primitives.md`;具体任务读 `recipes.md`,采购全链路读 `purchase-example.md`,错误查 `docs/errors/README.md` 和 `docs/ai/troubleshooting.md`。资料相对该学习目录,项目说明可指定源码仓库中的规范资料位置。
21
+
22
+ ### 业务代码放在哪里
23
+
24
+ | 位置 | 职责 |
25
+ | --- | --- |
26
+ | `packages/domain/src/modules/<业务>` | 同业务聚合、状态、命令、事件、审批、查询、任务;模块 index.ts 公开导出 |
27
+ | `packages/domain/src/workflows`、`integrations` | 跨模块反应 / 第三方协议与映射;不堆到全局 reactions.ts、queries.ts |
28
+ | `packages/domain/src/index.ts` | 统一导出全部业务及组织模型;没导出的声明不会注册 |
29
+ | `packages/contracts/src/aggregates/<聚合>`、`queries` | 生成协议;根 index.ts 提供 @app/contracts 公共入口,只用 cage gen 更新 |
30
+ | `apps/api/src` | API/worker 薄启动入口,普通业务不手写 HTTP 路由 |
31
+ | `apps/web/src/app` | 会话、导航、布局、模块组合;main.tsx 只挂载和装配 Provider |
32
+ | `apps/web/src/modules/<业务>` | 页面、表单、专用 hooks/API/样式;从模块 index.ts 暴露页面 |
33
+ | `apps/web/src/shared` | 跨模块复用且不绑定业务的 UI、hooks、纯辅助函数 |
34
+ | `db/migrations` | 审查过的结构迁移,作用于已配置的数据库 |
35
+ | `cage.config.json` | 项目路径、检查配置、graph.labels 中文图谱名称 |
36
+ | `.env` | 本机真实连接和密钥;不提交、不输出完整内容 |
37
+
38
+ 新增业务不得继续平铺在 src 根目录。前端模块只依赖自己和 shared,由 app 通过公开入口组合;shared 不反向依赖业务。领域模块间确有读取依赖时走目标模块 index.ts;跨模块反应写 workflows。小模块不创建空层级,已有独立职责再拆文件。完整命名、目录树和示例见 `docs/ai/project-structure.md`。新模板启用 `structure: modular`,check/verify 检查目录和导入边界,遇到 CAGE-STRUCT 错误按职责修正。
39
+
40
+ ### 实现一项需求的顺序
41
+
42
+ 1. 先运行 `pnpm exec cage context "需求关键词"`;按需 `graph search` 查候选、`graph inspect` 查完整节点、`graph path` 看关系路径。确认中文匹配入口后按源码位置阅读实现;候选和子图不是全部依赖,具体条件不能凭连线推断。完整用法见 `docs/ai/ontology-context.md`。从用户需求确定字段、状态/动作、角色/范围、约束与后续动作;能由业务声明表达的不改框架。
43
+ 2. 已有业务含义变化时,修改前保存本体图基线:`pnpm exec cage analyze` 后将 `.cage/ontology.json` 另存为独立文件;或使用真实 Git 基线。
44
+ 3. 先声明 aggregate/states/command/constraints/event,再写 handler、reaction/query/approval/connector,最后接业务页面。声明使用模块顶层 `export const`,从 domain 入口导出,跨文件导出名保持唯一。
45
+ 4. 运行 `pnpm exec cage check` 和 `pnpm gen`,审查 contracts 和迁移草稿。按需运行 `pnpm exec cage impact --base-file 旧图.json`,补中文图谱名。
46
+ 5. 页面使用生成方法并处理 code/domainCode;新增能力由管理员授权。数据库结构变化审查后显式 `pnpm migrate`,dev 不代办迁移。
47
+ 6. 按改动运行必要验证,交付时说明体验步骤、授权配置、迁移,以及通过/跳过/未执行项。
48
+
49
+ ### 必守边界
50
+
51
+ - 聚合定义对象字段、状态、范围字段与不变量;命令是业务写入口。handler 只计算业务变化和读取 reads 中的依赖,不直接操作数据库、网络或文件。
52
+ - 对象关系统一放在 fields:ref 为外键,hasMany 为只读反查,manyToMany 自动生成中间表并随所属对象命令提交。前端用生成的 related 方法分页读取;不手写纯中间表聚合,不把单页结果当完整集合替换。完整例子见 docs/ai/relations.md。
53
+ - command 的 input 使用 Zod;已有记录输入必须含 id。from/to 表达状态迁移;`to: null` 只适用于已有记录并保留状态,不能靠 handler 改 status 绕过状态机。
54
+ - 写入、审计、版本、幂等和事务交给内核;不要在业务项目重建 repository、连接池或权限流水线。
55
+ - 自定义查询声明 reads,二选一使用 sql/build,只读 `safe.*`;值参数化。不得拼接 SQL、查询基表绕过范围或硬编码密钥。
56
+ - scope 描述范围字段,角色数据决定实际范围;`scope.none()` 不代表所有人可访问。`can/useCan` 只控制按钮,后端负责授权。
57
+ - 前端从 `@app/contracts` 导入生成 API/类型,按需使用 `@yss123/cage-client`;不导入 domain、内核或数据库包。
58
+ - 跨聚合写入通过 reaction 调用命令。`tx: 'same'` 共同提交/回滚,默认 outbox 异步执行。资源 acquires/releases 是图规则标签,实际占用/释放仍由命令完成;离开持有状态要检查每条释放路径。
59
+ - 审批通过 approval + route 配置,结论是 process 命令;选中审批人不等于已具备能力、范围和额度。第三方 IO 通过连接器,回调验签后调用 external 命令。
60
+ - job 的读取与调用必须列入 reads/calls。业务导入/导出放在需要的业务页面调用通用任务接口,202 只代表任务已接受;worker 必须运行。
61
+ - 已部署事件只做兼容扩展;新增字段设为 optional,不兼容含义用新事件。已执行/已发布迁移不能改写,结构更新新增迁移。
62
+ - 不手改生成物,不关闭门禁掩盖错误,不因方便自动授予生产角色新能力。unsafe 必须写明 reason/owner,不能替代普通业务声明。
63
+ - 代码注释说明职责、关键流程和设计原因;避免无业务价值的防御分支和静默兜底。维护脚本用 TypeScript,不新增 .mjs。
64
+
65
+ ### 最小命令形状
66
+
67
+ ```ts
68
+ // 片段:Order 为已导出的聚合,OrderSubmitted 为事件,业务校验按需求添加。
69
+ export const submitOrder = command(Order, {
70
+ name: 'submit',
71
+ from: 'draft',
72
+ to: 'pending_approval',
73
+ emits: [OrderSubmitted],
74
+ handler: (draft) => draft,
75
+ });
76
+ ```
77
+
78
+ 完整可添加的普通管理对象见 `docs/ai/primitives.md` 的 Note;采购模板的审批、资源、第三方示例在 `packages/domain/src`,空白模板的参考源码在 `docs/examples/purchase-admin`。先读本项目 AGENTS.md 中的模板说明,区分运行代码与参考资料。API 以当前包公开导出和生成契约为准,不发明不存在的配置和方法。
79
+
80
+ ### 启动、验证与排错
81
+
82
+ 在项目根目录执行:首次 `pnpm install`,复制并编辑 .env.example,仅提供已有库管理员连接后 `pnpm exec cage init`;再 `pnpm build:app`、`pnpm gen`,审查后 `pnpm migrate`,最后 `pnpm dev`。已有配置不能覆盖。
83
+
84
+ init 只准备账号/schema/授权并填写三个连接,不创建数据库;APP/READ/MIGRATE 指向同一个库。已有集群账号复用原密码,日常启动不用管理员。普通项目不新增 Docker 生命周期命令。
85
+
86
+ - `pnpm exec cage graph`:浏览器图谱,默认端口 15418,以终端为准。
87
+ - `pnpm exec cage context command:对象.命令 --format json --out .cage/context.json`:按完整 key 取精简上下文;默认 Markdown,可用 --depth/--limit 调整范围。CLI 每次重新抽取;Web“复制 AI 上下文”使用当前页面快照,改代码后先刷新图谱。
88
+ - `graph inspect/path` 有歧义时复制候选完整 key;path 默认沿箭头,--direction both 的逆向遍历不表示执行方向。报告中的测试/前端文件是候选,须核对;查询也会覆盖当前 .cage/ontology.json,旧基线务必另存。
89
+ - `pnpm exec cage gen --check`:生成一致性;`pnpm exec cage sync --check`:本托管区一致性。
90
+ - `pnpm exec cage test --only project`:业务测试;`pnpm verify`:类型、依赖、lint、图规则、生成、托管区、预算和测试。
91
+ - `pnpm exec cage verify --skip-tests` 表示不完整门禁;派生测试跳过不能当作通过。测试连接只用独立测试集群。
92
+ - 重要业务改动验证成功路径及有风险的反例;文档或可逆的小改动不反复跑全量数据库测试。
93
+ - CLI 报错先看 code/at/reason/fix,再查错误码册;HTTP 错误查 runtime.md。异步失败先看 worker、同步记录和死信,修复后重放,不能直接 SQL 改状态。
94
+
95
+ 框架托管区由 cage sync 更新;项目独有的业务规则写在标记之外,避免升级覆盖。
96
+ <!-- cage:end -->
@@ -0,0 +1,25 @@
1
+ # 独立业务仓库使用已发布的 @yss123/cage-* 依赖;先提交 pnpm-lock.yaml。
2
+ # --framework-path 创建的 link: 本地依赖只用于源码开发,不能拷贝进独立镜像。
3
+ FROM node:24-bookworm-slim AS build
4
+ RUN corepack enable && corepack prepare pnpm@10.14.0 --activate
5
+ WORKDIR /app
6
+ COPY . .
7
+ RUN pnpm install --frozen-lockfile && pnpm build:app
8
+ RUN pnpm --filter @app/api deploy --prod --legacy /out/api
9
+
10
+ # 发布过程先单独运行此 target,迁移账号只注入迁移任务。
11
+ FROM build AS migration
12
+ CMD ["pnpm", "cage", "migrate"]
13
+
14
+ # API 与 worker 共用运行时镜像,通过启动命令区分职责。
15
+ FROM node:24-bookworm-slim AS runtime
16
+ WORKDIR /app
17
+ COPY --from=build --chown=node:node /out/api /app
18
+ COPY --from=build --chown=node:node /app/apps/web/dist /app/web
19
+ # 系统管理与图谱共享中文显示配置;运行时工作目录同样保持为 /app。
20
+ COPY --from=build --chown=node:node /app/cage.config.json /app/cage.config.json
21
+ ENV NODE_ENV=production PORT=3000 WEB_DIR=/app/web
22
+ USER node
23
+ EXPOSE 3000
24
+ CMD ["node", "dist/main.js"]
25
+ # worker 启动命令:node dist/worker.js
@@ -0,0 +1,88 @@
1
+ # Cage 业务应用(含采购示例)
2
+
3
+ 这是可启动的标准范例:组织管理、采购单、审批待办、库存台账、库存锁生命周期和 ERP 出入站映射。
4
+
5
+ ## 让 AI 在本项目开发业务
6
+
7
+ 把本目录交给 Codex 等编程工具时,先让它读 [AGENTS.md](AGENTS.md),再按[业务开发指南](docs/ai/README.md)和[任务配方](docs/ai/recipes.md)实现需求。普通业务不需要修改框架源码。
8
+
9
+ [采购全链路导读](docs/ai/purchase-example.md)说明每个文件和异步步骤;[原语与最小业务](docs/ai/primitives.md)提供可添加的普通管理对象;[错误码册](docs/errors/README.md)用于按码修复。脚手架会将这些资料放入生成项目本地的 `docs/ai` 与 `docs/errors`,无需再次克隆框架。
10
+
11
+ ## 启动
12
+
13
+ 在本项目根目录执行 `pnpm install`、`pnpm build:app`;无需克隆或构建框架仓库。
14
+
15
+ ```powershell
16
+ # 首次配置时复制,已有 .env 时直接编辑原文件。
17
+ Copy-Item .env.example .env
18
+ # 编辑 .env,只填写 CAGE_ADMIN_DATABASE_URL,连接已经存在的数据库。
19
+ pnpm exec cage init
20
+ # init 自动创建账号、生成密码和 Cookie 密钥,并写回 .env。
21
+ pnpm gen
22
+ # 审查 db/migrations 后执行表结构迁移。
23
+ pnpm migrate
24
+ pnpm dev
25
+ ```
26
+
27
+ 数据库配置位于本项目根目录的 `.env`,与 `package.json`、`cage.config.json` 同级。[`.env.example`](.env.example) 为每项提供中文注释、填写格式和是否必填。连接池和事务由框架提供,项目只需配置连接。
28
+
29
+ | 配置项 | 用途 |
30
+ | --- | --- |
31
+ | `CAGE_APP_DATABASE_URL` | `cage_app` 账号:API/worker 业务读写 |
32
+ | `CAGE_READ_DATABASE_URL` | `cage_read` 账号:仅查询安全视图 |
33
+ | `CAGE_MIGRATE_DATABASE_URL` | `cage_migrate` 账号:手动执行表结构迁移 |
34
+
35
+ 三个连接由 `cage init` 自动生成,指向**同一个已经存在的数据库**,主机、端口和库名一致。CLI 自动读取 `.env`,部署环境中的同名变量优先。修改后重启 `dev`。`migrate` 在下次执行时读取配置。
36
+
37
+ `pnpm migrate` 更新该库中的表、视图和索引;迁移历史记录在 `sys.schema_migrations`。`pnpm dev` 连接该库并启动 API、worker 和 Web,domain 变化后仅重新生成文件;表结构变更需审查迁移后手动执行。框架不创建数据库、不安装 PostgreSQL、不管理 Docker。
38
+
39
+ ### 首次只提供管理员连接
40
+
41
+ 在 `.env` 中填写 `CAGE_ADMIN_DATABASE_URL=postgresql://postgres:管理员密码@主机:端口/已有数据库名`。PostgreSQL 管理员通常叫 `postgres`,已有管理员叫 `root` 时使用实际账号名;连接串中的密码特殊字符需要 URL 编码。
42
+
43
+ 执行 `pnpm exec cage init` 会创建框架账号和授权,生成三个独立随机密码及 Cookie 密钥,自动填写 `.env`,成功后移除文件中的管理员连接。业务端口、自定义配置和已有 Cookie 密钥会保留;失败会回滚数据库并保留原 `.env`。日常启动不需要管理员连接。
44
+
45
+ 重复 `init` 会验证并复用已保存的三个账号,不更改密码。若集群已有 Cage 账号但本项目没有原连接,请先复用原凭证再运行 `init`;命令不会为了新项目重置其他项目的账号。部署时也可由平台直接提供三个账号连接,无需执行本地初始化。
46
+
47
+ 数据库除三个登录账号外,还有不允许登录的 `cage_view_owner`,由 `init` 一并创建,用于持有安全视图,无需填写密码。角色名属于整个 PostgreSQL 集群,不能为另一个项目随意重置密码。业务表及系统表由后续 `pnpm migrate` 创建,`init` 只准备角色、schema 和授权。连接现有数据库不表示框架会自动识别、接管其中任意历史业务表;接入历史表需另行映射和审查迁移。
48
+
49
+ 测试环境会初始化集群级角色,因此 `CAGE_TEST_DATABASE_URL` 必须指向独立测试集群。运行 `pnpm cage verify` 验证示例;框架仓库根目录的 `pnpm test:docker` 验证全部框架测试。
50
+
51
+ 浏览器打开终端打印的 Web 地址;配置示例使用 <http://localhost:15173>。初始管理员凭证在 API 终端显示一次。
52
+ `CAGE_WEB_PORT` 控制 Web 端口,`PORT` 控制 API 端口,Vite 代理同步使用它。缺少数据库配置时会给出错误,需填写 `.env` 后重新启动。
53
+
54
+ ## 体验完整采购流程
55
+
56
+ 1. 管理员在“库存台账”登记 `A-01` 等物料。
57
+ 2. 进入 `/admin/` 创建采购员、经理,分别分配采购命令和审批能力;经理的 `PurchaseOrder.approve` 参数配置 `ceiling`。
58
+ 3. 把经理设为采购员所在部门的负责人。提单人与审批人必须不同。
59
+ 4. 采购员新建并提交采购单;worker 建立审批待办。
60
+ 5. 经理在“审批待办”通过,内核同事务生成库存锁;worker 调用 fake ERP 并回写单号。
61
+ 6. 超过 50,000 元的采购走财务第二步,需另建 code 为 `finance` 的角色并分配审批人。
62
+ 7. 取消单据或收到 ERP 收货回调后,通过异步反应释放锁。回调需要 `ERP_WEBHOOK_SECRET` 对原始 JSON 的 HMAC-SHA256 签名。
63
+
64
+ `Inventory.available` 是演示台账数量。本例验证库存锁生命周期,尚未实现仓库级的并发扣减、实物库存及退货核算。
65
+
66
+ 本例的取消只改变本地单据并释放锁,尚未对接真实 ERP 的取消补偿接口。ERP 单号应答可能晚于取消或收货到达,`recordErpNo` 使用 `to: null` 保留当时的单据状态;它仍然检查允许的起始状态、调用身份和版本,并写入审计。上线前需确定外部订单撤销、退货或人工补偿的业务规则。
67
+
68
+ ## 文件怎么读
69
+
70
+ 在本目录运行 `pnpm exec cage graph`,浏览器打开终端输出的 <http://127.0.0.1:15418>,即可用图谱查看业务关系。页面支持中文/英文搜索、类型筛选、拖拽缩放、聚焦关联、声明位置与重新抽取,不需要启动数据库。
71
+
72
+ 默认“对象与字段”按表卡片展示采购单、库存台账和库存锁,字段收在对象卡片中,显示中文含义、类型、必填标记及实际表名。拖动表头可以移动整张卡片。勾选“包含系统组织模型”查看部门、用户等对象;字段引用从字段行连到目标表头。“业务流程”和“完整本体”用于查看命令、事件、审批等更完整的关系。页面所说的业务对象,技术上叫“聚合”,包含共同遵守业务规则的字段、状态和命令,不只是数据库表。
73
+
74
+ 线上的中文名称说明关系类型;点击连线、标签或节点详情中的“解释”,查看连接原因、业务用途、箭头方向和声明依据。可搜索 `PurchaseOrder.deptId` 后点击“聚焦关联”,看到采购单的所属部门字段**引用**部门卡片。字段详情中还可查看“采购审批分支”怎样用它**确定审批人**,点击解释会切换到完整本体显示对应连线。审批流程的“允许审批读取”表示字段可用范围,实际选人依据另有解释。
75
+
76
+ 图谱主标题显示中文业务名称,下面保留英文代码标识。框架会读取声明现有的 `description`;本项目在 `cage.config.json` 的 `graph.labels` 中补充状态、字段等名称,也可覆盖较长描述。例如 `"command:PurchaseOrder.approve": "通过审批"`。键为 `节点类型:本体节点 ID`,可从节点详情复制 ID;中文标题只用于显示,不改变命令、权限标识或数据库。新增业务声明时同时补上需要的名称,然后在图谱中点击“重新抽取”。
77
+
78
+ - `packages/domain/src/modules/inventory`:最简聚合和库存锁。
79
+ - `packages/domain/src/modules/purchase`:采购状态、命令、约束、事件、审批、查询和任务。
80
+ - `packages/domain/src/workflows/purchase-inventory.ts`:同事务建锁与异步释放,包含资源配对标记。
81
+ - `packages/domain/src/integrations/erp.ts`:出站、入站映射和验签。
82
+ - `packages/contracts/src/aggregates/<聚合>`:生成的 SDK;页面统一从 `@app/contracts` 引入。
83
+ - `apps/api/src`:API 和 worker 的薄启动入口。
84
+ - `apps/web/src/app`、`modules`、`shared`:应用组合、业务页面、共享基础组件;`main.tsx` 只挂载。
85
+
86
+ 新增业务先读[工程目录与代码组织](docs/ai/project-structure.md),不要继续在 src 根目录平铺文件。模板已启用模块目录门禁,`cage check` 和 `verify` 会指出目录与依赖越界。
87
+
88
+ 先运行 `pnpm cage gen` 再提交契约和迁移草稿;`pnpm cage verify` 检查完整工具链。派生测试遇到无法推断的业务输入会显示跳过,`purchase-order.test.ts` 另外准备真实业务数据覆盖成功审批和约束反例。
@@ -0,0 +1,8 @@
1
+ node_modules/
2
+ dist/
3
+ .cage/
4
+ generated/
5
+ .env
6
+ .env.*
7
+ !.env.example
8
+ *.log
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "@app/api",
3
+ "private": true,
4
+ "type": "module",
5
+ "scripts": {
6
+ "build": "tsc -p tsconfig.json",
7
+ "typecheck": "tsc -p tsconfig.json --noEmit",
8
+ "start": "node dist/main.js",
9
+ "worker": "node dist/worker.js"
10
+ },
11
+ "dependencies": {
12
+ "@app/domain": "workspace:*",
13
+ "@yss123/cage-http": "0.2.0",
14
+ "@yss123/cage-connectors": "0.2.0"
15
+ }
16
+ }
@@ -0,0 +1,10 @@
1
+ // 启动入口只装配框架:认证、业务路由和 /admin 都由 createServer 提供。
2
+ // WEB_DIR 在部署镜像中指向 Vite 构建产物;本地由 Vite 独立提供前端。
3
+ import { createServer } from '@yss123/cage-http';
4
+ import * as domain from '@app/domain';
5
+
6
+ const server = createServer({ domain, webDir: process.env.WEB_DIR, title: 'Cage 采购工作台' });
7
+ await server.listen();
8
+ // 退出时释放数据库池及 LISTEN 连接,部署滚动替换时不会留下旧连接。
9
+ process.once('SIGINT', () => void server.close());
10
+ process.once('SIGTERM', () => void server.close());
@@ -0,0 +1,14 @@
1
+ // API 与 worker 使用相同声明。worker 专门处理审批启动、异步反应和 ERP 推送。
2
+ import { startWorker } from '@yss123/cage-http/worker';
3
+ import { fakeConnector, stage } from '@yss123/cage-connectors';
4
+ import * as domain from '@app/domain';
5
+
6
+ // 本地和测试的 ERP 返回确定的单号,便于查看同步记录;生产环境走真实出口。
7
+ if (stage() === 'fake') {
8
+ fakeConnector(domain.erp, {
9
+ pushOrder: (request) => ({ erpNo: `DEMO-${request.externalId.slice(0, 8)}` }),
10
+ });
11
+ }
12
+ const worker = await startWorker({ domain });
13
+ process.once('SIGINT', () => void worker.stop());
14
+ process.once('SIGTERM', () => void worker.stop());
@@ -0,0 +1,5 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": { "outDir": "dist", "rootDir": "src" },
4
+ "include": ["src"]
5
+ }
@@ -0,0 +1,13 @@
1
+ <!doctype html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width,initial-scale=1" />
6
+ <meta name="theme-color" content="#153c35" />
7
+ <title>Cage · 采购工作台</title>
8
+ </head>
9
+ <body>
10
+ <div id="root"></div>
11
+ <script type="module" src="/src/main.tsx"></script>
12
+ </body>
13
+ </html>
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "@app/web",
3
+ "private": true,
4
+ "type": "module",
5
+ "scripts": {
6
+ "dev": "vite",
7
+ "build": "tsc --noEmit && vite build",
8
+ "typecheck": "tsc --noEmit"
9
+ },
10
+ "dependencies": {
11
+ "@app/contracts": "workspace:*",
12
+ "@tanstack/react-query": "^5.87.1",
13
+ "react": "^19.1.1",
14
+ "react-dom": "^19.1.1"
15
+ },
16
+ "devDependencies": {
17
+ "@types/react": "^19.1.13",
18
+ "@types/react-dom": "^19.1.9",
19
+ "vite": "^7.1.4",
20
+ "typescript": "~5.9.3"
21
+ }
22
+ }
@@ -0,0 +1,18 @@
1
+ // 应用组合层只决定会话与页面的切换;具体业务交给 modules 下的页面。
2
+ import { useEffect, useState } from 'react';
3
+ import { loadMe } from '@app/contracts';
4
+ import { LoginPage } from '../modules/auth';
5
+ import { WorkspaceLayout } from './workspace-layout';
6
+
7
+ export function App() {
8
+ const [session, setSession] = useState<'loading' | 'guest' | 'ready'>('loading');
9
+ useEffect(() => {
10
+ void loadMe().then((result) => setSession(result.ok ? 'ready' : 'guest'));
11
+ }, []);
12
+ if (session === 'loading') return <div className="loading">正在连接工作台…</div>;
13
+ return session === 'guest' ? (
14
+ <LoginPage onLogin={() => setSession('ready')} />
15
+ ) : (
16
+ <WorkspaceLayout onLogout={() => setSession('guest')} />
17
+ );
18
+ }