openxiangda-cli 2.0.0-alpha.16 → 2.0.0-alpha.162

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 (276) hide show
  1. package/README.md +51 -15
  2. package/bin/run.js +79 -1
  3. package/dist/base.d.ts +59 -5
  4. package/dist/base.d.ts.map +1 -1
  5. package/dist/base.js +213 -10
  6. package/dist/base.js.map +1 -1
  7. package/dist/commands/accept.d.ts +28 -0
  8. package/dist/commands/accept.d.ts.map +1 -0
  9. package/dist/commands/accept.js +21 -0
  10. package/dist/commands/accept.js.map +1 -0
  11. package/dist/commands/cancel.d.ts +19 -1
  12. package/dist/commands/cancel.d.ts.map +1 -1
  13. package/dist/commands/cancel.js +1 -1
  14. package/dist/commands/cancel.js.map +1 -1
  15. package/dist/commands/check.d.ts +22 -1
  16. package/dist/commands/check.d.ts.map +1 -1
  17. package/dist/commands/check.js +17 -4
  18. package/dist/commands/check.js.map +1 -1
  19. package/dist/commands/create.d.ts +39 -0
  20. package/dist/commands/create.d.ts.map +1 -0
  21. package/dist/commands/create.js +457 -0
  22. package/dist/commands/create.js.map +1 -0
  23. package/dist/commands/deploy.d.ts +26 -8
  24. package/dist/commands/deploy.d.ts.map +1 -1
  25. package/dist/commands/deploy.js +31 -17
  26. package/dist/commands/deploy.js.map +1 -1
  27. package/dist/commands/dev.d.ts +23 -1
  28. package/dist/commands/dev.d.ts.map +1 -1
  29. package/dist/commands/dev.js +28 -4
  30. package/dist/commands/dev.js.map +1 -1
  31. package/dist/commands/login.d.ts +29 -0
  32. package/dist/commands/login.d.ts.map +1 -0
  33. package/dist/commands/{auth/login.js → login.js} +27 -9
  34. package/dist/commands/login.js.map +1 -0
  35. package/dist/commands/logs.d.ts +22 -2
  36. package/dist/commands/logs.d.ts.map +1 -1
  37. package/dist/commands/logs.js +9 -5
  38. package/dist/commands/logs.js.map +1 -1
  39. package/dist/commands/retry.d.ts +19 -1
  40. package/dist/commands/retry.d.ts.map +1 -1
  41. package/dist/commands/retry.js +5 -2
  42. package/dist/commands/retry.js.map +1 -1
  43. package/dist/commands/rollback.d.ts +23 -4
  44. package/dist/commands/rollback.d.ts.map +1 -1
  45. package/dist/commands/rollback.js +18 -5
  46. package/dist/commands/rollback.js.map +1 -1
  47. package/dist/commands/skill.d.ts +31 -0
  48. package/dist/commands/skill.d.ts.map +1 -0
  49. package/dist/commands/skill.js +43 -0
  50. package/dist/commands/skill.js.map +1 -0
  51. package/dist/commands/spec.d.ts +39 -0
  52. package/dist/commands/spec.d.ts.map +1 -0
  53. package/dist/commands/spec.js +117 -0
  54. package/dist/commands/spec.js.map +1 -0
  55. package/dist/commands/start.d.ts +28 -0
  56. package/dist/commands/start.d.ts.map +1 -0
  57. package/dist/commands/start.js +18 -0
  58. package/dist/commands/start.js.map +1 -0
  59. package/dist/commands/status.d.ts +19 -1
  60. package/dist/commands/status.d.ts.map +1 -1
  61. package/dist/commands/status.js +1 -1
  62. package/dist/commands/status.js.map +1 -1
  63. package/dist/commands/stop.d.ts +28 -0
  64. package/dist/commands/stop.d.ts.map +1 -0
  65. package/dist/commands/stop.js +18 -0
  66. package/dist/commands/stop.js.map +1 -0
  67. package/dist/create-workspace.d.ts +67 -0
  68. package/dist/create-workspace.d.ts.map +1 -0
  69. package/dist/create-workspace.js +631 -0
  70. package/dist/create-workspace.js.map +1 -0
  71. package/dist/studio-events.d.ts +9 -0
  72. package/dist/studio-events.d.ts.map +1 -0
  73. package/dist/studio-events.js +30 -0
  74. package/dist/studio-events.js.map +1 -0
  75. package/dist/toolchain-capsule.d.ts +4 -0
  76. package/dist/toolchain-capsule.d.ts.map +1 -0
  77. package/dist/toolchain-capsule.js +116 -0
  78. package/dist/toolchain-capsule.js.map +1 -0
  79. package/package.json +16 -9
  80. package/template/.dockerignore +23 -0
  81. package/template/.env.example +3 -0
  82. package/template/AGENTS.md +47 -0
  83. package/template/README.md +65 -0
  84. package/template/_gitignore +14 -0
  85. package/template/apps/server/Dockerfile +20 -0
  86. package/template/apps/server/package.json +27 -0
  87. package/template/apps/server/src/app.module.ts +23 -0
  88. package/template/apps/server/src/main.ts +5 -0
  89. package/template/apps/server/test/smoke.test.ts +17 -0
  90. package/template/apps/server/tsconfig.json +9 -0
  91. package/template/apps/web/data-api-live.e2e.html +15 -0
  92. package/template/apps/web/e2e/client-fixture.ts +5 -0
  93. package/template/apps/web/e2e/data-api-live-fixture.tsx +162 -0
  94. package/template/apps/web/e2e/data-api-live.spec.ts +144 -0
  95. package/template/apps/web/e2e/field-protocol-fixture.tsx +350 -0
  96. package/template/apps/web/e2e/field-protocol.spec.ts +195 -0
  97. package/template/apps/web/e2e/resource-experience-fixture.tsx +446 -0
  98. package/template/apps/web/e2e/resources.spec.ts +638 -0
  99. package/template/apps/web/e2e/theme-contract-fixture.css +15 -0
  100. package/template/apps/web/e2e/workflow-experience-fixture.tsx +247 -0
  101. package/template/apps/web/e2e/workflow.spec.ts +1066 -0
  102. package/template/apps/web/field-protocol.e2e.html +15 -0
  103. package/template/apps/web/index.html +12 -0
  104. package/template/apps/web/package.json +34 -0
  105. package/template/apps/web/playwright.config.ts +47 -0
  106. package/template/apps/web/resource-experience.e2e.html +15 -0
  107. package/template/apps/web/scripts/check.mjs +43 -0
  108. package/template/apps/web/scripts/verify-build.mjs +6 -0
  109. package/template/apps/web/src/main.tsx +65 -0
  110. package/template/apps/web/src/user-end/tailwind.css +17 -0
  111. package/template/apps/web/test/contracts.test.ts +161 -0
  112. package/template/apps/web/test/loopback.test.ts +68 -0
  113. package/template/apps/web/tsconfig.json +12 -0
  114. package/template/apps/web/vite.config.ts +41 -0
  115. package/template/apps/web/workflow-experience.e2e.html +15 -0
  116. package/template/appspec/app.md +36 -0
  117. package/template/openxiangda.config.ts +77 -0
  118. package/template/package.json +29 -0
  119. package/template/packages/contracts/package.json +23 -0
  120. package/template/packages/contracts/src/generated.ts +265 -0
  121. package/template/packages/contracts/src/index.ts +1 -0
  122. package/template/packages/contracts/tsconfig.json +9 -0
  123. package/template/pnpm-workspace.yaml +7 -0
  124. package/template/scripts/verify-template-budget.mjs +49 -0
  125. package/template/tsconfig.base.json +13 -0
  126. package/dist/commands/app/create.d.ts +0 -15
  127. package/dist/commands/app/create.d.ts.map +0 -1
  128. package/dist/commands/app/create.js +0 -42
  129. package/dist/commands/app/create.js.map +0 -1
  130. package/dist/commands/app/info.d.ts +0 -9
  131. package/dist/commands/app/info.d.ts.map +0 -1
  132. package/dist/commands/app/info.js +0 -10
  133. package/dist/commands/app/info.js.map +0 -1
  134. package/dist/commands/app/link.d.ts +0 -10
  135. package/dist/commands/app/link.d.ts.map +0 -1
  136. package/dist/commands/app/link.js +0 -16
  137. package/dist/commands/app/link.js.map +0 -1
  138. package/dist/commands/app/provision.d.ts +0 -9
  139. package/dist/commands/app/provision.d.ts.map +0 -1
  140. package/dist/commands/app/provision.js +0 -10
  141. package/dist/commands/app/provision.js.map +0 -1
  142. package/dist/commands/auth/login.d.ts +0 -11
  143. package/dist/commands/auth/login.d.ts.map +0 -1
  144. package/dist/commands/auth/login.js.map +0 -1
  145. package/dist/commands/auth/logout.d.ts +0 -6
  146. package/dist/commands/auth/logout.d.ts.map +0 -1
  147. package/dist/commands/auth/logout.js +0 -30
  148. package/dist/commands/auth/logout.js.map +0 -1
  149. package/dist/commands/auth/status.d.ts +0 -6
  150. package/dist/commands/auth/status.d.ts.map +0 -1
  151. package/dist/commands/auth/status.js +0 -60
  152. package/dist/commands/auth/status.js.map +0 -1
  153. package/dist/commands/build.d.ts +0 -11
  154. package/dist/commands/build.d.ts.map +0 -1
  155. package/dist/commands/build.js +0 -23
  156. package/dist/commands/build.js.map +0 -1
  157. package/dist/commands/doctor.d.ts +0 -9
  158. package/dist/commands/doctor.d.ts.map +0 -1
  159. package/dist/commands/doctor.js +0 -7
  160. package/dist/commands/doctor.js.map +0 -1
  161. package/dist/commands/event/delivery/list.d.ts +0 -10
  162. package/dist/commands/event/delivery/list.d.ts.map +0 -1
  163. package/dist/commands/event/delivery/list.js +0 -14
  164. package/dist/commands/event/delivery/list.js.map +0 -1
  165. package/dist/commands/event/delivery/replay.d.ts +0 -13
  166. package/dist/commands/event/delivery/replay.d.ts.map +0 -1
  167. package/dist/commands/event/delivery/replay.js +0 -16
  168. package/dist/commands/event/delivery/replay.js.map +0 -1
  169. package/dist/commands/event/subscription/list.d.ts +0 -9
  170. package/dist/commands/event/subscription/list.d.ts.map +0 -1
  171. package/dist/commands/event/subscription/list.js +0 -10
  172. package/dist/commands/event/subscription/list.js.map +0 -1
  173. package/dist/commands/event/subscription/rotate-secret.d.ts +0 -15
  174. package/dist/commands/event/subscription/rotate-secret.d.ts.map +0 -1
  175. package/dist/commands/event/subscription/rotate-secret.js +0 -33
  176. package/dist/commands/event/subscription/rotate-secret.js.map +0 -1
  177. package/dist/commands/event/subscription/status.d.ts +0 -14
  178. package/dist/commands/event/subscription/status.d.ts.map +0 -1
  179. package/dist/commands/event/subscription/status.js +0 -19
  180. package/dist/commands/event/subscription/status.js.map +0 -1
  181. package/dist/commands/event/timer/list.d.ts +0 -9
  182. package/dist/commands/event/timer/list.d.ts.map +0 -1
  183. package/dist/commands/event/timer/list.js +0 -10
  184. package/dist/commands/event/timer/list.js.map +0 -1
  185. package/dist/commands/event/timer/status.d.ts +0 -14
  186. package/dist/commands/event/timer/status.d.ts.map +0 -1
  187. package/dist/commands/event/timer/status.js +0 -19
  188. package/dist/commands/event/timer/status.js.map +0 -1
  189. package/dist/commands/generate.d.ts +0 -10
  190. package/dist/commands/generate.d.ts.map +0 -1
  191. package/dist/commands/generate.js +0 -8
  192. package/dist/commands/generate.js.map +0 -1
  193. package/dist/commands/oauth/audit/list.d.ts +0 -12
  194. package/dist/commands/oauth/audit/list.d.ts.map +0 -1
  195. package/dist/commands/oauth/audit/list.js +0 -20
  196. package/dist/commands/oauth/audit/list.js.map +0 -1
  197. package/dist/commands/oauth/client/create.d.ts +0 -13
  198. package/dist/commands/oauth/client/create.d.ts.map +0 -1
  199. package/dist/commands/oauth/client/create.js +0 -34
  200. package/dist/commands/oauth/client/create.js.map +0 -1
  201. package/dist/commands/oauth/client/list.d.ts +0 -9
  202. package/dist/commands/oauth/client/list.d.ts.map +0 -1
  203. package/dist/commands/oauth/client/list.js +0 -10
  204. package/dist/commands/oauth/client/list.js.map +0 -1
  205. package/dist/commands/oauth/client/revoke.d.ts +0 -12
  206. package/dist/commands/oauth/client/revoke.d.ts.map +0 -1
  207. package/dist/commands/oauth/client/revoke.js +0 -12
  208. package/dist/commands/oauth/client/revoke.js.map +0 -1
  209. package/dist/commands/oauth/client/rotate.d.ts +0 -13
  210. package/dist/commands/oauth/client/rotate.d.ts.map +0 -1
  211. package/dist/commands/oauth/client/rotate.js +0 -20
  212. package/dist/commands/oauth/client/rotate.js.map +0 -1
  213. package/dist/commands/oauth/client/update.d.ts +0 -15
  214. package/dist/commands/oauth/client/update.d.ts.map +0 -1
  215. package/dist/commands/oauth/client/update.js +0 -23
  216. package/dist/commands/oauth/client/update.js.map +0 -1
  217. package/dist/commands/oauth/runtime/rotate.d.ts +0 -12
  218. package/dist/commands/oauth/runtime/rotate.d.ts.map +0 -1
  219. package/dist/commands/oauth/runtime/rotate.js +0 -31
  220. package/dist/commands/oauth/runtime/rotate.js.map +0 -1
  221. package/dist/commands/oauth/runtime/status.d.ts +0 -10
  222. package/dist/commands/oauth/runtime/status.d.ts.map +0 -1
  223. package/dist/commands/oauth/runtime/status.js +0 -17
  224. package/dist/commands/oauth/runtime/status.js.map +0 -1
  225. package/dist/commands/promote.d.ts +0 -13
  226. package/dist/commands/promote.d.ts.map +0 -1
  227. package/dist/commands/promote.js +0 -9
  228. package/dist/commands/promote.js.map +0 -1
  229. package/dist/commands/secret/audit/list.d.ts +0 -14
  230. package/dist/commands/secret/audit/list.d.ts.map +0 -1
  231. package/dist/commands/secret/audit/list.js +0 -16
  232. package/dist/commands/secret/audit/list.js.map +0 -1
  233. package/dist/commands/secret/create.d.ts +0 -18
  234. package/dist/commands/secret/create.d.ts.map +0 -1
  235. package/dist/commands/secret/create.js +0 -33
  236. package/dist/commands/secret/create.js.map +0 -1
  237. package/dist/commands/secret/delete.d.ts +0 -15
  238. package/dist/commands/secret/delete.d.ts.map +0 -1
  239. package/dist/commands/secret/delete.js +0 -20
  240. package/dist/commands/secret/delete.js.map +0 -1
  241. package/dist/commands/secret/list.d.ts +0 -10
  242. package/dist/commands/secret/list.d.ts.map +0 -1
  243. package/dist/commands/secret/list.js +0 -14
  244. package/dist/commands/secret/list.js.map +0 -1
  245. package/dist/commands/secret/rotate.d.ts +0 -18
  246. package/dist/commands/secret/rotate.d.ts.map +0 -1
  247. package/dist/commands/secret/rotate.js +0 -30
  248. package/dist/commands/secret/rotate.js.map +0 -1
  249. package/dist/commands/secret/update.d.ts +0 -17
  250. package/dist/commands/secret/update.d.ts.map +0 -1
  251. package/dist/commands/secret/update.js +0 -37
  252. package/dist/commands/secret/update.js.map +0 -1
  253. package/dist/commands/skill/install.d.ts +0 -11
  254. package/dist/commands/skill/install.d.ts.map +0 -1
  255. package/dist/commands/skill/install.js +0 -52
  256. package/dist/commands/skill/install.js.map +0 -1
  257. package/dist/commands/skill/validate.d.ts +0 -9
  258. package/dist/commands/skill/validate.d.ts.map +0 -1
  259. package/dist/commands/skill/validate.js +0 -32
  260. package/dist/commands/skill/validate.js.map +0 -1
  261. package/dist/commands/test.d.ts +0 -9
  262. package/dist/commands/test.d.ts.map +0 -1
  263. package/dist/commands/test.js +0 -7
  264. package/dist/commands/test.js.map +0 -1
  265. package/dist/commands/workflow/provider/list.d.ts +0 -10
  266. package/dist/commands/workflow/provider/list.d.ts.map +0 -1
  267. package/dist/commands/workflow/provider/list.js +0 -14
  268. package/dist/commands/workflow/provider/list.js.map +0 -1
  269. package/dist/commands/workflow/provider/rotate.d.ts +0 -15
  270. package/dist/commands/workflow/provider/rotate.d.ts.map +0 -1
  271. package/dist/commands/workflow/provider/rotate.js +0 -24
  272. package/dist/commands/workflow/provider/rotate.js.map +0 -1
  273. package/dist/secret-value.d.ts +0 -5
  274. package/dist/secret-value.d.ts.map +0 -1
  275. package/dist/secret-value.js +0 -15
  276. package/dist/secret-value.js.map +0 -1
