openxiangda 1.0.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 (121) hide show
  1. package/README.md +58 -0
  2. package/bin/openxiangda.js +11 -0
  3. package/lib/cli.js +2423 -0
  4. package/lib/config.js +121 -0
  5. package/lib/http.js +47 -0
  6. package/lib/skills.js +371 -0
  7. package/lib/utils.js +87 -0
  8. package/lib/workspace-init.js +139 -0
  9. package/openxiangda-skills/SKILL.md +128 -0
  10. package/openxiangda-skills/references/architecture-patterns.md +242 -0
  11. package/openxiangda-skills/references/automation-v3.md +129 -0
  12. package/openxiangda-skills/references/component-guide.md +198 -0
  13. package/openxiangda-skills/references/forms/component-registry.md +53 -0
  14. package/openxiangda-skills/references/forms/form-schema.md +109 -0
  15. package/openxiangda-skills/references/forms/layout-and-rules.md +24 -0
  16. package/openxiangda-skills/references/openxiangda-api.md +466 -0
  17. package/openxiangda-skills/references/pages/page-sdk.md +13 -0
  18. package/openxiangda-skills/references/pages/publish-flow.md +36 -0
  19. package/openxiangda-skills/references/pages/workspace-structure.md +38 -0
  20. package/openxiangda-skills/references/permissions-settings.md +147 -0
  21. package/openxiangda-skills/references/platform-data-model.md +305 -0
  22. package/openxiangda-skills/references/style-system.md +492 -0
  23. package/openxiangda-skills/references/troubleshooting.md +246 -0
  24. package/openxiangda-skills/references/workflow-v3.md +105 -0
  25. package/openxiangda-skills/references/workspace-state.md +45 -0
  26. package/openxiangda-skills/skills/openxiangda-app/SKILL.md +64 -0
  27. package/openxiangda-skills/skills/openxiangda-core/SKILL.md +143 -0
  28. package/openxiangda-skills/skills/openxiangda-form/SKILL.md +76 -0
  29. package/openxiangda-skills/skills/openxiangda-inspect/SKILL.md +40 -0
  30. package/openxiangda-skills/skills/openxiangda-page/SKILL.md +62 -0
  31. package/openxiangda-skills/skills/openxiangda-permission-settings/SKILL.md +95 -0
  32. package/openxiangda-skills/skills/openxiangda-workflow-automation/SKILL.md +97 -0
  33. package/package.json +126 -0
  34. package/packages/sdk/bin/lowcode-workspace.mjs +4 -0
  35. package/packages/sdk/dist/build/index.cjs +33 -0
  36. package/packages/sdk/dist/build/index.cjs.map +1 -0
  37. package/packages/sdk/dist/build/index.d.mts +40 -0
  38. package/packages/sdk/dist/build/index.d.ts +40 -0
  39. package/packages/sdk/dist/build/index.mjs +8 -0
  40. package/packages/sdk/dist/build/index.mjs.map +1 -0
  41. package/packages/sdk/dist/components/index.cjs +18700 -0
  42. package/packages/sdk/dist/components/index.cjs.map +1 -0
  43. package/packages/sdk/dist/components/index.d.mts +2094 -0
  44. package/packages/sdk/dist/components/index.d.ts +2094 -0
  45. package/packages/sdk/dist/components/index.mjs +18649 -0
  46. package/packages/sdk/dist/components/index.mjs.map +1 -0
  47. package/packages/sdk/dist/runtime/index.cjs +1469 -0
  48. package/packages/sdk/dist/runtime/index.cjs.map +1 -0
  49. package/packages/sdk/dist/runtime/index.d.mts +831 -0
  50. package/packages/sdk/dist/runtime/index.d.ts +831 -0
  51. package/packages/sdk/dist/runtime/index.mjs +1420 -0
  52. package/packages/sdk/dist/runtime/index.mjs.map +1 -0
  53. package/packages/sdk/dist/styles/antd-theme.cjs +60 -0
  54. package/packages/sdk/dist/styles/antd-theme.cjs.map +1 -0
  55. package/packages/sdk/dist/styles/antd-theme.d.mts +5 -0
  56. package/packages/sdk/dist/styles/antd-theme.d.ts +5 -0
  57. package/packages/sdk/dist/styles/antd-theme.mjs +35 -0
  58. package/packages/sdk/dist/styles/antd-theme.mjs.map +1 -0
  59. package/packages/sdk/dist/styles/tailwind-preset.cjs +2641 -0
  60. package/packages/sdk/dist/styles/tailwind-preset.cjs.map +1 -0
  61. package/packages/sdk/dist/styles/tailwind-preset.d.mts +75 -0
  62. package/packages/sdk/dist/styles/tailwind-preset.d.ts +75 -0
  63. package/packages/sdk/dist/styles/tailwind-preset.mjs +2618 -0
  64. package/packages/sdk/dist/styles/tailwind-preset.mjs.map +1 -0
  65. package/packages/sdk/dist/styles/tokens.css +73 -0
  66. package/packages/sdk/src/build-source/README.md +9 -0
  67. package/packages/sdk/src/build-source/bin/lowcode-workspace.mjs +7 -0
  68. package/packages/sdk/src/build-source/package.json +34 -0
  69. package/packages/sdk/src/build-source/scripts/build-forms.mjs +824 -0
  70. package/packages/sdk/src/build-source/scripts/build-forms.runtime-entry.test.ts +18 -0
  71. package/packages/sdk/src/build-source/scripts/build-pages.mjs +793 -0
  72. package/packages/sdk/src/build-source/scripts/build-workspace.mjs +64 -0
  73. package/packages/sdk/src/build-source/scripts/publish-all.mjs +127 -0
  74. package/packages/sdk/src/build-source/scripts/publish-oss.mjs +149 -0
  75. package/packages/sdk/src/build-source/scripts/register-bundle.mjs +1 -0
  76. package/packages/sdk/src/build-source/scripts/register.mjs +329 -0
  77. package/packages/sdk/src/build-source/scripts/sync-schema.mjs +301 -0
  78. package/packages/sdk/src/build-source/scripts/utils/form-api.mjs +639 -0
  79. package/packages/sdk/src/build-source/scripts/utils/form-api.test.ts +244 -0
  80. package/packages/sdk/src/build-source/scripts/utils/form-runtime-assets.mjs +57 -0
  81. package/packages/sdk/src/build-source/scripts/utils/form-runtime-assets.test.ts +135 -0
  82. package/packages/sdk/src/build-source/scripts/utils/incremental.mjs +210 -0
  83. package/packages/sdk/src/build-source/scripts/utils/load-config.mjs +257 -0
  84. package/packages/sdk/src/build-source/scripts/utils/load-config.test.ts +44 -0
  85. package/packages/sdk/src/build-source/scripts/utils/mime-types.mjs +70 -0
  86. package/packages/sdk/src/build-source/scripts/utils/namespace-css.mjs +61 -0
  87. package/packages/sdk/src/build-source/scripts/utils/oss-client.mjs +128 -0
  88. package/packages/sdk/src/build-source/scripts/utils/pages.mjs +80 -0
  89. package/packages/sdk/src/build-source/scripts/utils/progress.mjs +57 -0
  90. package/packages/sdk/src/build-source/scripts/utils/register-payload.mjs +89 -0
  91. package/packages/sdk/src/build-source/scripts/utils/register-payload.test.ts +76 -0
  92. package/packages/sdk/src/build-source/scripts/utils/runtime-css-check.mjs +44 -0
  93. package/packages/sdk/src/build-source/scripts/utils/runtime-css-check.test.ts +54 -0
  94. package/packages/sdk/src/build-source/scripts/utils/schema-transform.mjs +130 -0
  95. package/packages/sdk/src/build-source/scripts/utils/schema-transform.test.ts +141 -0
  96. package/packages/sdk/src/build-source/scripts/utils/tailwind-config.mjs +227 -0
  97. package/packages/sdk/src/build-source/scripts/utils/tailwind-config.test.ts +187 -0
  98. package/packages/sdk/src/build-source/src/cli.mjs +679 -0
  99. package/templates/sy-lowcode-app-workspace/app-workspace.config.ts +34 -0
  100. package/templates/sy-lowcode-app-workspace/examples/forms/customer/page.tsx +1 -0
  101. package/templates/sy-lowcode-app-workspace/examples/forms/customer/schema.ts +35 -0
  102. package/templates/sy-lowcode-app-workspace/index.html +12 -0
  103. package/templates/sy-lowcode-app-workspace/package.json +49 -0
  104. package/templates/sy-lowcode-app-workspace/postcss.config.cjs +6 -0
  105. package/templates/sy-lowcode-app-workspace/scripts/build-js-code.mjs +100 -0
  106. package/templates/sy-lowcode-app-workspace/src/dev/App.tsx +26 -0
  107. package/templates/sy-lowcode-app-workspace/src/forms/.gitkeep +1 -0
  108. package/templates/sy-lowcode-app-workspace/src/forms/README.md +48 -0
  109. package/templates/sy-lowcode-app-workspace/src/index.css +28 -0
  110. package/templates/sy-lowcode-app-workspace/src/js-code-nodes/.gitkeep +1 -0
  111. package/templates/sy-lowcode-app-workspace/src/js-code-nodes/types.d.ts +3 -0
  112. package/templates/sy-lowcode-app-workspace/src/main.tsx +36 -0
  113. package/templates/sy-lowcode-app-workspace/src/pages/.gitkeep +1 -0
  114. package/templates/sy-lowcode-app-workspace/src/shared/form-schema.ts +128 -0
  115. package/templates/sy-lowcode-app-workspace/src/types/app-workspace.types.ts +31 -0
  116. package/templates/sy-lowcode-app-workspace/tailwind.config.cjs +30 -0
  117. package/templates/sy-lowcode-app-workspace/tsconfig.app.json +24 -0
  118. package/templates/sy-lowcode-app-workspace/tsconfig.js-code-nodes.json +15 -0
  119. package/templates/sy-lowcode-app-workspace/tsconfig.json +7 -0
  120. package/templates/sy-lowcode-app-workspace/tsconfig.node.json +10 -0
  121. package/templates/sy-lowcode-app-workspace/vite.config.ts +32 -0
