openxiangda 1.0.85 → 1.0.86

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 (2) hide show
  1. package/lib/cli.js +91 -10
  2. package/package.json +2 -1
package/lib/cli.js CHANGED
@@ -2,6 +2,7 @@ const fs = require('fs');
2
2
  const path = require('path');
3
3
  const crypto = require('crypto');
4
4
  const os = require('os');
5
+ const { builtinModules } = require('module');
5
6
  const { spawnSync } = require('child_process');
6
7
  const { pathToFileURL } = require('url');
7
8
  const esbuild = require('esbuild');
@@ -7107,10 +7108,18 @@ function resolveJsCodeBundlePathForPlan(localPath) {
7107
7108
  const extension = path.extname(localPath).toLowerCase();
7108
7109
  if (extension && extension !== '.ts' && extension !== '.tsx') return null;
7109
7110
  const normalized = localPath.replace(/\\/g, '/');
7110
- const matched = normalized.match(/src\/js-code-nodes\/([^/]+)\/index\.tsx?$/);
7111
+ const jsCodeMatched = normalized.match(/src\/js-code-nodes\/([^/]+)\/index\.tsx?$/);
7112
+ const automationMatched = normalized.match(/src\/automations\/([^/]+)\/index\.tsx?$/);
7113
+ const functionMatched = normalized.match(/src\/functions\/([^/]+)\/index\.tsx?$/);
7114
+ const matched = jsCodeMatched || automationMatched || functionMatched;
7111
7115
  if (!matched) return null;
7116
+ const sourceKind = functionMatched
7117
+ ? 'functions'
7118
+ : automationMatched
7119
+ ? 'automations'
7120
+ : 'js-code-nodes';
7112
7121
  const workspaceRoot = findWorkspaceRoot(localPath);
7113
- return path.join(workspaceRoot, 'dist', 'js-code-nodes', matched[1], 'index.cjs');
7122
+ return path.join(workspaceRoot, 'dist', sourceKind, matched[1], 'index.cjs');
7114
7123
  }
7115
7124
 