@@ -0,0 +1,9 @@
1
+ import { type StudioCliEvent, type StudioCliEventType } from "openxiangda-contracts";
2
+ export declare class StudioCliEventStream {
3
+ readonly runId: string;
4
+ private readonly write;
5
+ private sequence;
6
+ constructor(runId: string, write?: (event: StudioCliEvent) => void);
7
+ emit(type: StudioCliEventType, payload: Record<string, unknown>): StudioCliEvent;
8
+ }
9
+ //# sourceMappingURL=studio-events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"studio-events.d.ts","sourceRoot":"","sources":["../src/studio-events.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACxB,MAAM,uBAAuB,CAAC;AAE/B,qBAAa,oBAAoB;IAI7B,QAAQ,CAAC,KAAK,EAAE,MAAM;IACtB,OAAO,CAAC,QAAQ,CAAC,KAAK;IAJxB,OAAO,CAAC,QAAQ,CAAK;gBAGV,KAAK,EAAE,MAAM,EACL,KAAK,GAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAElD;IAUH,IAAI,CAAC,IAAI,EAAE,kBAAkB,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAahE"}
@@ -0,0 +1,30 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { STUDIO_CLI_EVENT_SCHEMA_VERSION, } from "openxiangda-contracts";
3
+ export class StudioCliEventStream {
4
+ runId;
5
+ write;
6
+ sequence = 0;
7
+ constructor(runId, write = event => {
8
+ process.stdout.write(`${JSON.stringify(event)}\n`);
9
+ }) {
10
+ this.runId = runId;
11
+ this.write = write;
12
+ if (!runId || runId.length > 256) {
13
+ throw Object.assign(new Error("STUDIO_RUN_ID_INVALID: runId 必须为 1 到 256 个字符"), { code: "STUDIO_RUN_ID_INVALID", retryable: false });
14
+ }
15
+ }
16
+ emit(type, payload) {
17
+ const event = {
18
+ schemaVersion: STUDIO_CLI_EVENT_SCHEMA_VERSION,
19
+ eventId: randomUUID(),
20
+ runId: this.runId,
21
+ seq: ++this.sequence,
22
+ type,
23
+ timestamp: new Date().toISOString(),
24
+ payload,
25
+ };
26
+ this.write(event);
27
+ return event;
28
+ }
29
+ }
30
+ //# sourceMappingURL=studio-events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"studio-events.js","sourceRoot":"","sources":["../src/studio-events.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EACL,+BAA+B,GAGhC,MAAM,uBAAuB,CAAC;AAE/B,MAAM,OAAO,oBAAoB;IAIpB;IACQ;IAJX,QAAQ,GAAG,CAAC,CAAC;IAErB,YACW,KAAa,EACL,QAAyC,KAAK,CAAC,EAAE;QAChE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACrD,CAAC;QAHQ,UAAK,GAAL,KAAK,CAAQ;QACL,UAAK,GAAL,KAAK,CAErB;QAED,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;YACjC,MAAM,MAAM,CAAC,MAAM,CACjB,IAAI,KAAK,CAAC,8CAA8C,CAAC,EACzD,EAAE,IAAI,EAAE,uBAAuB,EAAE,SAAS,EAAE,KAAK,EAAE,CACpD,CAAC;QACJ,CAAC;IACH,CAAC;IAED,IAAI,CAAC,IAAwB,EAAE,OAAgC;QAC7D,MAAM,KAAK,GAAmB;YAC5B,aAAa,EAAE,+BAA+B;YAC9C,OAAO,EAAE,UAAU,EAAE;YACrB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,GAAG,EAAE,EAAE,IAAI,CAAC,QAAQ;YACpB,IAAI;YACJ,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,OAAO;SACR,CAAC;QACF,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAClB,OAAO,KAAK,CAAC;IACf,CAAC;CACF"}
@@ -0,0 +1,4 @@
1
+ import { type ToolchainCapsule } from "openxiangda-devkit-core";
2
+ export declare function resolveCliToolchainCapsule(templateRoot?: string): ToolchainCapsule;
3
+ export declare function resolveDefaultTemplate(): string;
4
+ //# sourceMappingURL=toolchain-capsule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toolchain-capsule.d.ts","sourceRoot":"","sources":["../src/toolchain-capsule.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,gBAAgB,EACtB,MAAM,yBAAyB,CAAC;AAOjC,wBAAgB,0BAA0B,CACxC,YAAY,SAA2B,GACtC,gBAAgB,CAsBlB;AAED,wBAAgB,sBAAsB,WAIrC"}
@@ -0,0 +1,116 @@
1
+ import { createToolchainCapsule, isOpenXiangdaPackageName, TOOLCHAIN_CAPSULE_MAX_MANIFEST_BYTES, TOOLCHAIN_CAPSULE_MAX_PACKAGE_FILES, ToolchainCapsuleScanLimitError, } from "openxiangda-devkit-core";
2
+ import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
3
+ import { dirname, join, relative, resolve } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
6
+ export function resolveCliToolchainCapsule(templateRoot = resolveDefaultTemplate()) {
7
+ const localVersions = readLocalPackageVersions();
8
+ const versions = new Map();
9
+ for (const dependency of readTemplateDependencies(templateRoot)) {
10
+ const value = dependency.specifier.startsWith("workspace:")
11
+ ? localVersions.get(dependency.name)
12
+ : dependency.specifier;
13
+ if (!value || /[<>=*^~| ]/.test(value)) {
14
+ throw new Error(`OPENXIANGDA_TEMPLATE_CAPSULE_VERSION_UNRESOLVED: ${dependency.name}`);
15
+ }
16
+ const previous = versions.get(dependency.name);
17
+ if (previous && previous !== value) {
18
+ throw new Error(`OPENXIANGDA_TEMPLATE_CAPSULE_SPLIT: ${dependency.name}`);
19
+ }
20
+ versions.set(dependency.name, value);
21
+ }
22
+ return createToolchainCapsule(versions, "cli-template");
23
+ }
24
+ export function resolveDefaultTemplate() {
25
+ const repository = resolve(packageRoot, "../../templates/application");
26
+ if (existsSync(repository))
27
+ return repository;
28
+ return join(packageRoot, "template");
29
+ }
30
+ function readLocalPackageVersions() {
31
+ const packagesRoot = resolve(packageRoot, "..");
32
+ const versions = new Map();
33
+ const self = readManifest(join(packageRoot, "package.json"));
34
+ if (self &&
35
+ typeof self.name === "string" &&
36
+ typeof self.version === "string" &&
37
+ isOpenXiangdaPackageName(self.name)) {
38
+ versions.set(self.name, self.version);
39
+ }
40
+ for (const entry of readdirSync(packagesRoot, { withFileTypes: true }).sort((left, right) => left.name.localeCompare(right.name))) {
41
+ if (!entry.isDirectory())
42
+ continue;
43
+ const manifest = readManifest(join(packagesRoot, entry.name, "package.json"));
44
+ if (manifest &&
45
+ typeof manifest.name === "string" &&
46
+ typeof manifest.version === "string" &&
47
+ isOpenXiangdaPackageName(manifest.name)) {
48
+ versions.set(manifest.name, manifest.version);
49
+ }
50
+ }
51
+ return versions;
52
+ }
53
+ function readTemplateDependencies(root) {
54
+ const dependencies = [];
55
+ let packageFileCount = 0;
56
+ const visit = (directory) => {
57
+ for (const entry of readdirSync(directory, { withFileTypes: true }).sort((left, right) => left.name.localeCompare(right.name))) {
58
+ if (["node_modules", "dist", ".openxiangda"].includes(entry.name)) {
59
+ continue;
60
+ }
61
+ const path = join(directory, entry.name);
62
+ if (entry.isDirectory()) {
63
+ visit(path);
64
+ continue;
65
+ }
66
+ if (!entry.isFile() || entry.name !== "package.json")
67
+ continue;
68
+ packageFileCount += 1;
69
+ if (packageFileCount > TOOLCHAIN_CAPSULE_MAX_PACKAGE_FILES) {
70
+ throw new ToolchainCapsuleScanLimitError(`template package.json count exceeds ${TOOLCHAIN_CAPSULE_MAX_PACKAGE_FILES}`);
71
+ }
72
+ if (statSync(path).size > TOOLCHAIN_CAPSULE_MAX_MANIFEST_BYTES) {
73
+ throw new ToolchainCapsuleScanLimitError(`${relative(root, path)} exceeds ${TOOLCHAIN_CAPSULE_MAX_MANIFEST_BYTES} bytes`);
74
+ }
75
+ const manifest = readManifest(path);
76
+ if (!manifest)
77
+ continue;
78
+ for (const section of [
79
+ "dependencies",
80
+ "devDependencies",
81
+ "peerDependencies",
82
+ "optionalDependencies",
83
+ ]) {
84
+ const values = manifest[section];
85
+ if (!values || typeof values !== "object")
86
+ continue;
87
+ for (const [name, specifier] of Object.entries(values)) {
88
+ if (!isOpenXiangdaPackageName(name)) {
89
+ continue;
90
+ }
91
+ dependencies.push({
92
+ name,
93
+ specifier: String(specifier),
94
+ packageFile: relative(root, path).replaceAll("\\", "/"),
95
+ section,
96
+ });
97
+ }
98
+ }
99
+ }
100
+ };
101
+ visit(resolve(root));
102
+ return dependencies.sort((left, right) => left.name.localeCompare(right.name) ||
103
+ left.packageFile.localeCompare(right.packageFile) ||
104
+ left.section.localeCompare(right.section));
105
+ }
106
+ function readManifest(path) {
107
+ try {
108
+ return JSON.parse(readFileSync(path, "utf8"));
109
+ }
110
+ catch (error) {
111
+ if (error.code === "ENOENT")
112
+ return undefined;
113
+ throw error;
114
+ }
115
+ }
116
+ //# sourceMappingURL=toolchain-capsule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toolchain-capsule.js","sourceRoot":"","sources":["../src/toolchain-capsule.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,24 +1,30 @@
1
1
  {
2
2
  "name": "openxiangda-cli",
3
- "version": "2.0.0-alpha.16",
3
+ "version": "2.0.0-alpha.162",
4
4
  "description": "Thin application-level CLI for OpenXiangda 2.0.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
8
- "bin": {
9
- "openxiangda": "./bin/run.js"
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ },
13
+ "./run": "./bin/run.js",
14
+ "./package.json": "./package.json"
10
15
  },
