package-cherry.mjs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. #!/usr/bin/env node
  2. import fs from 'fs/promises';
  3. import path from 'path';
  4. import { fileURLToPath } from 'url';
  5. import { spawn } from 'child_process';
  6. const __filename = fileURLToPath(import.meta.url);
  7. const __dirname = path.dirname(__filename);
  8. const root = path.resolve(__dirname, '..');
  9. function run(cmd, args, opts = {}) {
  10. return new Promise((resolve, reject) => {
  11. const p = spawn(cmd, args, { stdio: 'inherit', cwd: root, ...opts });
  12. p.on('close', (code) => {
  13. if (code === 0) resolve(); else reject(new Error(`${cmd} ${args.join(' ')} exited ${code}`));
  14. });
  15. p.on('error', reject);
  16. });
  17. }
  18. async function exists(p) {
  19. try { await fs.access(p); return true; } catch { return false; }
  20. }
  21. async function ensureDir(p) {
  22. await fs.mkdir(p, { recursive: true });
  23. }
  24. async function cp(src, dest) {
  25. await fs.cp(src, dest, { recursive: true, force: true });
  26. }
  27. async function main() {
  28. const skipBuild = process.env.NO_BUILD === '1' || process.argv.includes('--no-build');
  29. if (!skipBuild) {
  30. console.log('> Building Next.js (standalone)...');
  31. await run('npm', ['run', '-s', 'build']);
  32. } else {
  33. console.log('> Skipping build (NO_BUILD=1)');
  34. }
  35. const nextDir = path.join(root, '.next');
  36. const standaloneDir = path.join(nextDir, 'standalone');
  37. const outDir = path.join(root, 'dist');
  38. if (!(await exists(standaloneDir))) {
  39. throw new Error('Missing .next/standalone. Please run build first.');
  40. }
  41. // Reassemble dist
  42. console.log('> Assembling dist...');
  43. await fs.rm(outDir, { recursive: true, force: true });
  44. await ensureDir(outDir);
  45. await cp(standaloneDir + path.sep, outDir + path.sep);
  46. // Copy static and public
  47. const nextStatic = path.join(nextDir, 'static');
  48. const distNext = path.join(outDir, '.next');
  49. await ensureDir(distNext);
  50. if (await exists(nextStatic)) {
  51. await cp(nextStatic, path.join(distNext, 'static'));
  52. }
  53. const publicDir = path.join(root, 'public');
  54. if (await exists(publicDir)) {
  55. await cp(publicDir, path.join(outDir, 'public'));
  56. }
  57. // Write ESM entry
  58. console.log('> Writing dist/index.js');
  59. const entry = `import('./server.js').catch(err => {\n console.error('Failed to start Next standalone server:', err);\n setTimeout(() => process.exit(1), 10);\n});\n`;
  60. await fs.writeFile(path.join(outDir, 'index.js'), entry, 'utf8');
  61. // Compose cherry-node.json at repo root
  62. let name = 'writing-helper';
  63. let version = '1.0.0';
  64. const cherryStudioPath = path.join(root, 'cherry-studio.json');
  65. if (await exists(cherryStudioPath)) {
  66. try {
  67. const raw = await fs.readFile(cherryStudioPath, 'utf8');
  68. const j = JSON.parse(raw || '{}');
  69. name = typeof j.name === 'string' && j.name.trim() ? j.name.trim() : name;
  70. version = typeof j.version === 'string' && j.version.trim() ? j.version.trim() : version;
  71. } catch {}
  72. }
  73. const manifest = { name, version, entry: 'dist/index.js' };
  74. const manifestPath = path.join(root, 'cherry-node.json');
  75. await fs.writeFile(manifestPath, JSON.stringify(manifest, null, 2), 'utf8');
  76. // Zip: require system zip
  77. const stamp = new Date().toISOString().replace(/[-:T.Z]/g, '').slice(0, 14);
  78. const zipName = `cherry-package-${stamp}.zip`;
  79. const zipPath = path.join(outDir, zipName);
  80. console.log('> Creating zip:', zipPath);
  81. await run('zip', ['-rq', zipPath, 'cherry-node.json', 'dist']);
  82. await fs.copyFile(zipPath, path.join(outDir, 'cherry-package.zip'));
  83. console.log('\n✅ Done');
  84. console.log(' -', zipPath);
  85. console.log(' -', path.join(outDir, 'cherry-package.zip'));
  86. }
  87. main().catch((err) => {
  88. console.error('Package failed:', err);
  89. process.exit(1);
  90. });