@yss123/cage-cli 0.0.0-stage → 0.1.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 (235) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +18 -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 +26 -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 +47 -0
  16. package/dist/config.js.map +1 -0
  17. package/dist/create.d.ts +1 -0
  18. package/dist/create.js +47 -0
  19. package/dist/create.js.map +1 -0
  20. package/dist/database.d.ts +5 -0
  21. package/dist/database.js +70 -0
  22. package/dist/database.js.map +1 -0
  23. package/dist/derive.d.ts +14 -0
  24. package/dist/derive.js +163 -0
  25. package/dist/derive.js.map +1 -0
  26. package/dist/dev.d.ts +2 -0
  27. package/dist/dev.js +155 -0
  28. package/dist/dev.js.map +1 -0
  29. package/dist/env.d.ts +1 -0
  30. package/dist/env.js +15 -0
  31. package/dist/env.js.map +1 -0
  32. package/dist/findings.d.ts +11 -0
  33. package/dist/findings.js +13 -0
  34. package/dist/findings.js.map +1 -0
  35. package/dist/gen/contracts.d.ts +6 -0
  36. package/dist/gen/contracts.js +167 -0
  37. package/dist/gen/contracts.js.map +1 -0
  38. package/dist/gen/index.d.ts +19 -0
  39. package/dist/gen/index.js +137 -0
  40. package/dist/gen/index.js.map +1 -0
  41. package/dist/gen/zod-code.d.ts +7 -0
  42. package/dist/gen/zod-code.js +161 -0
  43. package/dist/gen/zod-code.js.map +1 -0
  44. package/dist/graph-snapshot.d.ts +13 -0
  45. package/dist/graph-snapshot.js +46 -0
  46. package/dist/graph-snapshot.js.map +1 -0
  47. package/dist/graph.d.ts +11 -0
  48. package/dist/graph.js +87 -0
  49. package/dist/graph.js.map +1 -0
  50. package/dist/impact.d.ts +28 -0
  51. package/dist/impact.js +223 -0
  52. package/dist/impact.js.map +1 -0
  53. package/dist/index.d.ts +16 -0
  54. package/dist/index.js +18 -0
  55. package/dist/index.js.map +1 -0
  56. package/dist/load.d.ts +6 -0
  57. package/dist/load.js +17 -0
  58. package/dist/load.js.map +1 -0
  59. package/dist/main.d.ts +1 -0
  60. package/dist/main.js +176 -0
  61. package/dist/main.js.map +1 -0
  62. package/dist/migrate.d.ts +7 -0
  63. package/dist/migrate.js +69 -0
  64. package/dist/migrate.js.map +1 -0
  65. package/dist/ontology.d.ts +41 -0
  66. package/dist/ontology.js +270 -0
  67. package/dist/ontology.js.map +1 -0
  68. package/dist/process.d.ts +6 -0
  69. package/dist/process.js +39 -0
  70. package/dist/process.js.map +1 -0
  71. package/dist/rules.d.ts +23 -0
  72. package/dist/rules.js +251 -0
  73. package/dist/rules.js.map +1 -0
  74. package/dist/static-check.d.ts +23 -0
  75. package/dist/static-check.js +225 -0
  76. package/dist/static-check.js.map +1 -0
  77. package/dist/sync.d.ts +5 -0
  78. package/dist/sync.js +46 -0
  79. package/dist/sync.js.map +1 -0
  80. package/dist/upgrade.d.ts +10 -0
  81. package/dist/upgrade.js +81 -0
  82. package/dist/upgrade.js.map +1 -0
  83. package/dist/verify.d.ts +7 -0
  84. package/dist/verify.js +88 -0
  85. package/dist/verify.js.map +1 -0
  86. package/dist/version.d.ts +4 -0
  87. package/dist/version.js +6 -0
  88. package/dist/version.js.map +1 -0
  89. package/graph-ui/app.js +1065 -0
  90. package/graph-ui/index.html +197 -0
  91. package/graph-ui/model.js +141 -0
  92. package/graph-ui/relations.js +125 -0
  93. package/graph-ui/structure.js +74 -0
  94. package/graph-ui/style.css +1698 -0
  95. package/managed/errors/CAGE-APPR-001.md +32 -0
  96. package/managed/errors/CAGE-APPR-002.md +32 -0
  97. package/managed/errors/CAGE-APPR-003.md +32 -0
  98. package/managed/errors/CAGE-APPR-004.md +32 -0
  99. package/managed/errors/CAGE-APPR-005.md +32 -0
  100. package/managed/errors/CAGE-APPR-006.md +32 -0
  101. package/managed/errors/CAGE-APPR-007.md +32 -0
  102. package/managed/errors/CAGE-APPR-010.md +32 -0
  103. package/managed/errors/CAGE-AUTH-001.md +32 -0
  104. package/managed/errors/CAGE-BUDGET-001.md +32 -0
  105. package/managed/errors/CAGE-BUDGET-002.md +32 -0
  106. package/managed/errors/CAGE-BUDGET-003.md +32 -0
  107. package/managed/errors/CAGE-CMD-002.md +32 -0
  108. package/managed/errors/CAGE-CMD-003.md +34 -0
  109. package/managed/errors/CAGE-CONN-001.md +32 -0
  110. package/managed/errors/CAGE-CONN-002.md +32 -0
  111. package/managed/errors/CAGE-CONN-003.md +32 -0
  112. package/managed/errors/CAGE-CONN-004.md +32 -0
  113. package/managed/errors/CAGE-CONN-005.md +32 -0
  114. package/managed/errors/CAGE-CONN-006.md +32 -0
  115. package/managed/errors/CAGE-CONN-007.md +32 -0
  116. package/managed/errors/CAGE-CONN-008.md +32 -0
  117. package/managed/errors/CAGE-CONN-009.md +32 -0
  118. package/managed/errors/CAGE-CONN-010.md +32 -0
  119. package/managed/errors/CAGE-CONN-011.md +32 -0
  120. package/managed/errors/CAGE-CONN-012.md +32 -0
  121. package/managed/errors/CAGE-CREATE-001.md +32 -0
  122. package/managed/errors/CAGE-DECL-001.md +34 -0
  123. package/managed/errors/CAGE-DECL-002.md +34 -0
  124. package/managed/errors/CAGE-DECL-003.md +34 -0
  125. package/managed/errors/CAGE-DECL-004.md +34 -0
  126. package/managed/errors/CAGE-DEP-001.md +34 -0
  127. package/managed/errors/CAGE-DEP-002.md +34 -0
  128. package/managed/errors/CAGE-DEP-003.md +34 -0
  129. package/managed/errors/CAGE-DEP-004.md +34 -0
  130. package/managed/errors/CAGE-DEP-005.md +34 -0
  131. package/managed/errors/CAGE-DLQ-001.md +32 -0
  132. package/managed/errors/CAGE-ENV-001.md +32 -0
  133. package/managed/errors/CAGE-EVENT-001.md +32 -0
  134. package/managed/errors/CAGE-EVENT-002.md +32 -0
  135. package/managed/errors/CAGE-FIELD-001.md +32 -0
  136. package/managed/errors/CAGE-FIELD-002.md +32 -0
  137. package/managed/errors/CAGE-FIELD-003.md +32 -0
  138. package/managed/errors/CAGE-FIELD-004.md +32 -0
  139. package/managed/errors/CAGE-GEN-001.md +33 -0
  140. package/managed/errors/CAGE-GEN-002.md +33 -0
  141. package/managed/errors/CAGE-GRANT-001.md +32 -0
  142. package/managed/errors/CAGE-GRANT-002.md +32 -0
  143. package/managed/errors/CAGE-GRANT-003.md +32 -0
  144. package/managed/errors/CAGE-IMPACT-001.md +32 -0
  145. package/managed/errors/CAGE-JOB-001.md +32 -0
  146. package/managed/errors/CAGE-JOB-002.md +32 -0
  147. package/managed/errors/CAGE-JOB-003.md +32 -0
  148. package/managed/errors/CAGE-LINT-001.md +32 -0
  149. package/managed/errors/CAGE-MIG-001.md +32 -0
  150. package/managed/errors/CAGE-MIG-002.md +32 -0
  151. package/managed/errors/CAGE-MIG-003.md +32 -0
  152. package/managed/errors/CAGE-MIG-004.md +32 -0
  153. package/managed/errors/CAGE-MIG-005.md +32 -0
  154. package/managed/errors/CAGE-NAME-001.md +32 -0
  155. package/managed/errors/CAGE-NAME-002.md +32 -0
  156. package/managed/errors/CAGE-NAME-003.md +32 -0
  157. package/managed/errors/CAGE-NAME-004.md +32 -0
  158. package/managed/errors/CAGE-NAME-005.md +32 -0
  159. package/managed/errors/CAGE-NAME-006.md +32 -0
  160. package/managed/errors/CAGE-ORG-001.md +32 -0
  161. package/managed/errors/CAGE-PAIR-002.md +33 -0
  162. package/managed/errors/CAGE-QUERY-001.md +32 -0
  163. package/managed/errors/CAGE-QUERY-002.md +32 -0
  164. package/managed/errors/CAGE-QUERY-003.md +32 -0
  165. package/managed/errors/CAGE-REACT-001.md +32 -0
  166. package/managed/errors/CAGE-REACT-002.md +32 -0
  167. package/managed/errors/CAGE-READS-001.md +32 -0
  168. package/managed/errors/CAGE-REG-001.md +32 -0
  169. package/managed/errors/CAGE-REG-002.md +32 -0
  170. package/managed/errors/CAGE-REG-003.md +32 -0
  171. package/managed/errors/CAGE-ROUTE-001.md +32 -0
  172. package/managed/errors/CAGE-SCOPE-001.md +32 -0
  173. package/managed/errors/CAGE-SCOPE-002.md +32 -0
  174. package/managed/errors/CAGE-SECRET-001.md +32 -0
  175. package/managed/errors/CAGE-SECRET-002.md +32 -0
  176. package/managed/errors/CAGE-SENS-001.md +32 -0
  177. package/managed/errors/CAGE-SQL-001.md +32 -0
  178. package/managed/errors/CAGE-SQL-002.md +32 -0
  179. package/managed/errors/CAGE-STATE-001.md +32 -0
  180. package/managed/errors/CAGE-STATE-002.md +32 -0
  181. package/managed/errors/CAGE-STATE-003.md +32 -0
  182. package/managed/errors/CAGE-STATE-004.md +32 -0
  183. package/managed/errors/CAGE-STATE-005.md +32 -0
  184. package/managed/errors/CAGE-STATE-010.md +32 -0
  185. package/managed/errors/CAGE-STATE-011.md +32 -0
  186. package/managed/errors/CAGE-SYNC-001.md +35 -0
  187. package/managed/errors/CAGE-TEST-001.md +33 -0
  188. package/managed/errors/CAGE-UNSAFE-001.md +32 -0
  189. package/managed/errors/CAGE-UPGRADE-001.md +32 -0
  190. package/managed/errors/README.md +99 -0
  191. package/package.json +60 -3
  192. package/templates/app/.dockerignore +10 -0
  193. package/templates/app/.env.example +17 -0
  194. package/templates/app/.github/workflows/cage.yml +44 -0
  195. package/templates/app/AGENTS.md +13 -0
  196. package/templates/app/Dockerfile +23 -0
  197. package/templates/app/README.md +58 -0
  198. package/templates/app/apps/api/package.json +16 -0
  199. package/templates/app/apps/api/src/main.ts +10 -0
  200. package/templates/app/apps/api/src/worker.ts +14 -0
  201. package/templates/app/apps/api/tsconfig.json +5 -0
  202. package/templates/app/apps/web/index.html +13 -0
  203. package/templates/app/apps/web/package.json +22 -0
  204. package/templates/app/apps/web/src/main.tsx +552 -0
  205. package/templates/app/apps/web/src/style.css +663 -0
  206. package/templates/app/apps/web/tsconfig.json +11 -0
  207. package/templates/app/apps/web/vite.config.ts +16 -0
  208. package/templates/app/cage.config.json +114 -0
  209. package/templates/app/compose.yaml +39 -0
  210. package/templates/app/db/migrations/0001_init.sql +112 -0
  211. package/templates/app/package.json +25 -0
  212. package/templates/app/packages/contracts/package.json +16 -0
  213. package/templates/app/packages/contracts/src/dept.ts +74 -0
  214. package/templates/app/packages/contracts/src/index.ts +81 -0
  215. package/templates/app/packages/contracts/src/inventory-lock.ts +52 -0
  216. package/templates/app/packages/contracts/src/inventory.ts +57 -0
  217. package/templates/app/packages/contracts/src/purchase-order.ts +72 -0
  218. package/templates/app/packages/contracts/src/queries.ts +17 -0
  219. package/templates/app/packages/contracts/src/role.ts +85 -0
  220. package/templates/app/packages/contracts/src/user.ts +89 -0
  221. package/templates/app/packages/contracts/tsconfig.json +5 -0
  222. package/templates/app/packages/domain/package.json +23 -0
  223. package/templates/app/packages/domain/src/approvals.ts +18 -0
  224. package/templates/app/packages/domain/src/erp.ts +36 -0
  225. package/templates/app/packages/domain/src/index.ts +9 -0
  226. package/templates/app/packages/domain/src/inventory.ts +43 -0
  227. package/templates/app/packages/domain/src/jobs.ts +13 -0
  228. package/templates/app/packages/domain/src/purchase-order.test.ts +137 -0
  229. package/templates/app/packages/domain/src/purchase-order.ts +122 -0
  230. package/templates/app/packages/domain/src/queries.ts +10 -0
  231. package/templates/app/packages/domain/src/reactions.ts +24 -0
  232. package/templates/app/packages/domain/tsconfig.json +5 -0
  233. package/templates/app/pnpm-workspace.yaml +10 -0
  234. package/templates/app/renovate.json +5 -0
  235. package/templates/app/tsconfig.base.json +8 -0
