@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,270 @@
1
+ // 抽取器:把声明变成一张本体图(节点 + 边),写到 .cage/ontology.json。规则检查、影响分析、测试生成都读这张图。
2
+ import { createHash } from 'node:crypto';
3
+ import { snake, stableStringify } from '@yss123/cage-kernel';
4
+ import { z } from 'zod';
5
+ const h = (v) => createHash('sha256').update(stableStringify(v)).digest('hex').slice(0, 12);
6
+ function jsonSchema(s) {
7
+ try {
8
+ return z.toJSONSchema(s, { unrepresentable: 'any', io: 'input' });
9
+ }
10
+ catch {
11
+ return null;
12
+ }
13
+ }
14
+ function fieldAttrs(f) {
15
+ return {
16
+ kind: f.kind,
17
+ sql: f.sql,
18
+ optional: f.isOptional,
19
+ sensitive: f.sensitiveKind ?? null,
20
+ ref: f.ref ?? null,
21
+ unique: !!f.isUnique,
22
+ hidden: !!f.isHidden,
23
+ description: f.description ?? null,
24
+ values: f.values ?? null,
25
+ shape: f.shape
26
+ ? Object.fromEntries(Object.entries(f.shape).map(([k, sf]) => [
27
+ k,
28
+ { kind: sf.kind, optional: sf.isOptional },
29
+ ]))
30
+ : null,
31
+ };
32
+ }
33
+ export function extract(reg, sites = [], unsafeCount = 0) {
34
+ const nodes = [];
35
+ const edges = [];
36
+ const siteOf = new Map(sites.map((s) => [s.exportName, s]));
37
+ const where = (v) => {
38
+ const n = reg.nameOf(v);
39
+ const s = n ? siteOf.get(n) : undefined;
40
+ return s ? { file: s.file, line: s.line } : {};
41
+ };
42
+ const textHash = (v) => {
43
+ const n = reg.nameOf(v);
44
+ const s = n ? siteOf.get(n) : undefined;
45
+ // Git 的 autocrlf 会改变检出文件的换行。源码哈希统一换行,避免没有业务改动
46
+ // 却把整张命令图都报成变化;字符串字面量的转义内容仍保留原样。
47
+ return s ? h(s.text.replace(/\r\n/g, '\n')) : null;
48
+ };
49
+ const push = (kind, id, attrs, at = {}) => nodes.push({ kind, id, hash: h({ kind, id, attrs }), ...at, attrs });
50
+ const aggOfField = new Map();
51
+ for (const a of reg.aggregates) {
52
+ push('aggregate', a.name, {
53
+ table: `${a.table.schema}.${a.table.name}`,
54
+ scope: { dept: a.scope.deptField ?? null, owner: a.scope.ownerField ?? null },
55
+ invariants: Object.keys(a.invariants),
56
+ invariantSrc: Object.fromEntries(Object.entries(a.invariants).map(([k, fn]) => [k, h(String(fn))])),
57
+ description: a.description ?? null,
58
+ defaultStates: a.states.values.join() === 'active,deleted',
59
+ }, where(a));
60
+ for (const [k, f] of Object.entries(a.fields)) {
61
+ push('field', `${a.name}.${k}`, fieldAttrs(f));
62
+ edges.push({ kind: 'field', from: a.name, to: `${a.name}.${k}` });
63
+ aggOfField.set(`${a.name}.${k}`, a);
64
+ if (f.ref)
65
+ edges.push({ kind: 'refs', from: `${a.name}.${k}`, to: f.ref });
66
+ }
67
+ for (const s of a.states.values) {
68
+ push('state', `${a.name}.${s}`, {
69
+ terminal: a.states.terminal.includes(s),
70
+ initial: a.states.initial === s,
71
+ });
72
+ }
73
+ push('capability', `${a.name}.read`, { kind: 'read' });
74
+ push('capability', `${a.name}.export`, { kind: 'export' });
75
+ }
76
+ for (const e of reg.events) {
77
+ push('event', e.name, { fields: Object.fromEntries(Object.entries(e.fields).map(([k, f]) => [k, fieldAttrs(f)])) }, where(e));
78
+ }
79
+ for (const c of reg.commands) {
80
+ const { cmd, capability } = c;
81
+ const agg = cmd.agg.name;
82
+ push('command', capability, {
83
+ from: cmd.from,
84
+ to: cmd.to,
85
+ invokedBy: cmd.invokedBy,
86
+ input: jsonSchema(cmd.input),
87
+ reads: Object.fromEntries(Object.entries(cmd.reads).map(([k, a]) => [k, a.name])),
88
+ emits: cmd.emits.map((e) => e.event.name),
89
+ customEmit: cmd.emits.filter((e) => e.map).map((e) => e.event.name),
90
+ constraints: cmd.constraints.map((k) => k.name),
91
+ src: textHash(cmd) ?? h(String(cmd.handler)),
92
+ domainCodes: sites.find((s) => s.exportName === c.exportName)?.domainCodes ?? [],
93
+ public: cmd.public,
94
+ }, where(cmd));
95
+ const froms = cmd.from === 'new' ? ['[new]'] : cmd.from;
96
+ for (const f of froms) {
97
+ edges.push({
98
+ kind: 'transition',
99
+ from: f === '[new]' ? `${agg}.[new]` : `${agg}.${f}`,
100
+ // to: null 是各允许起始状态上的自环,不能生成名为 null 的虚假状态。
101
+ to: `${agg}.${cmd.to ?? f}`,
102
+ via: capability,
103
+ });
104
+ }
105
+ for (const [alias, a] of Object.entries(cmd.reads))
106
+ edges.push({ kind: 'reads', from: capability, to: a.name, alias });
107
+ for (const spec of cmd.emits) {
108
+ edges.push({ kind: 'emits', from: capability, to: spec.event.name });
109
+ // 事件载荷用到了聚合的哪些字段(默认映射按同名字段)
110
+ if (!spec.map) {
111
+ for (const k of Object.keys(spec.event.fields)) {
112
+ if (k in cmd.agg.fields)
113
+ edges.push({ kind: 'uses', from: spec.event.name, to: `${agg}.${k}`, as: '事件载荷' });
114
+ }
115
+ }
116
+ }
117
+ for (const k of cmd.constraints) {
118
+ for (const f of k.fields ?? [])
119
+ edges.push({ kind: 'uses', from: capability, to: `${agg}.${f}`, as: `约束 ${k.name}` });
120
+ }
121
+ }
122
+ for (const { r, name } of reg.reactions) {
123
+ push('reaction', name, {
124
+ tx: r.tx,
125
+ acquires: r.acquires ?? null,
126
+ releases: r.releases ?? null,
127
+ event: r.event.name,
128
+ command: reg.capabilityOf(r.command),
129
+ src: h(String(r.map)),
130
+ }, where(r));
131
+ edges.push({ kind: 'triggers', from: r.event.name, to: name });
132
+ edges.push({
133
+ kind: 'targets',
134
+ from: name,
135
+ to: reg.capabilityOf(r.command),
136
+ acquires: r.acquires,
137
+ releases: r.releases,
138
+ });
139
+ }
140
+ for (const q of reg.queries) {
141
+ push('query', q.name, {
142
+ reads: q.reads.map((a) => a.name),
143
+ sql: q.sql ? h(q.sql) : null,
144
+ build: q.build ? h(String(q.build)) : null,
145
+ input: jsonSchema(q.input),
146
+ sqlText: q.sql ?? null,
147
+ }, where(q));
148
+ for (const a of q.reads) {
149
+ edges.push({ kind: 'queries', from: q.name, to: a.name });
150
+ const text = (q.sql ?? String(q.build ?? '')).toLowerCase();
151
+ for (const k of Object.keys(a.fields)) {
152
+ if (new RegExp(`\\b(${snake(k)}|${k.toLowerCase()})\\b`).test(text))
153
+ edges.push({ kind: 'uses', from: q.name, to: `${a.name}.${k}`, as: '查询' });
154
+ }
155
+ }
156
+ }
157
+ for (const { a, name } of reg.approvals) {
158
+ push('approval', name, {
159
+ process: a.process,
160
+ aggregate: a.agg.name,
161
+ start: a.start.name,
162
+ routable: a.routable,
163
+ onApproved: reg.capabilityOf(a.onApproved),
164
+ onRejected: reg.capabilityOf(a.onRejected),
165
+ cancelOn: a.cancelOn.map((e) => e.name),
166
+ }, where(a));
167
+ edges.push({ kind: 'triggers', from: a.start.name, to: name });
168
+ edges.push({ kind: 'binds', from: name, to: reg.capabilityOf(a.onApproved) });
169
+ edges.push({ kind: 'binds', from: name, to: reg.capabilityOf(a.onRejected) });
170
+ for (const f of a.routable)
171
+ edges.push({ kind: 'uses', from: name, to: `${a.agg.name}.${f}`, as: '可路由字段' });
172
+ }
173
+ for (const j of reg.jobs) {
174
+ push('job', j.name, {
175
+ cron: j.cron,
176
+ reads: j.reads.map((a) => a.name),
177
+ calls: j.calls.map((c) => reg.capabilityOf(c)),
178
+ src: h(String(j.run)),
179
+ }, where(j));
180
+ for (const a of j.reads)
181
+ edges.push({ kind: 'queries', from: j.name, to: a.name });
182
+ for (const c of j.calls)
183
+ edges.push({ kind: 'calls', from: j.name, to: reg.capabilityOf(c) });
184
+ }
185
+ for (const e of reg.extensions) {
186
+ const v = e.value;
187
+ if (e.kind === 'ROUTE') {
188
+ const binding = reg.approvalByProcess(v.process);
189
+ push('route', `route:${v.process}`, { process: v.process, nodes: v.nodes }, { ...(siteOf.get(e.name) ? { file: siteOf.get(e.name).file, line: siteOf.get(e.name).line } : {}) });
190
+ if (binding) {
191
+ edges.push({ kind: 'binds', from: `route:${v.process}`, to: binding.name });
192
+ for (const f of v.fieldsUsed)
193
+ edges.push({
194
+ kind: 'uses',
195
+ from: `route:${v.process}`,
196
+ to: `${binding.a.agg.name}.${f}`,
197
+ as: '路由条件',
198
+ });
199
+ }
200
+ }
201
+ else if (e.kind === 'CONNECTOR') {
202
+ push('connector', `connector:${v.name}`, {
203
+ hosts: v.hosts,
204
+ secret: v.secret ?? null,
205
+ operations: Object.fromEntries(Object.entries(v.operations).map(([k, o]) => [
206
+ k,
207
+ {
208
+ effect: o.effect,
209
+ method: o.method,
210
+ path: o.path,
211
+ request: jsonSchema(o.request),
212
+ response: jsonSchema(o.response),
213
+ },
214
+ ])),
215
+ }, siteOf.get(e.name) ? { file: siteOf.get(e.name).file, line: siteOf.get(e.name).line } : {});
216
+ }
217
+ else if (e.kind === 'OUTBOUND') {
218
+ const id = e.name;
219
+ push('outbound', id, {
220
+ event: v.event.name,
221
+ connector: v.op.connector.name,
222
+ operation: v.op.name,
223
+ onSuccess: v.onSuccess ? reg.capabilityOf(v.onSuccess.command) : null,
224
+ src: h(String(v.map)),
225
+ }, siteOf.get(e.name) ? { file: siteOf.get(e.name).file, line: siteOf.get(e.name).line } : {});
226
+ edges.push({ kind: 'triggers', from: v.event.name, to: id });
227
+ edges.push({ kind: 'targets', from: id, to: `connector:${v.op.connector.name}` });
228
+ if (v.onSuccess)
229
+ edges.push({ kind: 'targets', from: id, to: reg.capabilityOf(v.onSuccess.command) });
230
+ // 出站映射用到的事件字段 → 这些字段在聚合里的同名字段
231
+ const emitters = reg.commands.filter((c) => c.cmd.emits.some((s) => s.event === v.event));
232
+ for (const f of v.fields ?? []) {
233
+ for (const c of emitters)
234
+ if (f in c.cmd.agg.fields)
235
+ edges.push({ kind: 'uses', from: id, to: `${c.cmd.agg.name}.${f}`, as: '出站映射' });
236
+ }
237
+ }
238
+ else if (e.kind === 'INBOUND') {
239
+ const id = e.name;
240
+ push('inbound', id, {
241
+ connector: v.connector.name,
242
+ event: v.event,
243
+ command: reg.capabilityOf(v.command),
244
+ payload: jsonSchema(v.payload),
245
+ }, siteOf.get(e.name) ? { file: siteOf.get(e.name).file, line: siteOf.get(e.name).line } : {});
246
+ edges.push({ kind: 'targets', from: id, to: reg.capabilityOf(v.command) });
247
+ }
248
+ }
249
+ nodes.sort((a, b) => a.id.localeCompare(b.id) || a.kind.localeCompare(b.kind));
250
+ return { version: 1, nodes, edges, unsafeCount };
251
+ }
252
+ export function diffOntology(base, head) {
253
+ const key = (n) => `${n.kind}:${n.id}`;
254
+ const b = new Map(base.nodes.map((n) => [key(n), n]));
255
+ const hd = new Map(head.nodes.map((n) => [key(n), n]));
256
+ const out = { added: [], removed: [], changed: [] };
257
+ for (const [k, n] of hd) {
258
+ const old = b.get(k);
259
+ if (!old)
260
+ out.added.push(n);
261
+ else if (old.hash !== n.hash)
262
+ out.changed.push({ before: old, after: n });
263
+ }
264
+ for (const [k, n] of b)
265
+ if (!hd.has(k))
266
+ out.removed.push(n);
267
+ return out;
268
+ }
269
+ export const nodeById = (g) => new Map(g.nodes.map((n) => [n.id, n]));
270
+ //# sourceMappingURL=ontology.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ontology.js","sourceRoot":"","sources":["../src/ontology.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { type ChildProcess } from 'node:child_process';
2
+ export declare function binPath(pkg: string, bin?: string): string;
3
+ export declare function launch(file: string, args: string[], cwd: string, env?: NodeJS.ProcessEnv): ChildProcess;
4
+ export declare function run(file: string, args: string[], cwd: string, env?: NodeJS.ProcessEnv): Promise<number>;
5
+ /** 升级时安装更新后的清单。这里不接收任意 shell 字符串,参数固定为 install。 */
6
+ export declare function installDependencies(cwd: string): Promise<number>;
@@ -0,0 +1,39 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { dirname, join } from 'node:path';
4
+ import { existsSync, readFileSync } from 'node:fs';
5
+ export function binPath(pkg, bin) {
6
+ // 使用 ESM 解析条件,dependency-cruiser 等纯 ESM 包没有 require 入口。
7
+ let dir = dirname(fileURLToPath(import.meta.resolve(pkg)));
8
+ while (!existsSync(join(dir, 'package.json')) ||
9
+ JSON.parse(readFileSync(join(dir, 'package.json'), 'utf8')).name !== pkg) {
10
+ const parent = dirname(dir);
11
+ if (parent === dir)
12
+ throw new Error(`找不到 ${pkg} 的命令入口`);
13
+ dir = parent;
14
+ }
15
+ const p = JSON.parse(readFileSync(join(dir, 'package.json'), 'utf8'));
16
+ return join(dir, typeof p.bin === 'string' ? p.bin : p.bin[bin ?? Object.keys(p.bin)[0]]);
17
+ }
18
+ export function launch(file, args, cwd, env = process.env) {
19
+ return spawn(process.execPath, [file, ...args], { cwd, env, stdio: 'inherit', windowsHide: true });
20
+ }
21
+ export async function run(file, args, cwd, env = process.env) {
22
+ const child = launch(file, args, cwd, env);
23
+ return new Promise((resolve, reject) => {
24
+ child.once('error', reject);
25
+ child.once('exit', (code) => resolve(code ?? 1));
26
+ });
27
+ }
28
+ /** 升级时安装更新后的清单。这里不接收任意 shell 字符串,参数固定为 install。 */
29
+ export async function installDependencies(cwd) {
30
+ const pnpm = process.env.npm_execpath;
31
+ if (pnpm && /pnpm/i.test(pnpm))
32
+ return run(pnpm, ['install'], cwd);
33
+ const child = spawn('pnpm', ['install'], { cwd, stdio: 'inherit', windowsHide: true, shell: process.platform === 'win32' });
34
+ return new Promise((resolve, reject) => {
35
+ child.once('error', reject);
36
+ child.once('exit', (code) => resolve(code ?? 1));
37
+ });
38
+ }
39
+ //# sourceMappingURL=process.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process.js","sourceRoot":"","sources":["../src/process.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import type { Finding } from './findings.js';
2
+ import type { Ontology } from './ontology.js';
3
+ /** 状态 → 进入时获得的资源:命令迁移到 S、发出事件、事件触发标注了 acquires 的反应 */
4
+ export declare function statesHoldingResources(g: Ontology): {
5
+ state: string;
6
+ resource: string;
7
+ via: string;
8
+ }[];
9
+ /** CAGE-PAIR-002:进入某状态时获得了资源,从该状态出发的每一条迁移都必须释放它,或进入一个同样持有它的状态 */
10
+ export declare function checkPairing(g: Ontology): Finding[];
11
+ /** CAGE-STATE-010:每个状态都能从初始状态到达;CAGE-STATE-011:非终态必须有出边 */
12
+ export declare function checkStates(g: Ontology): Finding[];
13
+ /** CAGE-SENS-001:敏感字段不得原样进入事件载荷 */
14
+ export declare function checkSensitiveEvents(g: Ontology): Finding[];
15
+ /** CAGE-APPR-010:invokedBy 为 process 的命令必须有审批绑定或反应调用它,否则没有人能调用 */
16
+ export declare function checkProcessCommands(g: Ontology): Finding[];
17
+ /** CAGE-QUERY-003:手写 SQL 只能引用 reads 里聚合的安全视图 */
18
+ export declare function checkQueries(g: Ontology): Finding[];
19
+ /** CAGE-ORG-001:domain 必须包含框架自带的组织模型 */
20
+ export declare function checkOrg(g: Ontology): Finding[];
21
+ /** CAGE-EVENT-002:事件载荷只允许向后兼容的变更(只能新增可选字段) */
22
+ export declare function checkEventCompat(base: Ontology, head: Ontology): Finding[];
23
+ export declare function runRules(g: Ontology, base?: Ontology | null): Finding[];
package/dist/rules.js ADDED
@@ -0,0 +1,251 @@
1
+ const at = (n) => (n?.file ? `${n.file}:${n.line ?? 1}` : undefined);
2
+ function index(g) {
3
+ const byId = new Map(g.nodes.map((n) => [`${n.kind}:${n.id}`, n]));
4
+ const get = (kind, id) => byId.get(`${kind}:${id}`);
5
+ const out = (kind, from) => g.edges.filter((e) => e.kind === kind && e.from === from);
6
+ const into = (kind, to) => g.edges.filter((e) => e.kind === kind && e.to === to);
7
+ return { get, out, into };
8
+ }
9
+ /** 状态 → 进入时获得的资源:命令迁移到 S、发出事件、事件触发标注了 acquires 的反应 */
10
+ export function statesHoldingResources(g) {
11
+ const { out } = index(g);
12
+ const held = [];
13
+ for (const t of g.edges.filter((e) => e.kind === 'transition')) {
14
+ for (const ev of out('emits', t.via)) {
15
+ for (const tr of out('triggers', ev.to)) {
16
+ for (const tg of out('targets', tr.to)) {
17
+ if (tg.acquires && !held.some((h) => h.state === t.to && h.resource === tg.acquires))
18
+ held.push({ state: t.to, resource: tg.acquires, via: t.via });
19
+ }
20
+ }
21
+ }
22
+ }
23
+ return held;
24
+ }
25
+ function releasesOnPath(g, via, resource) {
26
+ const { out } = index(g);
27
+ for (const ev of out('emits', via)) {
28
+ for (const tr of out('triggers', ev.to)) {
29
+ if (out('targets', tr.to).some((tg) => tg.releases === resource))
30
+ return true;
31
+ }
32
+ }
33
+ return false;
34
+ }
35
+ /** CAGE-PAIR-002:进入某状态时获得了资源,从该状态出发的每一条迁移都必须释放它,或进入一个同样持有它的状态 */
36
+ export function checkPairing(g) {
37
+ const { get } = index(g);
38
+ const findings = [];
39
+ const held = statesHoldingResources(g);
40
+ const holds = (state, resource) => held.some((h) => h.state === state && h.resource === resource);
41
+ for (const h of held) {
42
+ for (const t of g.edges.filter((e) => e.kind === 'transition' && e.from === h.state && e.to !== h.state)) {
43
+ if (!releasesOnPath(g, t.via, h.resource) && !holds(t.to, h.resource)) {
44
+ findings.push({
45
+ code: 'CAGE-PAIR-002',
46
+ at: at(get('command', t.via)),
47
+ reason: `${t.via} 让单据离开 ${h.state},但没有释放 ${h.resource}`,
48
+ fix: `新增订阅 ${t.via} 所发事件的反应,并标注 releases: '${h.resource}'`,
49
+ });
50
+ }
51
+ }
52
+ }
53
+ return findings;
54
+ }
55
+ /** CAGE-STATE-010:每个状态都能从初始状态到达;CAGE-STATE-011:非终态必须有出边 */
56
+ export function checkStates(g) {
57
+ const { get } = index(g);
58
+ const findings = [];
59
+ for (const a of g.nodes.filter((n) => n.kind === 'aggregate')) {
60
+ const states = g.nodes.filter((n) => n.kind === 'state' && n.id.startsWith(`${a.id}.`));
61
+ const trans = g.edges.filter((e) => e.kind === 'transition' && e.to.startsWith(`${a.id}.`));
62
+ const reached = new Set(trans.filter((t) => t.from === `${a.id}.[new]`).map((t) => t.to));
63
+ if (reached.size === 0) {
64
+ const init = states.find((s) => s.attrs.initial);
65
+ if (init)
66
+ reached.add(init.id);
67
+ }
68
+ let grew = true;
69
+ while (grew) {
70
+ grew = false;
71
+ for (const t of trans)
72
+ if (reached.has(t.from) && !reached.has(t.to)) {
73
+ reached.add(t.to);
74
+ grew = true;
75
+ }
76
+ }
77
+ const defaults = !!a.attrs.defaultStates;
78
+ for (const s of states) {
79
+ if (defaults && s.id.endsWith('.deleted'))
80
+ continue; // 默认生命周期的 deleted 由框架提供
81
+ if (!reached.has(s.id)) {
82
+ findings.push({
83
+ code: 'CAGE-STATE-010',
84
+ at: at(a),
85
+ reason: `状态 ${s.id} 从初始状态不可达`,
86
+ fix: '增加一个迁移到它的命令,或从 states 里删掉它',
87
+ });
88
+ }
89
+ const outs = trans.filter((t) => t.from === s.id);
90
+ if (!s.attrs.terminal && outs.length === 0 && !defaults) {
91
+ findings.push({
92
+ code: 'CAGE-STATE-011',
93
+ at: at(a),
94
+ reason: `非终态 ${s.id} 没有任何出边,单据会卡在这里`,
95
+ fix: '增加离开它的命令,或在 states 里把它标记为 terminal',
96
+ });
97
+ }
98
+ }
99
+ }
100
+ void get;
101
+ return findings;
102
+ }
103
+ /** CAGE-SENS-001:敏感字段不得原样进入事件载荷 */
104
+ export function checkSensitiveEvents(g) {
105
+ const { get, out } = index(g);
106
+ const findings = [];
107
+ for (const c of g.nodes.filter((n) => n.kind === 'command')) {
108
+ const agg = c.id.split('.')[0];
109
+ const custom = new Set(c.attrs.customEmit ?? []);
110
+ for (const e of out('emits', c.id)) {
111
+ const ev = get('event', e.to);
112
+ if (!ev)
113
+ continue;
114
+ for (const [k, f] of Object.entries((ev.attrs.fields ?? {}))) {
115
+ const af = get('field', `${agg}.${k}`);
116
+ if (af?.attrs.sensitive && !f.sensitive) {
117
+ findings.push({
118
+ code: 'CAGE-SENS-001',
119
+ at: at(ev),
120
+ reason: `事件 ${ev.id} 的载荷字段 ${k}${custom.has(ev.id) ? '(自定义映射)' : ''} 对应敏感字段 ${agg}.${k},会原样进入 outbox 和下游系统`,
121
+ fix: `在事件声明里把 ${k} 标成 .sensitive('${af.attrs.sensitive}')(载荷里自动掩码),或从载荷里去掉它`,
122
+ });
123
+ }
124
+ }
125
+ }
126
+ }
127
+ return findings;
128
+ }
129
+ /** CAGE-APPR-010:invokedBy 为 process 的命令必须有审批绑定或反应调用它,否则没有人能调用 */
130
+ export function checkProcessCommands(g) {
131
+ const { into } = index(g);
132
+ const findings = [];
133
+ for (const c of g.nodes.filter((n) => n.kind === 'command')) {
134
+ const by = c.attrs.invokedBy;
135
+ const callers = [...into('binds', c.id), ...into('targets', c.id), ...into('calls', c.id)];
136
+ if (by.includes('process') && !by.includes('user') && callers.length === 0) {
137
+ findings.push({
138
+ code: 'CAGE-APPR-010',
139
+ at: at(c),
140
+ reason: `命令 ${c.id} 只接受流程调用,但没有审批绑定或反应调用它`,
141
+ fix: '用 approval(...) 把它绑定为 onApproved/onRejected,或让一个反应调用它;也可能是 invokedBy 写错了',
142
+ });
143
+ }
144
+ if (by.includes('external') && !by.includes('user') && callers.length === 0) {
145
+ findings.push({
146
+ code: 'CAGE-CONN-012',
147
+ at: at(c),
148
+ reason: `命令 ${c.id} 只接受外部调用,但没有入站回调或出站映射调用它`,
149
+ fix: '用 inbound(...) 或 outbound(..., { onSuccess }) 调用它',
150
+ severity: 'warning',
151
+ });
152
+ }
153
+ }
154
+ return findings;
155
+ }
156
+ /** CAGE-QUERY-003:手写 SQL 只能引用 reads 里聚合的安全视图 */
157
+ export function checkQueries(g) {
158
+ const { get } = index(g);
159
+ const findings = [];
160
+ for (const q of g.nodes.filter((n) => n.kind === 'query')) {
161
+ const text = q.attrs.sqlText;
162
+ if (!text)
163
+ continue;
164
+ const allowed = new Set((q.attrs.reads ?? []).map((a) => String(get('aggregate', a)?.attrs.table ?? '').split('.')[1]));
165
+ for (const m of text.matchAll(/\bsafe\.("?)([a-z_][a-z0-9_]*)\1/gi)) {
166
+ if (!allowed.has(m[2])) {
167
+ findings.push({
168
+ code: 'CAGE-QUERY-003',
169
+ at: at(q),
170
+ reason: `查询 ${q.id} 引用了 safe.${m[2]},但 reads 里没有声明对应的聚合`,
171
+ fix: `在 reads 里加上 safe.${m[2]} 对应的聚合,影响分析才能找到这个查询`,
172
+ });
173
+ }
174
+ }
175
+ if (/\b(from|join)\s+(?!safe\.|\(|lateral\b|unnest\b|generate_series\b|jsonb_|json_)("?[a-z_][a-z0-9_]*"?)\s*(\.|\b)/i.test(text.replace(/--.*$/gm, ''))) {
176
+ const m = /\b(from|join)\s+(?!safe\.|\(|lateral\b|unnest\b|generate_series\b|jsonb_|json_)("?[a-z_][a-z0-9_.]*"?)/i.exec(text);
177
+ if (m && m[2].includes('.'))
178
+ findings.push({
179
+ code: 'CAGE-QUERY-003',
180
+ at: at(q),
181
+ reason: `查询 ${q.id} 引用了 ${m[2]},只允许引用 safe.* 安全视图`,
182
+ fix: '改为查询对应的安全视图',
183
+ });
184
+ }
185
+ }
186
+ return findings;
187
+ }
188
+ /** CAGE-ORG-001:domain 必须包含框架自带的组织模型 */
189
+ export function checkOrg(g) {
190
+ const has = (id) => g.nodes.some((n) => n.kind === 'aggregate' && n.id === id);
191
+ return has('User') && has('Dept') && has('Role')
192
+ ? []
193
+ : [
194
+ {
195
+ code: 'CAGE-ORG-001',
196
+ reason: 'domain 没有导出组织模型(User、Dept、Role)',
197
+ fix: "在 domain 的 index.ts 里加上 export * from '@yss123/cage-admin/domain'",
198
+ },
199
+ ];
200
+ }
201
+ /** CAGE-EVENT-002:事件载荷只允许向后兼容的变更(只能新增可选字段) */
202
+ export function checkEventCompat(base, head) {
203
+ const findings = [];
204
+ const b = new Map(base.nodes.filter((n) => n.kind === 'event').map((n) => [n.id, n]));
205
+ for (const ev of head.nodes.filter((n) => n.kind === 'event')) {
206
+ const old = b.get(ev.id);
207
+ if (!old)
208
+ continue;
209
+ const of = (old.attrs.fields ?? {});
210
+ const nf = (ev.attrs.fields ?? {});
211
+ for (const [k, f] of Object.entries(of)) {
212
+ if (!(k in nf))
213
+ findings.push({
214
+ code: 'CAGE-EVENT-002',
215
+ at: at(ev),
216
+ reason: `事件 ${ev.id} 删除了载荷字段 ${k},下游消费者会出错`,
217
+ fix: '保留旧字段(标注废弃),新增字段承载新含义;或新建一个事件',
218
+ });
219
+ else if (nf[k].kind !== f.kind) {
220
+ findings.push({
221
+ code: 'CAGE-EVENT-002',
222
+ at: at(ev),
223
+ reason: `事件 ${ev.id} 的字段 ${k} 类型从 ${f.kind} 变成了 ${nf[k].kind}`,
224
+ fix: '新增一个字段承载新类型,旧字段保留',
225
+ });
226
+ }
227
+ }
228
+ for (const [k, f] of Object.entries(nf)) {
229
+ if (!(k in of) && !f.optional)
230
+ findings.push({
231
+ code: 'CAGE-EVENT-002',
232
+ at: at(ev),
233
+ reason: `事件 ${ev.id} 新增了必填字段 ${k},已在 outbox 里的旧事件没有它`,
234
+ fix: `把 ${k} 声明为 .optional()`,
235
+ });
236
+ }
237
+ }
238
+ return findings;
239
+ }
240
+ export function runRules(g, base) {
241
+ return [
242
+ ...checkOrg(g),
243
+ ...checkStates(g),
244
+ ...checkPairing(g),
245
+ ...checkSensitiveEvents(g),
246
+ ...checkProcessCommands(g),
247
+ ...checkQueries(g),
248
+ ...(base ? checkEventCompat(base, g) : []),
249
+ ];
250
+ }
251
+ //# sourceMappingURL=rules.js.map