7116
7125
  function sortObjectForStableJson(value) {
@@ -7272,7 +7281,7 @@ async function uploadJsCodeSnapshotFile(
7272
7281
  const resolvedLocalPath = fs.existsSync(baseResolvedPath)
7273
7282
  ? baseResolvedPath
7274
7283
  : cwdResolvedPath;
7275
- const bundlePath = resolveJsCodeBundlePath(resolvedLocalPath, scriptCode);
7284
+ const bundlePath = await resolveJsCodeBundlePath(resolvedLocalPath, scriptCode);
7276
7285
  if (!fs.existsSync(bundlePath)) {
7277
7286
  fail(`JS_CODE bundle不存在: ${bundlePath}`);
7278
7287
  }
@@ -7308,14 +7317,14 @@ async function uploadJsCodeSnapshotFile(
7308
7317
  return sourceFile;
7309
7318
  }
7310
7319
 
7311
- function resolveJsCodeBundlePath(localPath, scriptCode) {
7320
+ async function resolveJsCodeBundlePath(localPath, scriptCode) {
7312
7321
  const extension = path.extname(localPath).toLowerCase();
7313
7322
  if (['.js', '.cjs', '.mjs'].includes(extension)) {
7314
7323
  fail(
7315
7324
  `JS_CODE V2 要求 AI 源码使用 TypeScript,请把 sourceFile.localPath 指向 src/js-code-nodes/<scriptCode>/index.ts、src/automations/<scriptCode>/index.ts 或 src/functions/<functionCode>/index.ts,而不是已构建的 ${extension} 文件: ${localPath}`
7316
7325
  );
7317
7326
  }
7318
- if (extension !== '.ts') {
7327
+ if (!['.ts', '.tsx'].includes(extension)) {
7319
7328
  fail(
7320
7329
  `JS_CODE V2 sourceFile.localPath 必须指向 TypeScript 源文件 src/js-code-nodes/<scriptCode>/index.ts、src/automations/<scriptCode>/index.ts 或 src/functions/<functionCode>/index.ts: ${localPath}`
7321
7330
  );
@@ -7339,16 +7348,88 @@ function resolveJsCodeBundlePath(localPath, scriptCode) {
7339
7348
  : 'js-code-nodes';
7340
7349
 
7341
7350
  const workspaceRoot = findWorkspaceRoot(localPath);
7342
- const result = spawnSync('pnpm', ['build-js-code', '--script', resolvedScriptCode, '--source', sourceKind], {
7343
- cwd: workspaceRoot,
7344
- stdio: 'inherit',
7345
- });
7346
- if (result.status !== 0) {
7351
+ const result = runWorkspaceJsCodeBuild(workspaceRoot, resolvedScriptCode, sourceKind);
7352
+ if (result.status !== 0 && sourceKind === 'functions' && isUnsupportedFunctionsBuildScript(result)) {
7353
+ warn(
7354
+ `当前工作区 scripts/build-js-code.mjs 不支持 App Function source=functions,已使用 openxiangda 内置构建器兼容构建 ${resolvedScriptCode}`
7355
+ );
7356
+ await buildFunctionSourceWithBundledEsbuild(localPath, workspaceRoot, resolvedScriptCode);
7357
+ } else if (result.status !== 0) {
7358
+ if (result.stdout) process.stdout.write(result.stdout);
7359
+ if (result.stderr) process.stderr.write(result.stderr);
7347
7360
  fail(`JS_CODE bundle构建失败: ${resolvedScriptCode}`);
7361
+ } else {
7362
+ if (result.stdout) process.stdout.write(result.stdout);
7363
+ if (result.stderr) process.stderr.write(result.stderr);
7348
7364
  }
7349
7365
  return path.join(workspaceRoot, 'dist', sourceKind, resolvedScriptCode, 'index.cjs');
7350
7366
  }
7351
7367
 
7368
+ function runWorkspaceJsCodeBuild(workspaceRoot, resolvedScriptCode, sourceKind) {
7369
+ return spawnSync('pnpm', ['build-js-code', '--script', resolvedScriptCode, '--source', sourceKind], {
7370
+ cwd: workspaceRoot,
7371
+ encoding: 'utf8',
7372
+ });
7373
+ }
7374
+
7375
+ function isUnsupportedFunctionsBuildScript(result) {
7376
+ const output = `${result.stdout || ''}\n${result.stderr || ''}`;
7377
+ return (
7378
+ output.includes('unsupported source: functions') ||
7379
+ output.includes('Expected js-code-nodes or automations')
7380
+ );
7381
+ }
7382
+
7383
+ async function buildFunctionSourceWithBundledEsbuild(localPath, workspaceRoot, functionCode) {
7384
+ const outfile = path.join(workspaceRoot, 'dist', 'functions', functionCode, 'index.cjs');
7385
+ fs.mkdirSync(path.dirname(outfile), { recursive: true });
7386
+ const external = Array.from(
7387
+ new Set([...builtinModules, ...builtinModules.map(name => `node:${name}`)])
7388
+ );
7389
+ try {
7390
+ await esbuild.build({
7391
+ entryPoints: [localPath],
7392
+ outfile,
7393
+ bundle: true,
7394
+ platform: 'node',
7395
+ format: 'cjs',
7396
+ target: ['node20'],
7397
+ sourcemap: true,
7398
+ logLevel: 'silent',
7399
+ external,
7400
+ plugins: [
7401
+ {
7402
+ name: 'openxiangda-workspace-alias',
7403
+ setup(build) {
7404
+ build.onResolve({ filter: /^@\// }, args => ({
7405
+ path: resolveWorkspaceAliasPath(workspaceRoot, args.path),
7406
+ }));
7407
+ },
7408
+ },
7409
+ ],
7410
+ });
7411
+ } catch (error) {
7412
+ fail(`App Function 内置构建失败: ${functionCode}: ${error.message}`);
7413
+ }
7414
+ print(`built functions/${functionCode} -> ${path.relative(workspaceRoot, outfile)}`);
7415
+ }
7416
+
7417
+ function resolveWorkspaceAliasPath(workspaceRoot, importPath) {
7418
+ const raw = path.join(workspaceRoot, 'src', importPath.replace(/^@\//, ''));
7419
+ const candidates = [
7420
+ raw,
7421
+ `${raw}.ts`,
7422
+ `${raw}.tsx`,
7423
+ `${raw}.js`,
7424
+ `${raw}.mjs`,
7425
+ `${raw}.cjs`,
7426
+ path.join(raw, 'index.ts'),
7427
+ path.join(raw, 'index.tsx'),
7428
+ path.join(raw, 'index.js'),
7429
+ ];
7430
+ return candidates.find(candidate => fs.existsSync(candidate)) || raw;
7431
+ }
7432
+
7352
7433
  function findWorkspaceRoot(startPath) {
7353
7434
  if (!fs.existsSync(startPath)) {
7354
7435
  return process.cwd();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openxiangda",
3
- "version": "1.0.85",
3
+ "version": "1.0.86",
4
4
  "description": "OpenXiangda CLI, workspace build tools, runtime SDK, and form components.",
5
5
  "private": false,
6
6
  "bin": {
@@ -65,6 +65,7 @@
65
65
  "prepack": "npm run build:sdk",
66
66
  "test:profile-isolation": "bash scripts/profile-isolation-smoke.sh",
67
67
  "test:resource-plan": "node scripts/resource-plan-smoke.mjs",
68
+ "test:app-function-fallback": "node scripts/app-function-source-fallback-smoke.mjs",
68
69
  "test:runtime-deploy": "node scripts/runtime-deploy-smoke.mjs",
69
70
  "test:skill-install": "bash scripts/skill-install-smoke.sh",
70
71
  "test:workspace-init": "bash scripts/workspace-init-smoke.sh"