11
16
  "files": [
12
17
  "bin/",
13
18
  "dist/",
19
+ "template/",
14
20
  "README.md"
15
21
  ],
16
22
  "dependencies": {
17
23
  "@oclif/core": "4.13.3",
18
- "openxiangda-contracts": "2.0.0-alpha.12",
19
- "openxiangda-devkit-core": "2.0.0-alpha.13",
20
- "create-openxiangda": "2.0.0-alpha.14",
21
- "openxiangda-skill-kit": "2.0.0-alpha.15"
24
+ "openxiangda-contracts": "2.0.0-alpha.82",
25
+ "openxiangda-devkit-core": "2.0.0-alpha.105",
26
+ "openxiangda-mcp": "2.0.0-alpha.105",
27
+ "openxiangda-skill-kit": "2.0.0-alpha.128"
22
28
  },
23
29
  "devDependencies": {
24
30
  "tsx": "4.23.12",
@@ -35,8 +41,9 @@
35
41
  },
36
42
  "license": "MIT",
37
43
  "scripts": {
38
- "build": "tsc -p tsconfig.json",
44
+ "build": "node ../../scripts/prune-package-dist.mjs && tsc -p tsconfig.json",
45
+ "build:release": "node ../../scripts/prune-package-dist.mjs && pnpm build",
39
46
  "check": "tsc -p tsconfig.json --noEmit",
40
- "test": "tsx --test test/*.test.ts"
47
+ "test": "node scripts/prepare-template.mjs && tsx --test test/*.test.ts && node ../../scripts/verify-cli-blackbox.mjs"
41
48
  }