@@ -0,0 +1,32 @@
1
+ # CAGE-APPR-001
2
+
3
+ ## 什么时候出现
4
+
5
+ 命中以下实现中的检查时触发。终端会附具体声明位置、原因和修复方法。
6
+
7
+ 来源:[packages/kernel/src/primitives/flow.ts:134](../../packages/kernel/src/primitives/flow.ts)
8
+
9
+ ```ts
10
+ for (const f of def.routable) {
11
+ if (!(f in agg.fields)) throw declError('CAGE-APPR-001', `可路由字段 ${agg.name}.${f} 不存在`);
12
+ }
13
+ for (const c of [def.onApproved, def.onRejected]) {
14
+ if (c.agg !== agg) throw declError('CAGE-APPR-002', `审批结论命令必须属于 ${agg.name}`);
15
+ if (!c.invokedBy.includes('process')) {
16
+ ```
17
+
18
+ ## 怎么修
19
+
20
+ 核对流程绑定、可路由字段、结论命令及审批人配置。结论只能调用所属聚合的 process 命令。
21
+
22
+ ## 正例
23
+
24
+ ```text
25
+ onApproved: approve // approve 声明 invokedBy: 'process'
26
+ ```
27
+
28
+ ## 反例
29
+
30
+ ```text
31
+ onApproved: otherAggregateCommand // 结论落到了错误聚合
32
+ ```
@@ -0,0 +1,32 @@
1
+ # CAGE-APPR-002
2
+
3
+ ## 什么时候出现
4
+
5
+ 命中以下实现中的检查时触发。终端会附具体声明位置、原因和修复方法。
6
+
7
+ 来源:[packages/kernel/src/primitives/flow.ts:137](../../packages/kernel/src/primitives/flow.ts)
8
+
9
+ ```ts
10
+ for (const c of [def.onApproved, def.onRejected]) {
11
+ if (c.agg !== agg) throw declError('CAGE-APPR-002', `审批结论命令必须属于 ${agg.name}`);
12
+ if (!c.invokedBy.includes('process')) {
13
+ throw declError('CAGE-APPR-003', `审批结论命令必须声明 invokedBy: 'process'`);
14
+ }
15
+ }
16
+ ```
17
+
18
+ ## 怎么修
19
+
20
+ 核对流程绑定、可路由字段、结论命令及审批人配置。结论只能调用所属聚合的 process 命令。
21
+
22
+ ## 正例
23
+
24
+ ```text
25
+ onApproved: approve // approve 声明 invokedBy: 'process'
26
+ ```
27
+
28
+ ## 反例
29
+
30
+ ```text
31
+ onApproved: otherAggregateCommand // 结论落到了错误聚合
32
+ ```
@@ -0,0 +1,32 @@
1
+ # CAGE-APPR-003
2
+
3
+ ## 什么时候出现
4
+
5
+ 命中以下实现中的检查时触发。终端会附具体声明位置、原因和修复方法。
6
+
7
+ 来源:[packages/kernel/src/primitives/flow.ts:139](../../packages/kernel/src/primitives/flow.ts)
8
+
9
+ ```ts
10
+ if (!c.invokedBy.includes('process')) {
11
+ throw declError('CAGE-APPR-003', `审批结论命令必须声明 invokedBy: 'process'`);
12
+ }
13
+ }
14
+ return Object.freeze({
15
+ [APPROVAL]: true as const,
16
+ ```
17
+
18
+ ## 怎么修
19
+
20
+ 核对流程绑定、可路由字段、结论命令及审批人配置。结论只能调用所属聚合的 process 命令。
21
+
22
+ ## 正例
23
+
24
+ ```text
25
+ onApproved: approve // approve 声明 invokedBy: 'process'
26
+ ```
27
+
28
+ ## 反例
29
+
30
+ ```text
31
+ onApproved: otherAggregateCommand // 结论落到了错误聚合
32
+ ```
@@ -0,0 +1,32 @@
1
+ # CAGE-APPR-004
2
+
3
+ ## 什么时候出现
4
+
5
+ 命中以下实现中的检查时触发。终端会附具体声明位置、原因和修复方法。
6
+
7
+ 来源:[packages/approval/src/bridge.ts:8](../../packages/approval/src/bridge.ts)
8
+
9
+ ```ts
10
+ const binding = k.registry.approvalByProcess(r.process);
11
+ if (!binding) throw new Error(`[CAGE-APPR-004] 没有流程 ${r.process} 的审批绑定`);
12
+ const cmd = r.outcome === 'approved' ? binding.a.onApproved : binding.a.onRejected;
13
+ const ctx = k.processCtx({
14
+ process: r.process,
15
+ tenantId: r.tenantId,
16
+ ```
17
+
18
+ ## 怎么修
19
+
20
+ 核对流程绑定、可路由字段、结论命令及审批人配置。结论只能调用所属聚合的 process 命令。
21
+
22
+ ## 正例
23
+
24
+ ```text
25
+ onApproved: approve // approve 声明 invokedBy: 'process'
26
+ ```
27
+
28
+ ## 反例
29
+
30
+ ```text
31
+ onApproved: otherAggregateCommand // 结论落到了错误聚合
32
+ ```
@@ -0,0 +1,32 @@
1
+ # CAGE-APPR-005
2
+
3
+ ## 什么时候出现
4
+
5
+ 命中以下实现中的检查时触发。终端会附具体声明位置、原因和修复方法。
6
+
7
+ 来源:[packages/approval/src/route.ts:96](../../packages/approval/src/route.ts)
8
+
9
+ ```ts
10
+ export function route(process: string, nodes: RouteNode[]): Route {
11
+ if (!/^[a-z][a-z0-9-]*$/.test(process)) throw declError('CAGE-APPR-005', `流程名 ${process} 必须是小写短横线`);
12
+ if (nodes.length === 0) throw declError('CAGE-APPR-006', `流程 ${process} 至少需要一个步骤`);
13
+ const fields = new Set<string>();
14
+ for (const n of nodes) {
15
+ const steps = n.kind === 'step' ? [n] : n.steps;
16
+ ```
17
+
18
+ ## 怎么修
19
+
20
+ 核对流程绑定、可路由字段、结论命令及审批人配置。结论只能调用所属聚合的 process 命令。
21
+
22
+ ## 正例
23
+
24
+ ```text
25
+ onApproved: approve // approve 声明 invokedBy: 'process'
26
+ ```
27
+
28
+ ## 反例
29
+
30
+ ```text
31
+ onApproved: otherAggregateCommand // 结论落到了错误聚合
32
+ ```
@@ -0,0 +1,32 @@
1
+ # CAGE-APPR-006
2
+
3
+ ## 什么时候出现
4
+
5
+ 命中以下实现中的检查时触发。终端会附具体声明位置、原因和修复方法。
6
+
7
+ 来源:[packages/approval/src/route.ts:97](../../packages/approval/src/route.ts)
8
+
9
+ ```ts
10
+ if (!/^[a-z][a-z0-9-]*$/.test(process)) throw declError('CAGE-APPR-005', `流程名 ${process} 必须是小写短横线`);
11
+ if (nodes.length === 0) throw declError('CAGE-APPR-006', `流程 ${process} 至少需要一个步骤`);
12
+ const fields = new Set<string>();
13
+ for (const n of nodes) {
14
+ const steps = n.kind === 'step' ? [n] : n.steps;
15
+ if (n.kind === 'when') fields.add(n.cond.field);
16
+ ```
17
+
18
+ ## 怎么修
19
+
20
+ 核对流程绑定、可路由字段、结论命令及审批人配置。结论只能调用所属聚合的 process 命令。
21
+
22
+ ## 正例
23
+
24
+ ```text
25
+ onApproved: approve // approve 声明 invokedBy: 'process'
26
+ ```
27
+
28
+ ## 反例
29
+
30
+ ```text
31
+ onApproved: otherAggregateCommand // 结论落到了错误聚合
32
+ ```
@@ -0,0 +1,32 @@
1
+ # CAGE-APPR-007
2
+
3
+ ## 什么时候出现
4
+
5
+ 命中以下实现中的检查时触发。终端会附具体声明位置、原因和修复方法。
6
+
7
+ 来源:[packages/approval/src/engine.ts:64](../../packages/approval/src/engine.ts)
8
+
9
+ ```ts
10
+ if (who.length === 0) {
11
+ throw new Error(`[CAGE-APPR-007] 流程 ${this.route.process} 第 ${index + 1} 步「${s.title}」找不到审批人,请在 /admin 配置部门负责人或角色`);
12
+ }
13
+ for (const assignee of new Set(who)) {
14
+ await tx.insertInto('flow.approval_task').values({ instance_id: instanceId, tenant_id: tenantId, step: index, title: s.title, assignee }).execute();
15
+ }
16
+ ```
17
+
18
+ ## 怎么修
19
+
20
+ 核对流程绑定、可路由字段、结论命令及审批人配置。结论只能调用所属聚合的 process 命令。
21
+
22
+ ## 正例
23
+
24
+ ```text
25
+ onApproved: approve // approve 声明 invokedBy: 'process'
26
+ ```
27
+
28
+ ## 反例
29
+
30
+ ```text
31
+ onApproved: otherAggregateCommand // 结论落到了错误聚合
32
+ ```
@@ -0,0 +1,32 @@
1
+ # CAGE-APPR-010
2
+
3
+ ## 什么时候出现
4
+
5
+ 命中以下实现中的检查时触发。终端会附具体声明位置、原因和修复方法。
6
+
7
+ 来源:[packages/cli/src/rules.ts:140](../../packages/cli/src/rules.ts)
8
+
9
+ ```ts
10
+
11
+ /** CAGE-APPR-010:invokedBy 为 process 的命令必须有审批绑定或反应调用它,否则没有人能调用 */
12
+ export function checkProcessCommands(g: Ontology): Finding[] {
13
+ const { into } = index(g);
14
+ const findings: Finding[] = [];
15
+ for (const c of g.nodes.filter((n) => n.kind === 'command')) {
16
+ ```
17
+
18
+ ## 怎么修
19
+
20
+ 核对流程绑定、可路由字段、结论命令及审批人配置。结论只能调用所属聚合的 process 命令。
21
+
22
+ ## 正例
23
+
24
+ ```text
25
+ onApproved: approve // approve 声明 invokedBy: 'process'
26
+ ```
27
+
28
+ ## 反例
29
+
30
+ ```text
31
+ onApproved: otherAggregateCommand // 结论落到了错误聚合
32
+ ```
@@ -0,0 +1,32 @@
1
+ # CAGE-AUTH-001
2
+
3
+ ## 什么时候出现
4
+
5
+ 命中以下实现中的检查时触发。终端会附具体声明位置、原因和修复方法。
6
+
7
+ 来源:[packages/http/src/oidc.ts:20](../../packages/http/src/oidc.ts)
8
+
9
+ ```ts
10
+ (disco ??= fetch(new URL('.well-known/openid-configuration', o.issuer.endsWith('/') ? o.issuer : `${o.issuer}/`)).then(async (r) => {
11
+ if (!r.ok) throw new Error(`[CAGE-AUTH-001] OIDC 发现文档获取失败:${r.status}`);
12
+ return (await r.json()) as Discovery;
13
+ }));
14
+ const secure = opts.cookieSecure ?? process.env.NODE_ENV === 'production';
15
+
16
+ ```
17
+
18
+ ## 怎么修
19
+
20
+ 核对 OIDC 发现文档、issuer 和客户端配置,在部署环境配置所需变量。
21
+
22
+ ## 正例
23
+
24
+ ```text
25
+ OIDC_ISSUER + OIDC_CLIENT_ID + OIDC_REDIRECT_URI
26
+ ```
27
+
28
+ ## 反例
29
+
30
+ ```text
31
+ // issuer 不匹配或缺少客户端配置
32
+ ```
@@ -0,0 +1,32 @@
1
+ # CAGE-BUDGET-001
2
+
3
+ ## 什么时候出现
4
+
5
+ 命中以下实现中的检查时触发。终端会附具体声明位置、原因和修复方法。
6
+
7
+ 来源:[packages/cli/src/budget.ts:45](../../packages/cli/src/budget.ts)
8
+
9
+ ```ts
10
+ findings.push({
11
+ code: 'CAGE-BUDGET-001',
12
+ reason: `内核 ${lines} 行,超过 5000 行预算`,
13
+ fix: '拆出扩展职责,或提交架构评审调整预算',
14
+ });
15
+ if (primitives !== null && primitives > 16)
16
+ ```
17
+
18
+ ## 怎么修
19
+
20
+ 减少内核职责,移除不必要的 unsafe;预算调整及基线更新必须经过评审。
21
+
22
+ ## 正例
23
+
24
+ ```text
25
+ node packages/cli/bin/cage.js budget
26
+ ```
27
+
28
+ ## 反例
29
+
30
+ ```text
31
+ // 未评审就增加公共原语或 unsafe 数量
32
+ ```
@@ -0,0 +1,32 @@
1
+ # CAGE-BUDGET-002
2
+
3
+ ## 什么时候出现
4
+
5
+ 命中以下实现中的检查时触发。终端会附具体声明位置、原因和修复方法。
6
+
7
+ 来源:[packages/cli/src/budget.ts:51](../../packages/cli/src/budget.ts)
8
+
9
+ ```ts
10
+ findings.push({
11
+ code: 'CAGE-BUDGET-002',
12
+ reason: `品牌原语 ${primitives} 个,超过 16 个预算`,
13
+ fix: '优先使用组合子,避免新增原语',
14
+ });
15
+ const allowance = base?.unsafeCount ?? 0;
16
+ ```
17
+
18
+ ## 怎么修
19
+
20
+ 减少内核职责,移除不必要的 unsafe;预算调整及基线更新必须经过评审。
21
+
22
+ ## 正例
23
+
24
+ ```text
25
+ node packages/cli/bin/cage.js budget
26
+ ```
27
+
28
+ ## 反例
29
+
30
+ ```text
31
+ // 未评审就增加公共原语或 unsafe 数量
32
+ ```
@@ -0,0 +1,32 @@
1
+ # CAGE-BUDGET-003
2
+
3
+ ## 什么时候出现
4
+
5
+ 命中以下实现中的检查时触发。终端会附具体声明位置、原因和修复方法。
6
+
7
+ 来源:[packages/cli/src/budget.ts:58](../../packages/cli/src/budget.ts)
8
+
9
+ ```ts
10
+ findings.push({
11
+ code: 'CAGE-BUDGET-003',
12
+ reason: `unsafe 从 ${allowance} 增加到 ${graph.unsafeCount}`,
13
+ fix: '移除新增逃生口,或在评审完成后更新受审基线',
14
+ });
15
+ return { metrics: { kernelLines: lines, primitives, unsafe: graph.unsafeCount }, findings };
16
+ ```
17
+
18
+ ## 怎么修
19
+
20
+ 减少内核职责,移除不必要的 unsafe;预算调整及基线更新必须经过评审。
21
+
22
+ ## 正例
23
+
24
+ ```text
25
+ node packages/cli/bin/cage.js budget
26
+ ```
27
+
28
+ ## 反例
29
+
30
+ ```text
31
+ // 未评审就增加公共原语或 unsafe 数量
32
+ ```
@@ -0,0 +1,32 @@
1
+ # CAGE-CMD-002
2
+
3
+ ## 什么时候出现
4
+
5
+ 命中以下实现中的检查时触发。终端会附具体声明位置、原因和修复方法。
6
+
7
+ 来源:[packages/kernel/src/primitives/command.ts:142](../../packages/kernel/src/primitives/command.ts)
8
+
9
+ ```ts
10
+ if (from !== 'new' && input instanceof z.ZodObject && !('id' in input.shape)) {
11
+ throw declError('CAGE-CMD-002', `${agg.name} 的非新建命令输入必须包含 id`);
12
+ }
13
+ if (def.name !== undefined && !/^[a-z][A-Za-z0-9]*$/.test(def.name)) {
14
+ throw declError('CAGE-NAME-004', `命令名 ${def.name} 必须是小驼峰`);
15
+ }
16
+ ```
17
+
18
+ ## 怎么修
19
+
20
+ 非新建命令的输入必须含 id;from/to、调用身份和聚合定义保持一致。
21
+
22
+ ## 正例
23
+
24
+ ```text
25
+ input: z.object({ id: z.string().uuid(), note: z.string() })
26
+ ```
27
+
28
+ ## 反例
29
+
30
+ ```text
31
+ input: z.object({ note: z.string() }) // 非新建命令缺少 id
32
+ ```
@@ -0,0 +1,34 @@
1
+ # CAGE-CMD-003
2
+
3
+ ## 什么时候出现
4
+
5
+ 命中以下实现中的检查时触发。终端会附具体声明位置、原因和修复方法。
6
+
7
+ 来源:[packages/kernel/src/primitives/command.ts:135](../../packages/kernel/src/primitives/command.ts)
8
+
9
+ ```ts
10
+ if (from === 'new' && def.to === null) {
11
+ throw declError('CAGE-CMD-003', `${agg.name} 的新建命令必须指定目标状态,不能使用 to: null`);
12
+ }
13
+ if (def.to !== null && !hasStates(agg, def.to as string)) {
14
+ throw declError('CAGE-STATE-001', `${agg.name} 的命令 to 是未声明的状态:${String(def.to)}`);
15
+ }
16
+ ```
17
+
18
+ ## 怎么修
19
+
20
+ 新建命令必须指定聚合中声明的目标状态。to: null 仅用于已有记录的字段更新;它保留加锁读出的状态,不跳过 from、权限、版本及审计检查。
21
+
22
+ ## 正例
23
+
24
+ ```text
25
+ command(Order, { from: 'new', to: 'draft', handler: o => o });
26
+ // 晚到回执可以保留终态
27
+ command(Order, { from: ['approved', 'cancelled'], to: null, handler: o => o });
28
+ ```
29
+
30
+ ## 反例
31
+
32
+ ```text
33
+ command(Order, { from: 'new', to: null, handler: o => o }); // 新记录没有可保留的状态
34
+ ```
@@ -0,0 +1,32 @@
1
+ # CAGE-CONN-001
2
+
3
+ ## 什么时候出现
4
+
5
+ 命中以下实现中的检查时触发。终端会附具体声明位置、原因和修复方法。
6
+
7
+ 来源:[packages/connectors/src/primitives.ts:56](../../packages/connectors/src/primitives.ts)
8
+
9
+ ```ts
10
+ export function connector<Ops extends Record<string, OpDef<any, any>>>(name: string, def: ConnectorDef<Ops>): Connector<Ops> {
11
+ if (!/^[a-z][a-z0-9-]*$/.test(name)) throw declError('CAGE-CONN-001', `连接器名 ${name} 必须是小写短横线`);
12
+ for (const h of Object.values(def.hosts)) {
13
+ if (h && /[/:\s]/.test(h.replace(/:\d+$/, ''))) throw declError('CAGE-CONN-003', `地址白名单只能写主机名(可带端口):${h}`);
14
+ }
15
+ const c: any = {
16
+ ```
17
+
18
+ ## 怎么修
19
+
20
+ 核对 host 白名单、操作名、字段 schema 和签名。永久失败应先修正配置再重放死信。
21
+
22
+ ## 正例
23
+
24
+ ```text
25
+ hosts: { test: 'erp-sandbox.example.com', prod: 'erp.example.com' }
26
+ ```
27
+
28
+ ## 反例
29
+
30
+ ```text
31
+ // outbound 映射发送了 request schema 之外的字段
32
+ ```
@@ -0,0 +1,32 @@
1
+ # CAGE-CONN-002
2
+
3
+ ## 什么时候出现
4
+
5
+ 命中以下实现中的检查时触发。终端会附具体声明位置、原因和修复方法。
6
+
7
+ 来源:[packages/connectors/src/primitives.ts:29](../../packages/connectors/src/primitives.ts)
8
+
9
+ ```ts
10
+ export function op<Req extends z.ZodObject<any>, Res extends z.ZodType>(def: OpDef<Req, Res>): OpDef<Req, Res> {
11
+ if (!def.path.startsWith('/')) throw declError('CAGE-CONN-002', `操作路径 ${def.path} 必须以 / 开头`);
12
+ return def;
13
+ }
14
+
15
+ export interface ConnectorDef<Ops extends Record<string, OpDef<any, any>>> {
16
+ ```
17
+
18
+ ## 怎么修
19
+
20
+ 核对 host 白名单、操作名、字段 schema 和签名。永久失败应先修正配置再重放死信。
21
+
22
+ ## 正例
23
+
24
+ ```text
25
+ hosts: { test: 'erp-sandbox.example.com', prod: 'erp.example.com' }
26
+ ```
27
+
28
+ ## 反例
29
+
30
+ ```text
31
+ // outbound 映射发送了 request schema 之外的字段
32
+ ```
@@ -0,0 +1,32 @@
1
+ # CAGE-CONN-003
2
+
3
+ ## 什么时候出现
4
+
5
+ 命中以下实现中的检查时触发。终端会附具体声明位置、原因和修复方法。
6
+
7
+ 来源:[packages/connectors/src/primitives.ts:58](../../packages/connectors/src/primitives.ts)
8
+
9
+ ```ts
10
+ for (const h of Object.values(def.hosts)) {
11
+ if (h && /[/:\s]/.test(h.replace(/:\d+$/, ''))) throw declError('CAGE-CONN-003', `地址白名单只能写主机名(可带端口):${h}`);
12
+ }
13
+ const c: any = {
14
+ [CONNECTOR]: true,
15
+ name,
16
+ ```
17
+
18
+ ## 怎么修
19
+
20
+ 核对 host 白名单、操作名、字段 schema 和签名。永久失败应先修正配置再重放死信。
21
+
22
+ ## 正例
23
+
24
+ ```text
25
+ hosts: { test: 'erp-sandbox.example.com', prod: 'erp.example.com' }
26
+ ```
27
+
28
+ ## 反例
29
+
30
+ ```text
31
+ // outbound 映射发送了 request schema 之外的字段
32
+ ```
@@ -0,0 +1,32 @@
1
+ # CAGE-CONN-004
2
+
3
+ ## 什么时候出现
4
+
5
+ 命中以下实现中的检查时触发。终端会附具体声明位置、原因和修复方法。
6
+
7
+ 来源:[packages/connectors/src/primitives.ts:99](../../packages/connectors/src/primitives.ts)
8
+
9
+ ```ts
10
+ ): Outbound<E, O> {
11
+ if (operation.effect === 'read') throw declError('CAGE-CONN-004', '只读操作不能用于出站映射');
12
+ const o: any = {
13
+ [OUTBOUND]: true,
14
+ event: ev,
15
+ op: operation,
16
+ ```
17
+
18
+ ## 怎么修
19
+
20
+ 核对 host 白名单、操作名、字段 schema 和签名。永久失败应先修正配置再重放死信。
21
+
22
+ ## 正例
23
+
24
+ ```text
25
+ hosts: { test: 'erp-sandbox.example.com', prod: 'erp.example.com' }
26
+ ```
27
+
28
+ ## 反例
29
+
30
+ ```text
31
+ // outbound 映射发送了 request schema 之外的字段
32
+ ```
@@ -0,0 +1,32 @@
1
+ # CAGE-CONN-005
2
+
3
+ ## 什么时候出现
4
+
5
+ 命中以下实现中的检查时触发。终端会附具体声明位置、原因和修复方法。
6
+
7
+ 来源:[packages/connectors/src/primitives.ts:153](../../packages/connectors/src/primitives.ts)
8
+
9
+ ```ts
10
+ ): Inbound<P> {
11
+ if (!/^[a-z][A-Za-z0-9]*$/.test(eventName)) throw declError('CAGE-CONN-005', `入站事件名 ${eventName} 必须是小驼峰`);
12
+ if (!def.command.invokedBy.includes('external') && !def.command.invokedBy.includes('user')) {
13
+ throw declError('CAGE-CONN-006', `入站回调调用的命令必须声明 invokedBy: 'external'`);
14
+ }
15
+ return Object.freeze({ [INBOUND]: true as const, connector: conn, event: eventName, ...def });
16
+ ```
17
+
18
+ ## 怎么修
19
+
20
+ 核对 host 白名单、操作名、字段 schema 和签名。永久失败应先修正配置再重放死信。
21
+
22
+ ## 正例
23
+
24
+ ```text
25
+ hosts: { test: 'erp-sandbox.example.com', prod: 'erp.example.com' }
26
+ ```
27
+
28
+ ## 反例
29
+
30
+ ```text
31
+ // outbound 映射发送了 request schema 之外的字段
32
+ ```
@@ -0,0 +1,32 @@
1
+ # CAGE-CONN-006
2
+
3
+ ## 什么时候出现
4
+
5
+ 命中以下实现中的检查时触发。终端会附具体声明位置、原因和修复方法。
6
+
7
+ 来源:[packages/connectors/src/primitives.ts:155](../../packages/connectors/src/primitives.ts)
8
+
9
+ ```ts
10
+ if (!def.command.invokedBy.includes('external') && !def.command.invokedBy.includes('user')) {
11
+ throw declError('CAGE-CONN-006', `入站回调调用的命令必须声明 invokedBy: 'external'`);
12
+ }
13
+ return Object.freeze({ [INBOUND]: true as const, connector: conn, event: eventName, ...def });
14
+ }
15
+
16
+ ```
17
+
18
+ ## 怎么修
19
+
20
+ 核对 host 白名单、操作名、字段 schema 和签名。永久失败应先修正配置再重放死信。
21
+
22
+ ## 正例
23
+
24
+ ```text
25
+ hosts: { test: 'erp-sandbox.example.com', prod: 'erp.example.com' }
26
+ ```
27
+
28
+ ## 反例
29
+
30
+ ```text
31
+ // outbound 映射发送了 request schema 之外的字段
32
+ ```