@@ -0,0 +1,679 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import {
3
+ existsSync,
4
+ mkdirSync,
5
+ readdirSync,
6
+ readFileSync,
7
+ rmSync,
8
+ statSync,
9
+ writeFileSync,
10
+ } from "node:fs";
11
+ import { basename, dirname, join, resolve } from "node:path";
12
+ import { fileURLToPath } from "node:url";
13
+ import { createRequire } from "node:module";
14
+ import {
15
+ ensureWorkspaceTailwindConfig,
16
+ validateWorkspaceTailwindConfig,
17
+ } from "../scripts/utils/tailwind-config.mjs";
18
+
19
+ const require = createRequire(import.meta.url);
20
+ const packageRoot = dirname(dirname(fileURLToPath(import.meta.url)));
21
+ const managedScriptDir = join(packageRoot, "scripts");
22
+ const managedCommands = new Map([
23
+ ["build", "build-workspace.mjs"],
24
+ ["build-forms", "build-forms.mjs"],
25
+ ["build-pages", "build-pages.mjs"],
26
+ ["sync-schema", "sync-schema.mjs"],
27
+ ["publish-oss", "publish-oss.mjs"],
28
+ ["register", "register.mjs"],
29
+ ["publish-all", "publish-all.mjs"],
30
+ ]);
31
+ const wrapperScripts = new Map([
32
+ ["build-workspace.mjs", "build"],
33
+ ["build-forms.mjs", "build-forms"],
34
+ ["build-pages.mjs", "build-pages"],
35
+ ["sync-schema.mjs", "sync-schema"],
36
+ ["publish-oss.mjs", "publish-oss"],
37
+ ["register.mjs", "register"],
38
+ ["publish-all.mjs", "publish-all"],
39
+ ]);
40
+ const textExtensions = new Set([
41
+ ".js",
42
+ ".jsx",
43
+ ".ts",
44
+ ".tsx",
45
+ ".mjs",
46
+ ".cjs",
47
+ ".json",
48
+ ".md",
49
+ ".css",
50
+ ".scss",
51
+ ".yml",
52
+ ".yaml",
53
+ ]);
54
+ const ignoredDirs = new Set([
55
+ ".git",
56
+ "node_modules",
57
+ "dist",
58
+ "build",
59
+ "coverage",
60
+ ".vite",
61
+ "packages",
62
+ ]);
63
+ const runtimePackages = ["openxiangda"];
64
+ const runtimePackageRegistry =
65
+ process.env.APP_WORKSPACE_NPM_REGISTRY || "https://registry.npmjs.org/";
66
+
67
+ function usage() {
68
+ return `
69
+ lowcode-workspace <command> [options]
70
+
71
+ Commands:
72
+ build | build-forms | build-pages | sync-schema | publish-oss | register | publish-all
73
+ update Update workspace runtime dependencies and managed wrappers
74
+ migrate Convert old local SDK workspace to npm package mode
75
+ smoke Run workspace runtime smoke checks
76
+
77
+ Update options:
78
+ --workspace <path> Workspace root, defaults to cwd
79
+ --channel <tag> npm dist-tag, defaults to latest
80
+ --check Validate only; do not mutate
81
+ --strict-lock Compare lockfile and installed versions with npm latest
82
+ --commit Commit update changes
83
+ --push Push after commit
84
+ --no-commit Do not commit, even if changes exist
85
+ --allow-dirty Allow updates with existing worktree changes
86
+ --skip-install Do not run pnpm install/update
87
+ --skip-gate Do not run typecheck smoke gate
88
+ --gate <quick|full> Gate depth after update, defaults to quick
89
+
90
+ Smoke options:
91
+ --workspace <path> Workspace root, defaults to cwd
92
+ --mode <quick|full> quick validates commands/manifests; full builds shared runtimes
93
+ `;
94
+ }
95
+
96
+ function parseArgs(argv) {
97
+ const result = { _: [] };
98
+ for (let index = 0; index < argv.length; index += 1) {
99
+ const arg = argv[index];
100
+ if (!arg.startsWith("--")) {
101
+ result._.push(arg);
102
+ continue;
103
+ }
104
+ const key = arg.slice(2);
105
+ if (["workspace", "channel", "mode", "gate"].includes(key)) {
106
+ result[key] = argv[index + 1];
107
+ index += 1;
108
+ } else {
109
+ result[key] = true;
110
+ }
111
+ }
112
+ return result;
113
+ }
114
+
115
+ function run(command, args, options = {}) {
116
+ const result = spawnSync(command, args, {
117
+ cwd: options.cwd,
118
+ env: options.env || process.env,
119
+ stdio: options.capture ? "pipe" : "inherit",
120
+ encoding: "utf-8",
121
+ });
122
+ if (result.status !== 0) {
123
+ const output = [result.stdout, result.stderr].filter(Boolean).join("\n");
124
+ throw new Error(
125
+ `command failed: ${[command, ...args].join(" ")}${output ? `\n${output}` : ""}`,
126
+ );
127
+ }
128
+ return result;
129
+ }
130
+
131
+ function runManagedScript(command, args, workspaceRoot) {
132
+ const scriptName = managedCommands.get(command);
133
+ if (!scriptName) throw new Error(`unknown managed command: ${command}`);
134
+ const scriptPath = join(managedScriptDir, scriptName);
135
+ const tsxCli = require.resolve("tsx/cli");
136
+ run(process.execPath, [tsxCli, scriptPath, ...args], {
137
+ cwd: workspaceRoot,
138
+ env: {
139
+ ...process.env,
140
+ LOWCODE_WORKSPACE_ROOT: workspaceRoot,
141
+ },
142
+ });
143
+ }
144
+
145
+ function readJson(path) {
146
+ return JSON.parse(readFileSync(path, "utf-8"));
147
+ }
148
+
149
+ function writeJson(path, value) {
150
+ writeFileSync(path, `${JSON.stringify(value, null, 2)}\n`, "utf-8");
151
+ }
152
+
153
+ function escapeRegExp(value) {
154
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
155
+ }
156
+
157
+ function readOptionalJson(path) {
158
+ if (!existsSync(path)) return null;
159
+ try {
160
+ return readJson(path);
161
+ } catch {
162
+ return null;
163
+ }
164
+ }
165
+
166
+ function npmLatestVersion(packageName, channel) {
167
+ const result = run(
168
+ "npm",
169
+ [
170
+ "view",
171
+ `${packageName}@${channel}`,
172
+ "version",
173
+ "--registry",
174
+ runtimePackageRegistry,
175
+ ],
176
+ {
177
+ capture: true,
178
+ env: runtimeDependencyInstallEnv(),
179
+ },
180
+ );
181
+ return String(result.stdout || "").trim();
182
+ }
183
+
184
+ function runtimeDependencyInstallEnv() {
185
+ return {
186
+ ...process.env,
187
+ npm_config_registry: runtimePackageRegistry,
188
+ PNPM_CONFIG_MINIMUM_RELEASE_AGE: "0",
189
+ };
190
+ }
191
+
192
+ function readInstalledVersion(workspaceRoot, packageName) {
193
+ const packagePath = join(
194
+ workspaceRoot,
195
+ "node_modules",
196
+ packageName,
197
+ "package.json",
198
+ );
199
+ const pkg = readOptionalJson(packagePath);
200
+ return typeof pkg?.version === "string" ? pkg.version : null;
201
+ }
202
+
203
+ function readLockVersion(workspaceRoot, packageName) {
204
+ const lockPath = join(workspaceRoot, "pnpm-lock.yaml");
205
+ if (!existsSync(lockPath)) return null;
206
+ const content = readFileSync(lockPath, "utf-8");
207
+ const packagePattern = new RegExp(
208
+ `(?:^|\\n)\\s{2,}/?${escapeRegExp(packageName)}@([^:\\n(]+)(?:\\([^\\n]*\\))?:`,
209
+ );
210
+ const packageMatch = content.match(packagePattern);
211
+ if (packageMatch?.[1]) return packageMatch[1].trim();
212
+
213
+ const dependencyPattern = new RegExp(
214
+ `(?:^|\\n)\\s{6}${escapeRegExp(packageName)}:\\n\\s{8}specifier:\\s*[^\\n]+\\n\\s{8}version:\\s*([^\\s(]+)`,
215
+ );
216
+ const dependencyMatch = content.match(dependencyPattern);
217
+ return dependencyMatch?.[1]?.trim() || null;
218
+ }
219
+
220
+ function validateRuntimeManifest(
221
+ workspaceRoot,
222
+ manifestPath,
223
+ expectedProtocol,
224
+ expectedMajorVersion,
225
+ ) {
226
+ if (!existsSync(manifestPath)) return;
227
+ const manifest = readJson(manifestPath);
228
+ const errors = [];
229
+ if (manifest.protocol !== expectedProtocol) {
230
+ errors.push(`protocol must be ${expectedProtocol}`);
231
+ }
232
+ if (manifest.majorVersion !== expectedMajorVersion) {
233
+ errors.push(`majorVersion must be ${expectedMajorVersion}`);
234
+ }
235
+ if (!manifest.version) errors.push("version is required");
236
+ if (!manifest.files?.entry) errors.push("files.entry is required");
237
+ if (errors.length) {
238
+ throw new Error(
239
+ `${manifestPath.replace(`${workspaceRoot}/`, "")} is invalid: ${errors.join("; ")}`,
240
+ );
241
+ }
242
+ }
243
+
244
+ function gitStatus(workspaceRoot) {
245
+ const result = run("git", ["status", "--porcelain"], {
246
+ cwd: workspaceRoot,
247
+ capture: true,
248
+ });
249
+ return String(result.stdout || "").trim();
250
+ }
251
+
252
+ function hasGit(workspaceRoot) {
253
+ return (
254
+ existsSync(join(workspaceRoot, ".git")) ||
255
+ existsSync(join(workspaceRoot, "..", ".git"))
256
+ );
257
+ }
258
+
259
+ function updatePackageJson(workspaceRoot, channel) {
260
+ const packagePath = join(workspaceRoot, "package.json");
261
+ if (!existsSync(packagePath))
262
+ throw new Error(`package.json not found: ${packagePath}`);
263
+ const pkg = readJson(packagePath);
264
+ pkg.scripts = {
265
+ ...(pkg.scripts || {}),
266
+ build: "lowcode-workspace build",
267
+ "build:forms": "lowcode-workspace build-forms",
268
+ "build:pages": "lowcode-workspace build-pages",
269
+ "sync-schema": "lowcode-workspace sync-schema",
270
+ "publish:oss": "lowcode-workspace publish-oss",
271
+ register: "lowcode-workspace register",
272
+ "register-bundle": "lowcode-workspace register",
273
+ "publish:all": "lowcode-workspace publish-all",
274
+ "ai:update": `pnpm dlx openxiangda@${channel} lowcode-workspace update --channel ${channel}`,
275
+ "ai:migrate": `pnpm dlx openxiangda@${channel} lowcode-workspace migrate`,
276
+ };
277
+ pkg.dependencies = pkg.dependencies || {};
278
+ delete pkg.dependencies["@sy/page-sdk"];
279
+ delete pkg.dependencies["sy-form-components"];
280
+ delete pkg.dependencies["sy-page-sdk"];
281
+ delete pkg.dependencies["sy-lowcode-workspace-tools"];
282
+ pkg.dependencies["openxiangda"] = channel;
283
+ if (pkg.pnpm?.patchedDependencies) {
284
+ for (const packageName of [
285
+ "@sy/page-sdk",
286
+ "sy-form-components",
287
+ "sy-page-sdk",
288
+ "sy-lowcode-workspace-tools",
289
+ ]) {
290
+ for (const key of Object.keys(pkg.pnpm.patchedDependencies)) {
291
+ if (key === packageName || key.startsWith(`${packageName}@`)) {
292
+ delete pkg.pnpm.patchedDependencies[key];
293
+ }
294
+ }
295
+ }
296
+ if (Object.keys(pkg.pnpm.patchedDependencies).length === 0) {
297
+ delete pkg.pnpm.patchedDependencies;
298
+ }
299
+ }
300
+ if (pkg.pnpm?.overrides) {
301
+ for (const key of Object.keys(pkg.pnpm.overrides)) {
302
+ if (key.startsWith("@tiptap/")) {
303
+ delete pkg.pnpm.overrides[key];
304
+ }
305
+ }
306
+ if (Object.keys(pkg.pnpm.overrides).length === 0) {
307
+ delete pkg.pnpm.overrides;
308
+ }
309
+ }
310
+ if (pkg.pnpm && Object.keys(pkg.pnpm).length === 0) {
311
+ delete pkg.pnpm;
312
+ }
313
+ writeJson(packagePath, pkg);
314
+ }
315
+
316
+ function wrapperContent(command) {
317
+ return `#!/usr/bin/env node
318
+ import { spawnSync } from "node:child_process";
319
+
320
+ const result = spawnSync("lowcode-workspace", [${JSON.stringify(command)}, ...process.argv.slice(2)], {
321
+ stdio: "inherit",
322
+ shell: process.platform === "win32",
323
+ });
324
+ process.exit(result.status ?? 1);
325
+ `;
326
+ }
327
+
328
+ function ensureWrapperScripts(workspaceRoot) {
329
+ const scriptsDir = join(workspaceRoot, "scripts");
330
+ mkdirSync(scriptsDir, { recursive: true });
331
+ for (const [fileName, command] of wrapperScripts) {
332
+ writeFileSync(join(scriptsDir, fileName), wrapperContent(command), "utf-8");
333
+ }
334
+ }
335
+
336
+ function replaceInFile(path, replacer) {
337
+ const before = readFileSync(path, "utf-8");
338
+ const after = replacer(before);
339
+ if (after !== before) writeFileSync(path, after, "utf-8");
340
+ }
341
+
342
+ function rewriteImports(workspaceRoot) {
343
+ walkFiles(workspaceRoot, (filePath) => {
344
+ if (
345
+ ["pnpm-lock.yaml", "package-lock.json", "yarn.lock"].includes(
346
+ basename(filePath),
347
+ )
348
+ ) {
349
+ return;
350
+ }
351
+ if (!textExtensions.has(filePath.slice(filePath.lastIndexOf(".")))) return;
352
+ replaceInFile(filePath, (content) =>
353
+ content
354
+ .replaceAll("@sy/page-sdk", "openxiangda/runtime")
355
+ .replaceAll("sy-page-sdk/react", "openxiangda/runtime")
356
+ .replaceAll("sy-page-sdk", "openxiangda/runtime")
357
+ .replaceAll("sy-form-components/tailwind-preset", "openxiangda/tailwind-preset")
358
+ .replaceAll("sy-form-components", "openxiangda")
359
+ .replaceAll("sy-lowcode-workspace-tools", "openxiangda"),
360
+ );
361
+ });
362
+ }
363
+
364
+ function rewriteLocalSdkConfig(workspaceRoot) {
365
+ const viteConfig = join(workspaceRoot, "vite.config.ts");
366
+ if (existsSync(viteConfig)) {
367
+ replaceInFile(viteConfig, (content) =>
368
+ content
369
+ .replace(/\s*\{[^{}]*packages\/page-sdk[^{}]*\},?/g, "")
370
+ .replace(
371
+ /\s*\{\s*find:\s*["']sy-page-sdk\/react["'][\s\S]*?\n\s*\},\n/g,
372
+ "",
373
+ )
374
+ .replace(/\s*\{\s*find:\s*["']sy-page-sdk["'][\s\S]*?\n\s*\},\n/g, ""),
375
+ );
376
+ }
377
+ const vitestConfig = join(workspaceRoot, "vitest.config.ts");
378
+ if (existsSync(vitestConfig)) {
379
+ replaceInFile(vitestConfig, (content) =>
380
+ content
381
+ .replace(/\s*\{[^{}]*packages\/page-sdk[^{}]*\},?/g, "")
382
+ .replace(
383
+ /\s*\{\s*find:\s*["']sy-page-sdk\/react["'][\s\S]*?\n\s*\},\n/g,
384
+ "",
385
+ )
386
+ .replace(/\s*\{\s*find:\s*["']sy-page-sdk["'][\s\S]*?\n\s*\},\n/g, "")
387
+ .replace(/,\s*["']sy-page-sdk["']/g, ""),
388
+ );
389
+ }
390
+ const tsconfig = join(workspaceRoot, "tsconfig.app.json");
391
+ if (existsSync(tsconfig)) {
392
+ try {
393
+ const config = readJson(tsconfig);
394
+ if (config.compilerOptions?.paths) {
395
+ delete config.compilerOptions.paths["sy-page-sdk"];
396
+ delete config.compilerOptions.paths["sy-page-sdk/react"];
397
+ }
398
+ if (Array.isArray(config.include)) {
399
+ config.include = config.include.filter(
400
+ (item) => !String(item).includes("packages/page-sdk"),
401
+ );
402
+ }
403
+ writeJson(tsconfig, config);
404
+ } catch {
405
+ replaceInFile(tsconfig, (content) =>
406
+ content
407
+ .replace(/\s*["']sy-page-sdk["']:\s*\[[^\n]*\],?\n/g, "")
408
+ .replace(/\s*["']sy-page-sdk\/react["']:\s*\[[^\n]*\],?\n/g, "")
409
+ .replace(/,\s*["']packages\/page-sdk\/src["']/g, "")
410
+ .replace(/["']packages\/page-sdk\/src["'],?\s*/g, ""),
411
+ );
412
+ }
413
+ }
414
+ const tailwindConfig = join(workspaceRoot, "tailwind.config.cjs");
415
+ if (existsSync(tailwindConfig)) {
416
+ replaceInFile(tailwindConfig, (content) =>
417
+ content
418
+ .replace(/,\s*["'][^"']*packages\/page-sdk[^"']*["']/g, "")
419
+ .replace(/["'][^"']*packages\/page-sdk[^"']*["']\s*,?/g, ""),
420
+ );
421
+ }
422
+ }
423
+
424
+ function walkFiles(root, onFile) {
425
+ for (const entry of readdirSync(root)) {
426
+ if (ignoredDirs.has(entry)) continue;
427
+ const path = join(root, entry);
428
+ const stat = statSync(path);
429
+ if (stat.isDirectory()) {
430
+ walkFiles(path, onFile);
431
+ } else if (stat.isFile()) {
432
+ onFile(path);
433
+ }
434
+ }
435
+ }
436
+
437
+ function removeLocalSdk(workspaceRoot) {
438
+ const localSdkPath = join(workspaceRoot, "packages", "page-sdk");
439
+ if (existsSync(localSdkPath)) {
440
+ rmSync(localSdkPath, { recursive: true, force: true });
441
+ }
442
+ }
443
+
444
+ function validateWorkspace(workspaceRoot, channel = "latest", options = {}) {
445
+ const errors = [];
446
+ const warnings = [];
447
+ const pkg = readJson(join(workspaceRoot, "package.json"));
448
+ const deps = pkg.dependencies || {};
449
+ if (deps["@sy/page-sdk"])
450
+ errors.push("package.json still depends on @sy/page-sdk");
451
+ for (const oldName of [
452
+ "sy-form-components",
453
+ "sy-page-sdk",
454
+ "sy-lowcode-workspace-tools",
455
+ ]) {
456
+ if (deps[oldName]) errors.push(`package.json still depends on ${oldName}`);
457
+ }
458
+ for (const name of runtimePackages) {
459
+ if (deps[name] !== channel)
460
+ errors.push(`package.json dependency ${name} must be ${channel}`);
461
+ }
462
+ const isWorkspaceToolsSourceRepo = existsSync(
463
+ join(workspaceRoot, "packages", "workspace-tools", "package.json"),
464
+ );
465
+ if (
466
+ existsSync(join(workspaceRoot, "packages", "page-sdk")) &&
467
+ !isWorkspaceToolsSourceRepo
468
+ ) {
469
+ errors.push(
470
+ "local packages/page-sdk must be removed from application workspaces",
471
+ );
472
+ }
473
+ errors.push(...validateWorkspaceTailwindConfig(workspaceRoot));
474
+ walkFiles(workspaceRoot, (filePath) => {
475
+ if (!textExtensions.has(filePath.slice(filePath.lastIndexOf(".")))) return;
476
+ if (
477
+ ["pnpm-lock.yaml", "package-lock.json", "yarn.lock"].includes(
478
+ basename(filePath),
479
+ )
480
+ ) {
481
+ return;
482
+ }
483
+ const content = readFileSync(filePath, "utf-8");
484
+ for (const oldName of [
485
+ "@sy/page-sdk",
486
+ "sy-form-components",
487
+ "sy-page-sdk",
488
+ "sy-lowcode-workspace-tools",
489
+ ]) {
490
+ if (content.includes(oldName)) {
491
+ errors.push(`${filePath} still references ${oldName}`);
492
+ }
493
+ }
494
+ if (content.includes("packages/page-sdk")) {
495
+ errors.push(`${filePath} still references packages/page-sdk`);
496
+ }
497
+ });
498
+ if (errors.length) {
499
+ throw new Error(`workspace update check failed:\n- ${errors.join("\n- ")}`);
500
+ }
501
+ if (options.strictLock) {
502
+ const versionRows = [];
503
+ for (const packageName of runtimePackages) {
504
+ const latest = npmLatestVersion(packageName, channel);
505
+ const installed = readInstalledVersion(workspaceRoot, packageName);
506
+ const locked = readLockVersion(workspaceRoot, packageName);
507
+ versionRows.push({ packageName, latest, installed, locked });
508
+ if (latest && locked && locked !== latest) {
509
+ errors.push(
510
+ `pnpm-lock.yaml locks ${packageName}@${locked}, latest is ${latest}`,
511
+ );
512
+ }
513
+ if (latest && installed && installed !== latest) {
514
+ errors.push(
515
+ `node_modules has ${packageName}@${installed}, latest is ${latest}`,
516
+ );
517
+ }
518
+ if (!locked) {
519
+ warnings.push(
520
+ `pnpm-lock.yaml does not contain ${packageName}; run pnpm install after update`,
521
+ );
522
+ }
523
+ if (!installed) {
524
+ warnings.push(
525
+ `node_modules does not contain ${packageName}; run pnpm install`,
526
+ );
527
+ }
528
+ }
529
+ if (versionRows.length) {
530
+ console.log("[lowcode-workspace] runtime dependency versions:");
531
+ for (const row of versionRows) {
532
+ console.log(
533
+ ` - ${row.packageName}: latest=${row.latest || "unknown"} locked=${row.locked || "missing"} installed=${row.installed || "missing"}`,
534
+ );
535
+ }
536
+ }
537
+ }
538
+ if (errors.length) {
539
+ throw new Error(`workspace update check failed:\n- ${errors.join("\n- ")}`);
540
+ }
541
+ for (const warning of warnings) {
542
+ console.warn(`[lowcode-workspace] warning: ${warning}`);
543
+ }
544
+ }
545
+
546
+ function runUpdateInstall(workspaceRoot, channel) {
547
+ const installEnv = runtimeDependencyInstallEnv();
548
+ run("pnpm", ["install"], { cwd: workspaceRoot, env: installEnv });
549
+ run(
550
+ "pnpm",
551
+ [
552
+ "update",
553
+ "--latest",
554
+ "openxiangda",
555
+ ],
556
+ { cwd: workspaceRoot, env: installEnv },
557
+ );
558
+ updatePackageJson(workspaceRoot, channel);
559
+ run("pnpm", ["install"], { cwd: workspaceRoot, env: installEnv });
560
+ }
561
+
562
+ function runSmoke(workspaceRoot, mode = "quick") {
563
+ const normalizedMode = String(mode || "quick").trim();
564
+ if (!["quick", "full"].includes(normalizedMode)) {
565
+ throw new Error(`unsupported smoke mode: ${mode}`);
566
+ }
567
+ const pkg = readJson(join(workspaceRoot, "package.json"));
568
+ if (pkg.scripts?.typecheck) {
569
+ run("pnpm", ["typecheck"], { cwd: workspaceRoot });
570
+ }
571
+ if (normalizedMode === "full") {
572
+ runManagedScript("build-pages", [], workspaceRoot);
573
+ runManagedScript("build-forms", [], workspaceRoot);
574
+ } else {
575
+ runManagedScript("build-pages", ["--help"], workspaceRoot);
576
+ runManagedScript("build-forms", ["--help"], workspaceRoot);
577
+ }
578
+ validateRuntimeManifest(
579
+ workspaceRoot,
580
+ join(workspaceRoot, "dist", "page-runtime", "manifest.json"),
581
+ "sy-page-runtime",
582
+ 1,
583
+ );
584
+ validateRuntimeManifest(
585
+ workspaceRoot,
586
+ join(workspaceRoot, "dist", "form-runtime", "manifest.json"),
587
+ "sy-form-runtime",
588
+ 2,
589
+ );
590
+ }
591
+
592
+ function commitAndMaybePush(workspaceRoot, push) {
593
+ if (!hasGit(workspaceRoot)) return;
594
+ run("git", ["add", "-A"], { cwd: workspaceRoot });
595
+ const status = gitStatus(workspaceRoot);
596
+ if (!status) return;
597
+ run(
598
+ "git",
599
+ ["commit", "-m", "chore: update lowcode workspace runtime dependencies"],
600
+ {
601
+ cwd: workspaceRoot,
602
+ },
603
+ );
604
+ if (push) {
605
+ run("git", ["push", "origin", "HEAD"], { cwd: workspaceRoot });
606
+ }
607
+ }
608
+
609
+ async function updateWorkspace(argv, { migrate = false } = {}) {
610
+ const args = parseArgs(argv);
611
+ const workspaceRoot = resolve(args.workspace || process.cwd());
612
+ const channel = String(
613
+ args.channel || process.env.APP_WORKSPACE_UPDATE_CHANNEL || "latest",
614
+ );
615
+ const checkOnly = Boolean(args.check);
616
+ const strictLock = Boolean(args["strict-lock"]);
617
+ const allowDirty = Boolean(args["allow-dirty"]);
618
+ const shouldCommit = Boolean(args.commit) && !args["no-commit"];
619
+ const shouldPush = Boolean(args.push);
620
+ const gateMode = String(args.gate || "quick");
621
+
622
+ if (checkOnly) {
623
+ validateWorkspace(workspaceRoot, channel, { strictLock });
624
+ console.log("[lowcode-workspace] update check passed");
625
+ return;
626
+ }
627
+
628
+ if (hasGit(workspaceRoot) && !allowDirty) {
629
+ const before = gitStatus(workspaceRoot);
630
+ if (before) {
631
+ throw new Error(
632
+ "workspace has uncommitted changes; commit/stash them first or pass --allow-dirty",
633
+ );
634
+ }
635
+ }
636
+
637
+ updatePackageJson(workspaceRoot, channel);
638
+ rewriteImports(workspaceRoot);
639
+ ensureWorkspaceTailwindConfig(workspaceRoot);
640
+ ensureWrapperScripts(workspaceRoot);
641
+ rewriteLocalSdkConfig(workspaceRoot);
642
+ if (migrate || existsSync(join(workspaceRoot, "packages", "page-sdk"))) {
643
+ removeLocalSdk(workspaceRoot);
644
+ }
645
+
646
+ if (!args["skip-install"]) runUpdateInstall(workspaceRoot, channel);
647
+ validateWorkspace(workspaceRoot, channel, { strictLock: !args["skip-install"] });
648
+ if (!args["skip-gate"]) runSmoke(workspaceRoot, gateMode);
649
+ if (shouldCommit) commitAndMaybePush(workspaceRoot, shouldPush);
650
+ console.log("[lowcode-workspace] workspace update completed");
651
+ }
652
+
653
+ export async function main(argv = process.argv.slice(2)) {
654
+ const [command, ...rest] = argv;
655
+ if (!command || command === "--help" || command === "-h") {
656
+ console.log(usage());
657
+ return;
658
+ }
659
+ if (command === "update") {
660
+ await updateWorkspace(rest);
661
+ return;
662
+ }
663
+ if (command === "migrate") {
664
+ await updateWorkspace(rest, { migrate: true });
665
+ return;
666
+ }
667
+ if (command === "smoke") {
668
+ const args = parseArgs(rest);
669
+ runSmoke(resolve(args.workspace || process.cwd()), args.mode || "quick");
670
+ console.log("[lowcode-workspace] smoke check passed");
671
+ return;
672
+ }
673
+ if (managedCommands.has(command)) {
674
+ const args = parseArgs(rest);
675
+ runManagedScript(command, rest, resolve(args.workspace || process.cwd()));
676
+ return;
677
+ }
678
+ throw new Error(`unknown command: ${command}`);
679
+ }
@@ -0,0 +1,34 @@
1
+ import { defineAppWorkspaceConfig } from "openxiangda/build";
2
+
3
+ export default defineAppWorkspaceConfig({
4
+ appType: process.env.APP_TYPE || process.env.OPENXIANGDA_APP_TYPE || "APP_XXXXXXXXXXXXXXXX",
5
+ appName: process.env.APP_NAME || "低代码应用",
6
+ platformUrl: process.env.APP_PLATFORM_URL || process.env.OPENXIANGDA_BASE_URL || "http://yida.wisejob.cn/service",
7
+ servicePrefix: process.env.APP_SERVICE_PREFIX || "/service",
8
+ appKey: process.env.APP_KEY || "",
9
+ appSecret: process.env.APP_SECRET || "",
10
+ userId: process.env.APP_USER_ID || "",
11
+ version: process.env.APP_VERSION || "0.1.0",
12
+ buildId: process.env.APP_BUILD_ID || "",
13
+ oss: {
14
+ region: process.env.APP_OSS_REGION || "oss-cn-hangzhou",
15
+ bucket: process.env.APP_OSS_BUCKET || "sy-app-workspace-dev",
16
+ accessKeyId: process.env.APP_OSS_ACCESS_KEY_ID || "",
17
+ accessKeySecret: process.env.APP_OSS_ACCESS_KEY_SECRET || "",
18
+ pathPrefix: process.env.APP_OSS_PATH_PREFIX || "app-workspace",
19
+ },
20
+ defaults: {
21
+ protocolVersion: process.env.APP_PAGE_PROTOCOL_VERSION || "1.0",
22
+ frameworkVersion: process.env.APP_FRAMEWORK_VERSION || "18.3.1",
23
+ cssIsolation:
24
+ process.env.APP_PAGE_CSS_ISOLATION === "none"
25
+ ? "none"
26
+ : process.env.APP_PAGE_CSS_ISOLATION === "shadow"
27
+ ? "shadow"
28
+ : "namespace",
29
+ formMenuParentId: process.env.APP_FORM_MENU_PARENT_ID || "",
30
+ formMenuIcon: process.env.APP_FORM_MENU_ICON || "",
31
+ pageMenuParentId: process.env.APP_PAGE_MENU_PARENT_ID || "",
32
+ pageMenuIcon: process.env.APP_PAGE_MENU_ICON || "",
33
+ },
34
+ });