42
49
  }
@@ -0,0 +1,23 @@
1
+ node_modules
2
+ **/node_modules
3
+ dist
4
+ **/dist
5
+ coverage
6
+ **/coverage
7
+ playwright-report
8
+ **/playwright-report
9
+ test-results
10
+ **/test-results
11
+ .openxiangda
12
+ **/.openxiangda
13
+ .turbo
14
+ **/.turbo
15
+ .turbopack
16
+ **/.turbopack
17
+ .umi
18
+ **/.umi
19
+ .umi-production
20
+ **/.umi-production
21
+ .git
22
+ *.log
23
+ **/*.log
@@ -0,0 +1,3 @@
1
+ # openxiangda dev injects these values. Do not put platform tokens in this file.
2
+ OPENXIANGDA_APP_CODE=instrument-center
3
+ OPENXIANGDA_DEV_HOST=127.0.0.1
@@ -0,0 +1,47 @@
1
+ # OpenXiangda 2.0 Application Agent Contract
2
+
3
+ - Use only the workspace-pinned CLI: `pnpm openxiangda <command>`. Never invoke a bare global `openxiangda` inside a 2.0 task.
4
+ - `appspec/` is the optional OpenXiangda 2.0 business-intent layer. Before changing observable behavior, read the bounded index with `pnpm openxiangda spec context --json`, then select only the relevant stable ID; use no ChangeSpec for L0 work, one short ChangeSpec for L1, and add permission/rollback/concurrency detail only for L2/L3. Before close, the user—not AI—confirms `currentSpec=merged` or `not-applicable`. AppSpec is advisory and never a release gate. Never read, import or migrate 1.x `openspec/` or SDD.
5
+ - Use Vite, React Router, Refine Core and Ant Design. Do not add Umi, ProComponents or another admin shell.
6
+ - The platform `openxiangda/react` owns the only admin `ConfigProvider` and the
7
+ `light`/`dark`/`system` appearance preference. Admin pages use Ant Design's
8
+ `defaultAlgorithm`/`darkAlgorithm`, `theme.useToken()`, or generated
9
+ `--oxa-antd-*` CSS variables. Do not add a nested theme provider, theme
10
+ store, palette editor, `--oxa-color-*`/`--oxa-shell-*` aliases, or fixed
11
+ white/black/neutral structural colors. Future palettes are centralized
12
+ platform seed configurations; alpha contracts are replaced directly without
13
+ compatibility aliases. User-end pages are outside this admin visual contract
14
+ and may use Tailwind CSS and their own product design tokens/components, but
15
+ must not mutate the admin provider or Seed.
16
+ - Use the complete Ant Design Seed/Map/Alias/Component model on admin pages:
17
+ platform-owned Seed values feed the selected algorithm; admin code consumes
18
+ generated Alias values for colors, spacing, typography, control dimensions,
19
+ motion, shadows, z-index and breakpoints. Never hand-write Map values or
20
+ introduce an admin token registry. Component tokens are only for
21
+ platform-approved non-color dimensions and typography.
22
+ - The template includes Tailwind CSS v4 for user-end pages. Keep its `@theme`
23
+ and utility classes in the user-end layer, omit Tailwind preflight from the
24
+ admin shell, and do not make user-end utilities depend on `--oxa-antd-*`.
25
+ - Bind every generated `appRoutes` entry to its local page with `defineApplicationContributions`; desktop `admin` routes stay inside the platform Shell, while `user` routes render without an admin Shell for independent mobile/user experiences. Generated resource CRUD routes are compiler-owned under `/admin/resources/<resourceCode>...` and `/m/admin/resources/<resourceCode>...`; never recreate root resource paths, aliases or redirects. Explicit routes that have the same canonical shape as another explicit or generated route fail compilation, even when dynamic parameter names differ. Use only the typed `toolbar`, `row` and `detail` resource slots for generated resource actions. Declare the complete editable admin menu with `defineAdminNavigation` and its page/group helpers; the Shell renders only generated `adminNavigation` references and permissions only filter them. Do not create another router, menu store, layout, identity provider, permission store or copied CRUD page; route/action access uses capability or `allOf`/`anyOf`, while Data/App API and Workflow authorization remain server-owned.
26
+ - Application login is optional `frontend.authentication`: existing platform users only, registration rejected, exact desktop `/login` and mobile `/m/login`. Bind generated `authenticationSurfaces` to separate PC/mobile renderers through `defineApplicationContributions`; renderers own only brand visuals and call `ApplicationLoginSurfaceProps`. The platform alone owns passwords, providers, OAuth state/callbacks, secure cookies, current identity and authorization. Never put login in protected `appRoutes`, call a v1 auth route, store tokens, create users/roles, or add another Router/identity provider. Keep QA in generated `platformAuthManifest`, outside the protected route denominator.
27
+ - External users without platform accounts use only an exact static `surface: 'user'` route declared through `frontend.publicAccess`. Declare the one resource, bounded field sets, required operations, draft limits and named duplicate validations; consume only generated `anonymousPublicAccess` and `createAnonymousPublicClient`. `own.list`/`own.read` mean records submitted by the same platform-issued HttpOnly browser credential, not a verified natural person, and another browser or cleared cookie intentionally loses access. Never create a guest role/user, call the general Native Data API, expose an anonymous upload path, store identity locally or derive ownership from IP, user-agent or fingerprint.
28
+ - Declare each resource once in `openxiangda.config.ts` with only `code`, `name`, `fields` and optional `mutationOwner`, generated/list/layout/data-policy settings. Each field owns type, label, required state, Surface flags, reference/file metadata and access. Resource codes are lower kebab-case. Use `native` for direct Data API mutations, `action`, `readonly` or `workflow` for non-Native ownership; never grant or generate Native mutation for a non-Native owner.
29
+ - Never write resource-level `schemaVersion`, `appCode`, `schema`, `surface`, `capabilities`, `fieldPolicies` or `platform/data` modules. The compiler derives the strict DataResource, CRUD capabilities, Surface and AI Schema. The application manifest still starts with its one top-level `schemaVersion: 3`.
30
+ - Ordinary list/get/create/update/delete, filters, export and batch operations use the platform Native Data API. Do not create Function CRUD or NestJS wrappers.
31
+ - Add NestJS only for a named business action that needs a cross-resource transaction, an invariant or an external side effect.
32
+ - Every interactive business action binds `@OpenXiangdaOperation(operation)` and injects `OpenXiangdaBusinessDataApiService`, `OpenXiangdaBusinessNotificationService`, or `OpenXiangdaStandardOperations`. The platform checks the action capability once at App API ingress; the trusted backend then has full Data/managed business-notification access only to its exact application/environment while audit retains the initiating user and action. Do not author `authorizationJSON`, forward user tokens, grant ordinary users `app:notification2:send`, or reapply the user's resource, row and field permissions inside the action.
33
+ - A NestJS backend declares only `enabled`, `isolation: 'shared' | 'dedicated'` and `resourceProfile: 'light' | 'standard'`. Never put raw Kubernetes resources, replicas, ports or environment maps in application metadata; the platform owns capacity and scaling.
34
+ - Use the current logged-in user and the union of that user's application roles. An app for every logged-in platform user may declare one existing package role through `authz.authenticatedUserRoleCode`; the platform materializes it on first access and unions it with manual and business-projected roles. Do not fabricate a browser fallback role or use a business membership resource for this universal audience. An optional declared Perspective projects only read visibility (pages, rows and fields); create/update/delete, workflows and custom actions continue to authorize against the complete union. Standard Data API calls inherit `X-OpenXiangda-Perspective` automatically. Use `@CurrentPerspective()` only when custom Nest code reads outside the standard Data API, and apply an equivalent read projection explicitly. Business code must not persist a platform Token or authorization result and must not implement a second identity path.
35
+ - Fields inherit the resource read/create/update capabilities. Use field `access` only to tighten them; arrays are all-of and `false` is explicit deny. There is no `write` fallback.
36
+ - Field `type` is semantic, never a hand-authored database type. The supported catalog is exactly `text.short`, `text.long`, `text.rich`, `number.integer`, `number.decimal`, `boolean`, `date`, `time`, `datetime`, `date-range`, `datetime-range`, `option.single`, `option.multiple`, `cascade.single`, `cascade.multiple`, `user.single`, `user.multiple`, `department.single`, `department.multiple`, `resource-ref.single`, `resource-ref.multiple`, `file`, `image`, `signature`, `address`, `location`, `json`, `serial-number`, `uuid` and `subtable`. The compiler alone derives PostgreSQL columns, constraints and indexes.
37
+ - Every `date-range` and `datetime-range` field explicitly declares `rangeBoundary: 'closed' | 'half-open'`. Values remain `{ start, end }`; callers never send or override the boundary. Closed ranges allow `start <= end` and use PostgreSQL `[]`; half-open ranges require `start < end` and use `[)`.
38
+ - Declare every custom operation capability in `authz.capabilities` with `kind: 'backend'`, then reference that same code from the operation and its allowed roles. Generated resource CRUD capabilities do not go in this catalog.
39
+ - Build App Operation request/response schemas with `resourceRecordSchema`, `schemaRef`, `composeJsonSchema` and `composeAppOperationSchemas` from `openxiangda/config`. They project the same Resource declaration and canonical field value protocols; never import a physical toolchain package or repeat user, department, resource-reference or managed-file schemas by hand.
40
+ - Visitor duplicate protection uses `createVisitorReservation({ duplicateMatch: { fieldCode: submittedValue }, ... })`. `duplicateMatch` is a non-empty value map, never a field-name array, and no mutable pre-read is allowed.
41
+ - Desktop and mobile pages share values, validation and authorization, but use separate renderers. Options, members and departments store display snapshots; resource references store direct JSON display values; attachments, images and signatures use platform-managed file references.
42
+ - `option.*`, `user.*`, `department.*` and `resource-ref.*` values never collapse to scalar IDs. Single values store one labeled object and multiple values store object arrays. `resource-ref.*` JSON is not a foreign key, trusted target snapshot or automatically refreshed copy; current target state is read by `resourceCode` plus `value`. A resource source `labelField` must be `text.short` or `text.long`; `serial-number` is allowed in source search, description and snapshot fields, but not as the label. `location` accepts only exact WGS84 coordinates captured by DingTalk or browser geolocation; it has no manual input or `manual` source. Roles that consume directory-backed fields explicitly include `app:<app-code>:directory:read`.
43
+ - Derive role grants with `resourceCapabilityCodes(appCode, resourceCode)`. Grant a Native resource's `read` capability to every role allowed to enter its generated page; the compiler adds enabled generated create/update/delete capabilities by default. Tighten only exceptional roles with `deniedCapabilities`, which is compile-time authoring input and is removed from the sealed role. Non-Native mutation owners never receive this expansion. Declare current-user rows only with `currentUserDataPolicy(...)`; do not invent operators, values or alternate current-user spellings.
44
+ - Do not add compatibility aliases, migration branches or silent fallbacks for an earlier 2.0 alpha contract. Replace an incorrect contract and regenerate the application.
45
+ - Standard Workflow and Notification Hub are optional 2.0 modules. Enable them only through canonical `openxiangda.config.ts` declarations and generated clients. `standalone`/`hidden-handoff` default to the compiler-owned process operation; action-owned submission must instead declare `launch.submission.kind: 'named-operation'` with sealed create/existing input and output bindings so the standard PC/mobile page calls the original Named Action and accepts an explicit no-Workflow result. Never add a browser save callback or call Workflow prepare/start directly. Custom pages launch only through a verified Named Action using `OpenXiangdaBusinessProcessService`. PC and mobile render the same `ProcessCommandSurface` independently and recover only by `commandId`. To replace Workflow detail, declare both desktop and mobile `detailRouteCode` values whose routes contain exactly `:instanceId`. Add the current-user todo page only with `frontend.user.applicationTodoCenter: true`; never query Notification Hub management APIs from a user page.
46
+ - Run `pnpm openxiangda check --json` after contract changes and read `data.sealedArtifact`; check never seals, and an older `.openxiangda/build/app-package.json` is not the current check result. Use `pnpm openxiangda accept --plan <file>` only for optional real preproduction identity acceptance; it never blocks delivery. Deploy with `pnpm openxiangda deploy`, inspect with `pnpm openxiangda status` and `pnpm openxiangda logs`, and use the platform rollback command rather than mutating K3s directly.
47
+ - AI-native clients start the workspace protocol through the same pinned binary: `pnpm exec openxiangda --mcp-stdio --cwd <workspace>`. Read `openxiangda://workspace/contracts` or call `contract_describe`; for first-time menu authoring, copy `data.adminNavigationAuthoring.suggestion.expression` once into `frontend.admin.navigation` with its listed `openxiangda/config` imports, then edit that application-owned declaration. Never treat the proposal as runtime discovery. When AppSpec is enabled, also read `openxiangda://workspace/appspec` or call `appspec_context`. Require `aiCatalog` and `aiCatalogDigest` to match the normal compiler output. This is a stdio transport mode, not another application-owned server. Never write an application MCP server, Catalog file, preview store or second authorization path.
@@ -0,0 +1,65 @@
1
+ # OpenXiangda 2.0 应用模板
2
+
3
+ 这是干净的资源 CRUD 模板:Vite + React Router + Refine Core + Ant Design 前端、NestJS 平台启动层,以及平台 Data/AuthZ 声明。
4
+
5
+ ```bash
6
+ pnpm openxiangda dev
7
+ ```
8
+
9
+ 当前应用只直接依赖一个精确版本的 `openxiangda` 根包,并在 lockfile 中锁定其内部实现包。创建另一个应用时使用当前安装的 OpenXiangda 2.0 Skill 给出的精确根包版本,不使用 `latest`、`alpha` 或全局命令。
10
+
11
+ `appspec/app.md` 是可选的业务意图总纲,帮助人和 AI 理解当前需求,但不是发布门禁。没有行为变化
12
+ 时不写变更;小改动最多维护一份短 ChangeSpec。按需使用
13
+ `pnpm openxiangda spec context --json`、`spec new` 和 `spec close`,不要引入 1.x `openspec/SDD`。
14
+
15
+ 在 `openxiangda.config.ts` 的 `data.resources` 中只声明资源 `code`、`name`、`fields` 和可选列表/布局/数据策略。每个字段一次写完语义 `type`、`label`、`required`、列表/筛选标记、`options`/`source`/`file` 与 `access`;不要再写 `schema`、`surface`、PostgreSQL 类型、资源 capabilities、资源 fieldPolicies 或 `platform/data` 模块。编译器据此生成标准后台列表、筛选、表单、详情、审计、文件上传、独立移动端页面、Data API 查询计划和 AI Schema。
16
+
17
+ 成员、部门分别声明 `user.single`/`user.multiple` 和 `department.single`/`department.multiple`;同应用动态资源声明 `resource-ref.single`/`resource-ref.multiple` 及编译期固定的 `source`。这些字段都保存完整 `{label,value,...}` 显示快照,资源引用还保存 `resourceCode` 和声明的 `snapshot` 字段;查询和权限以稳定 `value` 为比较键。资源来源的 `labelField` 只能引用 `text.short` 或 `text.long`;流水号可用于搜索、描述和快照,不能作为显示标签。需要目录选择器的业务角色必须显式拥有 `app:<app-code>:directory:read` 能力。用 `resourceCapabilityCodes` 生成资源 CRUD 权限,用 `currentUserDataPolicy` 声明唯一的当前用户行规则。
18
+
19
+ 字段组件、CRUD Renderer、Shell、Runtime 与 Data/Directory/File/App Client 都由 `openxiangda/react`、`openxiangda/field-kit` 和 `openxiangda/core` 统一提供,应用模板不复制这些实现。Nest 只在需要复杂事务或外部集成时增加 App API。标准客户端显式携带当前环境、使用同源 Cookie;业务代码不读取或持久化 Token、平台内部身份标识与授权结果。
20
+
21
+ 同一应用的自定义后台页、PC 用户页和移动用户页统一声明在
22
+ `frontend.routes`,再用 `defineApplicationContributions(appRoutes, { pages })`
23
+ 逐项绑定本地组件并传给 `OpenXiangdaApplication`。后者是唯一的
24
+ BrowserRouter、RuntimeBoundary、Refine、generated routes 和后台 Shell
25
+ 所有者;用户页可以拥有独立布局,但不要再建 router/Shell。要使用通用应用待办中心,
26
+ 声明 `frontend.user.applicationTodoCenter: true`;平台生成 `/todos` 与 `/m/todos`,
27
+ 只读取当前用户的消息/待办投影并统一解析目标页面。
28
+
29
+ 自定义后台页使用 `OpenXiangdaAdminPage` 作为页面根;Ant Design 组件自动继承平台
30
+ `ConfigProvider`,图表等 TypeScript 渲染值读取 `theme.useToken()`,自定义 CSS
31
+ 只使用平台生成的 `--oxa-antd-*` CSS 变量。不要为后台页新建主题 Provider、主题状态
32
+ 或颜色别名,也不要把白色、黑色、浅灰色写死为页面、卡片、边框或文字颜色。品牌色只能
33
+ 用于品牌和有明确语义的数据分类,不能替代结构色。主题只由平台的 Ant Design
34
+ `defaultAlgorithm`/`darkAlgorithm` 生成;Seed 由平台集中维护,Map/Alias、间距、排版、
35
+ 动效、阴影、层级、断点和组件尺寸均从算法令牌读取。未来配色扩展只能修改平台集中维护
36
+ 的 seed,不得在应用内新建 token registry 或任意颜色输入。
37
+
38
+ 用户端页面不属于这份后台主题合同,可以使用 Tailwind CSS 和自己的产品组件/设计令牌;
39
+ 用户端不应依赖 `--oxa-antd-*`,也不能修改后台 Provider 或平台 Seed。
40
+ 模板已预装 Tailwind CSS v4 与 Vite 插件;在用户端页面直接使用 utility class,
41
+ 并在 `apps/web/src/user-end/tailwind.css` 的 `@theme` 中集中维护用户端产品令牌。
42
+
43
+ 登录声明位于 `frontend.authentication`,只允许现有平台用户并拒绝注册。桌面 `/login`
44
+ 与移动 `/m/login` 是独立生成的 `authenticationSurfaces`,不计入受保护的
45
+ `appRoutes`。用 `defineApplicationContributions({ routes: appRoutes,
46
+ authenticationSurfaces }, { pages, authentication })` 分别绑定 PC/移动品牌 renderer;
47
+ renderer 只使用 `ApplicationLoginSurfaceProps` 回调,不能验证密码、读取 Token、处理
48
+ OAuth callback 或创建第二个 Router/身份状态。`platformAuthManifest` 单独记录登录面 QA,
49
+ 不会改变用户路由覆盖数。
50
+
51
+ 生成式资源后台路径固定为 `/admin/resources/<resourceCode>...`,移动后台面为
52
+ `/m/admin/resources/<resourceCode>...`;普通根路径和 `/m/...` 产品路径可由显式
53
+ `user` route 使用。生成页内部跳转来自编译后的 `adminPages`,不要手写旧根路径、别名或
54
+ 重定向。显式 route 与任一生成 route 的动态路径形状重复时,配置编译会直接失败。
55
+
56
+ 前端一次读取当前登录用户在当前环境的完整应用角色并集和 capability。应用可在 `perspectives` 中声明工作视角;视角只投影页面、行和字段的读取范围,不改变真实身份,也不收窄新增、编辑、删除、流程与自定义动作权限。标准 Data API 自动识别视角;只有绕过标准 Data API 的自定义 Nest 查询才需要通过 `@CurrentPerspective()` 显式实现同等读取投影。字段默认继承资源 read/create/update;`access` 数组为 all-of,`false` 为明确拒绝,无权字段在提交前从 payload 删除。
57
+
58
+ ```bash
59
+ pnpm openxiangda check
60
+ pnpm openxiangda deploy
61
+ pnpm openxiangda status
62
+ pnpm openxiangda logs
63
+ ```
64
+
65
+ `deploy` 使用本模板的 `apps/server/Dockerfile` 自动构建并推送 `linux/amd64` 镜像,再把不可变 digest 写入 AppPackage。纯 CRUD 应用可以保持 backend disabled;复杂事务再启用 Nest。
@@ -0,0 +1,14 @@
1
+ node_modules/
2
+ dist/
3
+ coverage/
4
+ playwright-report/
5
+ test-results/
6
+ .openxiangda/
7
+ .turbo/
8
+ .turbopack/
9
+ .umi/
10
+ .umi-production/
11
+ .codegraph/
12
+ .env
13
+ *.log
14
+ .DS_Store
@@ -0,0 +1,20 @@
1
+ FROM node:22-alpine AS build
2
+ WORKDIR /workspace
3
+ RUN corepack enable
4
+ COPY package.json pnpm-lock.yaml pnpm-workspace.yaml tsconfig.base.json ./
5
+ COPY apps/server/package.json apps/server/package.json
6
+ COPY packages/contracts/package.json packages/contracts/package.json
7
+ RUN node -e "const fs=require('node:fs'); const p=JSON.parse(fs.readFileSync('package.json','utf8')); delete p.devDependencies; fs.writeFileSync('package.json', JSON.stringify(p));"
8
+ RUN pnpm --filter @app/server --filter @app/contracts install --no-frozen-lockfile --ignore-scripts
9
+ COPY apps/server apps/server
10
+ COPY packages/contracts packages/contracts
11
+ RUN pnpm --filter @app/server... build
12
+ RUN pnpm --filter @app/server deploy --prod --legacy --ignore-scripts /output
13
+
14
+ FROM node:22-alpine AS runtime
15
+ ENV NODE_ENV=production
16
+ WORKDIR /app
17
+ COPY --from=build --chown=1000:1000 /output /app
18
+ USER 1000:1000
19
+ EXPOSE 3000
20
+ CMD ["node", "dist/main.js"]
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "@app/server",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "tsx watch src/main.ts",
8
+ "check": "tsc -p tsconfig.json --noEmit",
9
+ "test": "tsx --test test/*.test.ts",
10
+ "build": "tsc -p tsconfig.json",
11
+ "start": "node dist/main.js"
12
+ },
13
+ "dependencies": {
14
+ "@app/contracts": "workspace:*",
15
+ "@nestjs/common": "11.1.29",
16
+ "@nestjs/core": "11.1.29",
17
+ "@nestjs/platform-fastify": "11.1.29",
18
+ "openxiangda": "2.0.0-alpha.85",
19
+ "reflect-metadata": "0.2.2",
20
+ "rxjs": "7.8.2"
21
+ },
22
+ "devDependencies": {
23
+ "@types/node": "24.13.3",
24
+ "tsx": "4.23.12",
25
+ "typescript": "5.9.3"
26
+ }
27
+ }
@@ -0,0 +1,23 @@
1
+ import { Module } from '@nestjs/common';
2
+ import {
3
+ eventHandlerManifest,
4
+ eventSchemas,
5
+ eventSubscriptionCodes,
6
+ } from '@app/contracts';
7
+ import {
8
+ OpenXiangdaModule,
9
+ eventSigningSecretsFromEnvironment,
10
+ } from 'openxiangda/nest';
11
+
12
+ @Module({
13
+ imports: [
14
+ OpenXiangdaModule.forApplication({
15
+ eventHandlerManifest,
16
+ eventSchemas,
17
+ eventSigningSecrets: eventSigningSecretsFromEnvironment(
18
+ eventSubscriptionCodes
19
+ ),
20
+ }),
21
+ ],
22
+ })
23
+ export class AppModule {}
@@ -0,0 +1,5 @@
1
+ import 'reflect-metadata';
2
+ import { bootstrapOpenXiangdaApplication } from 'openxiangda/nest';
3
+ import { AppModule } from './app.module.js';
4
+
5
+ await bootstrapOpenXiangdaApplication(AppModule);
@@ -0,0 +1,17 @@
1
+ import assert from 'node:assert/strict';
2
+ import { readFileSync } from 'node:fs';
3
+ import test from 'node:test';
4
+
5
+ test('the clean server template only owns platform bootstrap', () => {
6
+ const source = readFileSync(new URL('../src/app.module.ts', import.meta.url), 'utf8');
7
+ const main = readFileSync(new URL('../src/main.ts', import.meta.url), 'utf8');
8
+ assert.match(source, /OpenXiangdaModule\.forApplication/);
9
+ assert.doesNotMatch(source, /OPENXIANGDA_(?:APP_CODE|ENVIRONMENT_ID|OAUTH_CLIENT_ID)/);
10
+ assert.match(source, /eventHandlerManifest/);
11
+ assert.match(source, /eventSigningSecretsFromEnvironment/);
12
+ assert.match(main, /bootstrapOpenXiangdaApplication\(AppModule\)/);
13
+ assert.doesNotMatch(main, /NestFactory|FastifyAdapter/);
14
+ const legacyMarkers = ['oauth' + 'Client', 'Workflow', 'instrument' + '-context'];
15
+ assert.doesNotMatch(source, new RegExp(legacyMarkers.join('|')));
16
+ assert.doesNotMatch(source, /createData|updateData|deleteData|queryData/);
17
+ });
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "outDir": "dist",
5
+ "rootDir": "src",
6
+ "sourceMap": true
7
+ },
8
+ "include": ["src/**/*.ts"]
9
+ }
@@ -0,0 +1,15 @@
1
+ <!doctype html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <meta name="openxiangda-runtime-base" content="/" />
7
+ <meta name="openxiangda-app-code" content="native-projection-app" />
8
+ <meta name="openxiangda-environment" content="production" />
9
+ <title>OpenXiangda Standard Data API Live Acceptance</title>
10
+ </head>
11
+ <body>
12
+ <div id="root"></div>
13
+ <script type="module" src="/e2e/data-api-live-fixture.tsx"></script>
14
+ </body>
15
+ </html>
@@ -0,0 +1,5 @@
1
+ export {
2
+ requestApplicationApi,
3
+ searchDirectory,
4
+ searchResource,
5
+ } from 'openxiangda/core';