@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-SECRET-002
2
+
3
+ ## 什么时候出现
4
+
5
+ 命中以下实现中的检查时触发。终端会附具体声明位置、原因和修复方法。
6
+
7
+ 来源:[packages/lint/src/rules/no-secret-literal.ts:19](../../packages/lint/src/rules/no-secret-literal.ts)
8
+
9
+ ```ts
10
+ docs: { description: '禁止密钥字面量' },
11
+ messages: { secret: '[CAGE-SECRET-002] 疑似{{what}}写在了代码里:密钥只写名字,值由密钥管理服务注入' },
12
+ schema: [],
13
+ },
14
+ create(context) {
15
+ const check = (node: any, value: string, name?: string) => {
16
+ ```
17
+
18
+ ## 怎么修
19
+
20
+ 配置中只写密钥名;密钥值通过运行环境注入,移除源码中的字面量。
21
+
22
+ ## 正例
23
+
24
+ ```text
25
+ secret: 'ERP_API_TOKEN'
26
+ ```
27
+
28
+ ## 反例
29
+
30
+ ```text
31
+ secret: 'a-real-token-in-source'
32
+ ```
@@ -0,0 +1,32 @@
1
+ # CAGE-SENS-001
2
+
3
+ ## 什么时候出现
4
+
5
+ 命中以下实现中的检查时触发。终端会附具体声明位置、原因和修复方法。
6
+
7
+ 来源:[packages/cli/src/rules.ts:114](../../packages/cli/src/rules.ts)
8
+
9
+ ```ts
10
+
11
+ /** CAGE-SENS-001:敏感字段不得原样进入事件载荷 */
12
+ export function checkSensitiveEvents(g: Ontology): Finding[] {
13
+ const { get, out } = index(g);
14
+ const findings: Finding[] = [];
15
+ for (const c of g.nodes.filter((n) => n.kind === 'command')) {
16
+ ```
17
+
18
+ ## 怎么修
19
+
20
+ 从事件移除敏感字段,或保留与聚合一致的 sensitive 标注,让运行时脱敏。
21
+
22
+ ## 正例
23
+
24
+ ```text
25
+ event('OrderChanged', { phone: text().sensitive('phone') })
26
+ ```
27
+
28
+ ## 反例
29
+
30
+ ```text
31
+ event('OrderChanged', { phone: text() }) // 来源字段是敏感电话
32
+ ```
@@ -0,0 +1,32 @@
1
+ # CAGE-SQL-001
2
+
3
+ ## 什么时候出现
4
+
5
+ 命中以下实现中的检查时触发。终端会附具体声明位置、原因和修复方法。
6
+
7
+ 来源:[packages/lint/src/rules/no-sql-concat.ts:19](../../packages/lint/src/rules/no-sql-concat.ts)
8
+
9
+ ```ts
10
+ messages: {
11
+ concat: '[CAGE-SQL-001] 不要拼接 SQL 字符串,改用 sql 标签模板或查询构建器(值会自动参数化)',
12
+ raw: '[CAGE-SQL-002] sql.raw() 只能接收字面量',
13
+ },
14
+ schema: [],
15
+ },
16
+ ```
17
+
18
+ ## 怎么修
19
+
20
+ 使用参数化 SQL 或查询构建器;sql.raw 只接收固定 SQL 片段。
21
+
22
+ ## 正例
23
+
24
+ ```text
25
+ sql`select * from safe.purchase_order where id = ${id}`
26
+ ```
27
+
28
+ ## 反例
29
+
30
+ ```text
31
+ 'select * from safe.purchase_order where id = ' + input
32
+ ```
@@ -0,0 +1,32 @@
1
+ # CAGE-SQL-002
2
+
3
+ ## 什么时候出现
4
+
5
+ 命中以下实现中的检查时触发。终端会附具体声明位置、原因和修复方法。
6
+
7
+ 来源:[packages/lint/src/rules/no-sql-concat.ts:20](../../packages/lint/src/rules/no-sql-concat.ts)
8
+
9
+ ```ts
10
+ concat: '[CAGE-SQL-001] 不要拼接 SQL 字符串,改用 sql 标签模板或查询构建器(值会自动参数化)',
11
+ raw: '[CAGE-SQL-002] sql.raw() 只能接收字面量',
12
+ },
13
+ schema: [],
14
+ },
15
+ create(context) {
16
+ ```
17
+
18
+ ## 怎么修
19
+
20
+ 使用参数化 SQL 或查询构建器;sql.raw 只接收固定 SQL 片段。
21
+
22
+ ## 正例
23
+
24
+ ```text
25
+ sql`select * from safe.purchase_order where id = ${id}`
26
+ ```
27
+
28
+ ## 反例
29
+
30
+ ```text
31
+ 'select * from safe.purchase_order where id = ' + input
32
+ ```
@@ -0,0 +1,32 @@
1
+ # CAGE-STATE-001
2
+
3
+ ## 什么时候出现
4
+
5
+ 命中以下实现中的检查时触发。终端会附具体声明位置、原因和修复方法。
6
+
7
+ 来源:[packages/kernel/src/primitives/command.ts:130](../../packages/kernel/src/primitives/command.ts)
8
+
9
+ ```ts
10
+ if (from !== 'new' && !hasStates(agg, from)) {
11
+ throw declError('CAGE-STATE-001', `${agg.name} 的命令 from 里有未声明的状态:${[from].flat().join(', ')}`);
12
+ }
13
+ // 回执等异步元数据可能在单据取消/完成后到达。允许显式保留当前状态,
14
+ // 避免业务 handler 通过篡改 status 绕过状态机;新建命令必须有实际目标状态。
15
+ if (from === 'new' && def.to === null) {
16
+ ```
17
+
18
+ ## 怎么修
19
+
20
+ 让 from/to 引用已声明的状态,初始状态可达,非终态有出边,结束状态列入 terminal。
21
+
22
+ ## 正例
23
+
24
+ ```text
25
+ states('draft', 'done', { terminal: ['done'] });
26
+ ```
27
+
28
+ ## 反例
29
+
30
+ ```text
31
+ command(Order, { from: 'missing', to: 'done', handler: o => o });
32
+ ```
@@ -0,0 +1,32 @@
1
+ # CAGE-STATE-002
2
+
3
+ ## 什么时候出现
4
+
5
+ 命中以下实现中的检查时触发。终端会附具体声明位置、原因和修复方法。
6
+
7
+ 来源:[packages/kernel/src/primitives/states.ts:22](../../packages/kernel/src/primitives/states.ts)
8
+
9
+ ```ts
10
+ const values = all.filter((a): a is S => typeof a === 'string');
11
+ if (values.length === 0) throw declError('CAGE-STATE-002', 'states() 至少需要一个状态');
12
+ for (const v of values) {
13
+ if (!/^[a-z][a-z0-9_]*$/.test(v)) throw declError('CAGE-STATE-003', `状态名 ${v} 必须是小写下划线`);
14
+ }
15
+ if (new Set(values).size !== values.length) throw declError('CAGE-STATE-004', '状态名重复');
16
+ ```
17
+
18
+ ## 怎么修
19
+
20
+ 让 from/to 引用已声明的状态,初始状态可达,非终态有出边,结束状态列入 terminal。
21
+
22
+ ## 正例
23
+
24
+ ```text
25
+ states('draft', 'done', { terminal: ['done'] });
26
+ ```
27
+
28
+ ## 反例
29
+
30
+ ```text
31
+ command(Order, { from: 'missing', to: 'done', handler: o => o });
32
+ ```
@@ -0,0 +1,32 @@
1
+ # CAGE-STATE-003
2
+
3
+ ## 什么时候出现
4
+
5
+ 命中以下实现中的检查时触发。终端会附具体声明位置、原因和修复方法。
6
+
7
+ 来源:[packages/kernel/src/primitives/states.ts:24](../../packages/kernel/src/primitives/states.ts)
8
+
9
+ ```ts
10
+ for (const v of values) {
11
+ if (!/^[a-z][a-z0-9_]*$/.test(v)) throw declError('CAGE-STATE-003', `状态名 ${v} 必须是小写下划线`);
12
+ }
13
+ if (new Set(values).size !== values.length) throw declError('CAGE-STATE-004', '状态名重复');
14
+ const terminal = opts.terminal ?? [];
15
+ for (const t of [...terminal, ...(opts.initial ? [opts.initial] : [])]) {
16
+ ```
17
+
18
+ ## 怎么修
19
+
20
+ 让 from/to 引用已声明的状态,初始状态可达,非终态有出边,结束状态列入 terminal。
21
+
22
+ ## 正例
23
+
24
+ ```text
25
+ states('draft', 'done', { terminal: ['done'] });
26
+ ```
27
+
28
+ ## 反例
29
+
30
+ ```text
31
+ command(Order, { from: 'missing', to: 'done', handler: o => o });
32
+ ```
@@ -0,0 +1,32 @@
1
+ # CAGE-STATE-004
2
+
3
+ ## 什么时候出现
4
+
5
+ 命中以下实现中的检查时触发。终端会附具体声明位置、原因和修复方法。
6
+
7
+ 来源:[packages/kernel/src/primitives/states.ts:26](../../packages/kernel/src/primitives/states.ts)
8
+
9
+ ```ts
10
+ }
11
+ if (new Set(values).size !== values.length) throw declError('CAGE-STATE-004', '状态名重复');
12
+ const terminal = opts.terminal ?? [];
13
+ for (const t of [...terminal, ...(opts.initial ? [opts.initial] : [])]) {
14
+ if (!values.includes(t)) throw declError('CAGE-STATE-001', `状态 ${t} 未在 states 中声明`);
15
+ }
16
+ ```
17
+
18
+ ## 怎么修
19
+
20
+ 让 from/to 引用已声明的状态,初始状态可达,非终态有出边,结束状态列入 terminal。
21
+
22
+ ## 正例
23
+
24
+ ```text
25
+ states('draft', 'done', { terminal: ['done'] });
26
+ ```
27
+
28
+ ## 反例
29
+
30
+ ```text
31
+ command(Order, { from: 'missing', to: 'done', handler: o => o });
32
+ ```
@@ -0,0 +1,32 @@
1
+ # CAGE-STATE-005
2
+
3
+ ## 什么时候出现
4
+
5
+ 命中以下实现中的检查时触发。终端会附具体声明位置、原因和修复方法。
6
+
7
+ 来源:[packages/kernel/src/primitives/aggregate.ts:78](../../packages/kernel/src/primitives/aggregate.ts)
8
+
9
+ ```ts
10
+ if (isStates(v)) {
11
+ if (k !== 'status') throw declError('CAGE-STATE-005', `状态集只能放在 status 字段上(发现 ${name}.${k})`);
12
+ if (st) throw declError('CAGE-STATE-005', `${name} 同时在 states 和 fields.status 里声明了状态`);
13
+ st = v;
14
+ continue;
15
+ }
16
+ ```
17
+
18
+ ## 怎么修
19
+
20
+ 让 from/to 引用已声明的状态,初始状态可达,非终态有出边,结束状态列入 terminal。
21
+
22
+ ## 正例
23
+
24
+ ```text
25
+ states('draft', 'done', { terminal: ['done'] });
26
+ ```
27
+
28
+ ## 反例
29
+
30
+ ```text
31
+ command(Order, { from: 'missing', to: 'done', handler: o => o });
32
+ ```
@@ -0,0 +1,32 @@
1
+ # CAGE-STATE-010
2
+
3
+ ## 什么时候出现
4
+
5
+ 命中以下实现中的检查时触发。终端会附具体声明位置、原因和修复方法。
6
+
7
+ 来源:[packages/cli/src/rules.ts:67](../../packages/cli/src/rules.ts)
8
+
9
+ ```ts
10
+
11
+ /** CAGE-STATE-010:每个状态都能从初始状态到达;CAGE-STATE-011:非终态必须有出边 */
12
+ export function checkStates(g: Ontology): Finding[] {
13
+ const { get } = index(g);
14
+ const findings: Finding[] = [];
15
+ for (const a of g.nodes.filter((n) => n.kind === 'aggregate')) {
16
+ ```
17
+
18
+ ## 怎么修
19
+
20
+ 让 from/to 引用已声明的状态,初始状态可达,非终态有出边,结束状态列入 terminal。
21
+
22
+ ## 正例
23
+
24
+ ```text
25
+ states('draft', 'done', { terminal: ['done'] });
26
+ ```
27
+
28
+ ## 反例
29
+
30
+ ```text
31
+ command(Order, { from: 'missing', to: 'done', handler: o => o });
32
+ ```
@@ -0,0 +1,32 @@
1
+ # CAGE-STATE-011
2
+
3
+ ## 什么时候出现
4
+
5
+ 命中以下实现中的检查时触发。终端会附具体声明位置、原因和修复方法。
6
+
7
+ 来源:[packages/cli/src/rules.ts:67](../../packages/cli/src/rules.ts)
8
+
9
+ ```ts
10
+
11
+ /** CAGE-STATE-010:每个状态都能从初始状态到达;CAGE-STATE-011:非终态必须有出边 */
12
+ export function checkStates(g: Ontology): Finding[] {
13
+ const { get } = index(g);
14
+ const findings: Finding[] = [];
15
+ for (const a of g.nodes.filter((n) => n.kind === 'aggregate')) {
16
+ ```
17
+
18
+ ## 怎么修
19
+
20
+ 让 from/to 引用已声明的状态,初始状态可达,非终态有出边,结束状态列入 terminal。
21
+
22
+ ## 正例
23
+
24
+ ```text
25
+ states('draft', 'done', { terminal: ['done'] });
26
+ ```
27
+
28
+ ## 反例
29
+
30
+ ```text
31
+ command(Order, { from: 'missing', to: 'done', handler: o => o });
32
+ ```
@@ -0,0 +1,35 @@
1
+ # CAGE-SYNC-001
2
+
3
+ ## 什么时候出现
4
+
5
+ 命中以下实现中的检查时触发。终端会附具体声明位置、原因和修复方法。
6
+
7
+ 来源:[packages/cli/src/sync.ts:25](../../packages/cli/src/sync.ts)
8
+
9
+ ```ts
10
+ if (starts.length !== 1 || ends.length !== 1 || ends[0].index! < starts[0].index!) {
11
+ throw new Error('[CAGE-SYNC-001] 托管区标记不完整或重复,请修复 AGENTS.md 的 begin/end 标记');
12
+ }
13
+ return current.slice(0, starts[0].index) + latest + current.slice(ends[0].index! + ends[0][0].length);
14
+ }
15
+
16
+ ```
17
+
18
+ ## 怎么修
19
+
20
+ 修复唯一的 begin/end 标记,再执行 cage sync;托管区之外的内容会保留。
21
+
22
+ ## 正例
23
+
24
+ ```text
25
+ <!-- cage:begin v0.1.0 -->
26
+ 框架约定
27
+ <!-- cage:end -->
28
+ ```
29
+
30
+ ## 反例
31
+
32
+ ```text
33
+ <!-- cage:begin old -->
34
+ 没有结束标记
35
+ ```
@@ -0,0 +1,33 @@
1
+ # CAGE-TEST-001
2
+
3
+ ## 什么时候出现
4
+
5
+ 命中以下实现中的检查时触发。终端会附具体声明位置、原因和修复方法。
6
+
7
+ 来源:[packages/cli/src/verify.ts:36](../../packages/cli/src/verify.ts)
8
+
9
+ ```ts
10
+ if (code !== 0) return code;
11
+ if (!existsSync(report)) throw new Error('[CAGE-TEST-001] 测试进程未输出结果报告,不能判定通过');
12
+ const result = JSON.parse(readFileSync(report, 'utf8'));
13
+ if (result.numPendingTests) console.log(`覆盖提示:${result.numPendingTests} 个用例跳过,请结合业务测试验收。`);
14
+ return result.success ? 0 : 1;
15
+ }
16
+ ```
17
+
18
+ ## 怎么修
19
+
20
+ 检查 Vitest 的输出及配置。必须生成当前运行的 JSON 报告,失败不能当作通过。
21
+
22
+ ## 正例
23
+
24
+ ```text
25
+ cage test
26
+ // .cage/test-results.json 中 success: true
27
+ ```
28
+
29
+ ## 反例
30
+
31
+ ```text
32
+ // 测试启动失败却复用上一次结果
33
+ ```
@@ -0,0 +1,32 @@
1
+ # CAGE-UNSAFE-001
2
+
3
+ ## 什么时候出现
4
+
5
+ 命中以下实现中的检查时触发。终端会附具体声明位置、原因和修复方法。
6
+
7
+ 来源:[packages/kernel/src/primitives/flow.ts:219](../../packages/kernel/src/primitives/flow.ts)
8
+
9
+ ```ts
10
+ export function unsafe<T>(tag: UnsafeTag, fn: () => T): T {
11
+ if (!tag?.reason || !tag?.owner) throw declError('CAGE-UNSAFE-001', 'unsafe 必须写明 reason 和 owner');
12
+ return fn();
13
+ }
14
+ (unsafe as any)[UNSAFE] = true;
15
+
16
+ ```
17
+
18
+ ## 怎么修
19
+
20
+ 优先改为声明或命令;确需逃生口时填写非空 reason、owner,并记录评审。
21
+
22
+ ## 正例
23
+
24
+ ```text
25
+ unsafe({ reason: '一次性修复历史数据', owner: '数据负责人' }, action)
26
+ ```
27
+
28
+ ## 反例
29
+
30
+ ```text
31
+ unsafe({ reason: '', owner: '' }, action)
32
+ ```
@@ -0,0 +1,32 @@
1
+ # CAGE-UPGRADE-001
2
+
3
+ ## 什么时候出现
4
+
5
+ 命中以下实现中的检查时触发。终端会附具体声明位置、原因和修复方法。
6
+
7
+ 来源:[packages/cli/src/upgrade.ts:45](../../packages/cli/src/upgrade.ts)
8
+
9
+ ```ts
10
+ if (old && obj?.getProperty('invokedBy'))
11
+ throw new Error('[CAGE-UPGRADE-001] command 同时包含 caller 与 invokedBy,请手工消除歧义');
12
+ old?.rename('invokedBy');
13
+ }
14
+ return file.getFullText();
15
+ }
16
+ ```
17
+
18
+ ## 怎么修
19
+
20
+ 先安装目标版本 CLI,再运行对应 codemod;遇到同时存在新旧字段时手工消除歧义。
21
+
22
+ ## 正例
23
+
24
+ ```text
25
+ cage upgrade --dry-run
26
+ ```
27
+
28
+ ## 反例
29
+
30
+ ```text
31
+ command(A, { caller: 'user', invokedBy: 'process' })
32
+ ```
@@ -0,0 +1,99 @@
1
+ # 错误码册
2
+
3
+ 每个错误码包含触发位置、修复建议和正反例。框架源码更新后运行 `node scripts/build-error-docs.mjs` 刷新索引。
4
+
5
+ - [CAGE-APPR-001](CAGE-APPR-001.md)
6
+ - [CAGE-APPR-002](CAGE-APPR-002.md)
7
+ - [CAGE-APPR-003](CAGE-APPR-003.md)
8
+ - [CAGE-APPR-004](CAGE-APPR-004.md)
9
+ - [CAGE-APPR-005](CAGE-APPR-005.md)
10
+ - [CAGE-APPR-006](CAGE-APPR-006.md)
11
+ - [CAGE-APPR-007](CAGE-APPR-007.md)
12
+ - [CAGE-APPR-010](CAGE-APPR-010.md)
13
+ - [CAGE-AUTH-001](CAGE-AUTH-001.md)
14
+ - [CAGE-BUDGET-001](CAGE-BUDGET-001.md)
15
+ - [CAGE-BUDGET-002](CAGE-BUDGET-002.md)
16
+ - [CAGE-BUDGET-003](CAGE-BUDGET-003.md)
17
+ - [CAGE-CMD-002](CAGE-CMD-002.md)
18
+ - [CAGE-CMD-003](CAGE-CMD-003.md)
19
+ - [CAGE-CONN-001](CAGE-CONN-001.md)
20
+ - [CAGE-CONN-002](CAGE-CONN-002.md)
21
+ - [CAGE-CONN-003](CAGE-CONN-003.md)
22
+ - [CAGE-CONN-004](CAGE-CONN-004.md)
23
+ - [CAGE-CONN-005](CAGE-CONN-005.md)
24
+ - [CAGE-CONN-006](CAGE-CONN-006.md)
25
+ - [CAGE-CONN-007](CAGE-CONN-007.md)
26
+ - [CAGE-CONN-008](CAGE-CONN-008.md)
27
+ - [CAGE-CONN-009](CAGE-CONN-009.md)
28
+ - [CAGE-CONN-010](CAGE-CONN-010.md)
29
+ - [CAGE-CONN-011](CAGE-CONN-011.md)
30
+ - [CAGE-CONN-012](CAGE-CONN-012.md)
31
+ - [CAGE-CREATE-001](CAGE-CREATE-001.md)
32
+ - [CAGE-DECL-001](CAGE-DECL-001.md)
33
+ - [CAGE-DECL-002](CAGE-DECL-002.md)
34
+ - [CAGE-DECL-003](CAGE-DECL-003.md)
35
+ - [CAGE-DECL-004](CAGE-DECL-004.md)
36
+ - [CAGE-DEP-001](CAGE-DEP-001.md)
37
+ - [CAGE-DEP-002](CAGE-DEP-002.md)
38
+ - [CAGE-DEP-003](CAGE-DEP-003.md)
39
+ - [CAGE-DEP-004](CAGE-DEP-004.md)
40
+ - [CAGE-DEP-005](CAGE-DEP-005.md)
41
+ - [CAGE-DLQ-001](CAGE-DLQ-001.md)
42
+ - [CAGE-ENV-001](CAGE-ENV-001.md)
43
+ - [CAGE-EVENT-001](CAGE-EVENT-001.md)
44
+ - [CAGE-EVENT-002](CAGE-EVENT-002.md)
45
+ - [CAGE-FIELD-001](CAGE-FIELD-001.md)
46
+ - [CAGE-FIELD-002](CAGE-FIELD-002.md)
47
+ - [CAGE-FIELD-003](CAGE-FIELD-003.md)
48
+ - [CAGE-FIELD-004](CAGE-FIELD-004.md)
49
+ - [CAGE-GEN-001](CAGE-GEN-001.md)
50
+ - [CAGE-GEN-002](CAGE-GEN-002.md)
51
+ - [CAGE-GRANT-001](CAGE-GRANT-001.md)
52
+ - [CAGE-GRANT-002](CAGE-GRANT-002.md)
53
+ - [CAGE-GRANT-003](CAGE-GRANT-003.md)
54
+ - [CAGE-IMPACT-001](CAGE-IMPACT-001.md)
55
+ - [CAGE-JOB-001](CAGE-JOB-001.md)
56
+ - [CAGE-JOB-002](CAGE-JOB-002.md)
57
+ - [CAGE-JOB-003](CAGE-JOB-003.md)
58
+ - [CAGE-LINT-001](CAGE-LINT-001.md)
59
+ - [CAGE-MIG-001](CAGE-MIG-001.md)
60
+ - [CAGE-MIG-002](CAGE-MIG-002.md)
61
+ - [CAGE-MIG-003](CAGE-MIG-003.md)
62
+ - [CAGE-MIG-004](CAGE-MIG-004.md)
63
+ - [CAGE-MIG-005](CAGE-MIG-005.md)
64
+ - [CAGE-NAME-001](CAGE-NAME-001.md)
65
+ - [CAGE-NAME-002](CAGE-NAME-002.md)
66
+ - [CAGE-NAME-003](CAGE-NAME-003.md)
67
+ - [CAGE-NAME-004](CAGE-NAME-004.md)
68
+ - [CAGE-NAME-005](CAGE-NAME-005.md)
69
+ - [CAGE-NAME-006](CAGE-NAME-006.md)
70
+ - [CAGE-ORG-001](CAGE-ORG-001.md)
71
+ - [CAGE-PAIR-002](CAGE-PAIR-002.md)
72
+ - [CAGE-QUERY-001](CAGE-QUERY-001.md)
73
+ - [CAGE-QUERY-002](CAGE-QUERY-002.md)
74
+ - [CAGE-QUERY-003](CAGE-QUERY-003.md)
75
+ - [CAGE-REACT-001](CAGE-REACT-001.md)
76
+ - [CAGE-REACT-002](CAGE-REACT-002.md)
77
+ - [CAGE-READS-001](CAGE-READS-001.md)
78
+ - [CAGE-REG-001](CAGE-REG-001.md)
79
+ - [CAGE-REG-002](CAGE-REG-002.md)
80
+ - [CAGE-REG-003](CAGE-REG-003.md)
81
+ - [CAGE-ROUTE-001](CAGE-ROUTE-001.md)
82
+ - [CAGE-SCOPE-001](CAGE-SCOPE-001.md)
83
+ - [CAGE-SCOPE-002](CAGE-SCOPE-002.md)
84
+ - [CAGE-SECRET-001](CAGE-SECRET-001.md)
85
+ - [CAGE-SECRET-002](CAGE-SECRET-002.md)
86
+ - [CAGE-SENS-001](CAGE-SENS-001.md)
87
+ - [CAGE-SQL-001](CAGE-SQL-001.md)
88
+ - [CAGE-SQL-002](CAGE-SQL-002.md)
89
+ - [CAGE-STATE-001](CAGE-STATE-001.md)
90
+ - [CAGE-STATE-002](CAGE-STATE-002.md)
91
+ - [CAGE-STATE-003](CAGE-STATE-003.md)
92
+ - [CAGE-STATE-004](CAGE-STATE-004.md)
93
+ - [CAGE-STATE-005](CAGE-STATE-005.md)
94
+ - [CAGE-STATE-010](CAGE-STATE-010.md)
95
+ - [CAGE-STATE-011](CAGE-STATE-011.md)
96
+ - [CAGE-SYNC-001](CAGE-SYNC-001.md)
97
+ - [CAGE-TEST-001](CAGE-TEST-001.md)
98
+ - [CAGE-UNSAFE-001](CAGE-UNSAFE-001.md)
99
+ - [CAGE-UPGRADE-001](CAGE-UPGRADE-001.md)
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.1.0",
4
+ "description": "cage 命令行:gen、check、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
+ "managed"
24
+ ],
25
+ "dependencies": {
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-testkit": "0.1.0",
35
+ "@yss123/cage-kernel": "0.1.0",
36
+ "@yss123/cage-lint": "0.1.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": "tsc -p tsconfig.json && tsc -p ui/tsconfig.json && node scripts/build-graph.mjs && node scripts/copy-assets.mjs",
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