@onexapis/cli 1.0.0 → 1.0.2
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.
- package/README.md +211 -208
- package/dist/cli.js +468 -221
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +462 -218
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +25 -2
- package/dist/index.d.ts +25 -2
- package/dist/index.js +418 -184
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +416 -186
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -1
package/dist/cli.js
CHANGED
|
@@ -1,33 +1,38 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
var commander = require('commander');
|
|
5
|
-
var chalk4 = require('chalk');
|
|
6
4
|
var path = require('path');
|
|
7
|
-
var
|
|
8
|
-
var child_process = require('child_process');
|
|
9
|
-
var inquirer = require('inquirer');
|
|
10
|
-
var ora = require('ora');
|
|
5
|
+
var dotenv = require('dotenv');
|
|
11
6
|
var fs = require('fs-extra');
|
|
12
7
|
var ejs = require('ejs');
|
|
8
|
+
var child_process = require('child_process');
|
|
9
|
+
var chalk4 = require('chalk');
|
|
10
|
+
var ora = require('ora');
|
|
11
|
+
var commander = require('commander');
|
|
12
|
+
var fs2 = require('fs');
|
|
13
|
+
var inquirer = require('inquirer');
|
|
13
14
|
var archiver = require('archiver');
|
|
14
15
|
var FormData = require('form-data');
|
|
15
16
|
var fetch = require('node-fetch');
|
|
16
17
|
var clientS3 = require('@aws-sdk/client-s3');
|
|
17
|
-
var
|
|
18
|
+
var os = require('os');
|
|
19
|
+
var AdmZip = require('adm-zip');
|
|
18
20
|
|
|
19
21
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
20
22
|
|
|
21
|
-
var chalk4__default = /*#__PURE__*/_interopDefault(chalk4);
|
|
22
23
|
var path__default = /*#__PURE__*/_interopDefault(path);
|
|
23
|
-
var
|
|
24
|
-
var inquirer__default = /*#__PURE__*/_interopDefault(inquirer);
|
|
25
|
-
var ora__default = /*#__PURE__*/_interopDefault(ora);
|
|
24
|
+
var dotenv__default = /*#__PURE__*/_interopDefault(dotenv);
|
|
26
25
|
var fs__default = /*#__PURE__*/_interopDefault(fs);
|
|
27
26
|
var ejs__default = /*#__PURE__*/_interopDefault(ejs);
|
|
27
|
+
var chalk4__default = /*#__PURE__*/_interopDefault(chalk4);
|
|
28
|
+
var ora__default = /*#__PURE__*/_interopDefault(ora);
|
|
29
|
+
var fs2__default = /*#__PURE__*/_interopDefault(fs2);
|
|
30
|
+
var inquirer__default = /*#__PURE__*/_interopDefault(inquirer);
|
|
28
31
|
var archiver__default = /*#__PURE__*/_interopDefault(archiver);
|
|
29
32
|
var FormData__default = /*#__PURE__*/_interopDefault(FormData);
|
|
30
33
|
var fetch__default = /*#__PURE__*/_interopDefault(fetch);
|
|
34
|
+
var os__default = /*#__PURE__*/_interopDefault(os);
|
|
35
|
+
var AdmZip__default = /*#__PURE__*/_interopDefault(AdmZip);
|
|
31
36
|
|
|
32
37
|
var __knownSymbol = (name, symbol) => (symbol = Symbol[name]) ? symbol : /* @__PURE__ */ Symbol.for("Symbol." + name);
|
|
33
38
|
var __forAwait = (obj, it, method) => (it = obj[__knownSymbol("asyncIterator")]) ? it.call(obj) : (obj = obj[__knownSymbol("iterator")](), it = {}, method = (key, fn) => (fn = obj[key]) && (it[key] = (arg) => new Promise((yes, no, done) => (arg = fn.call(obj, arg), done = arg.done, Promise.resolve(arg.value).then((value) => yes({ value, done }), no)))), method("next"), method("return"), it);
|
|
@@ -83,34 +88,7 @@ var Logger = class {
|
|
|
83
88
|
};
|
|
84
89
|
var logger = new Logger();
|
|
85
90
|
|
|
86
|
-
// src/utils/
|
|
87
|
-
function validateName(name) {
|
|
88
|
-
return /^[a-z0-9]+(-[a-z0-9]+)*$/.test(name);
|
|
89
|
-
}
|
|
90
|
-
function toKebabCase(str) {
|
|
91
|
-
return str.replace(/([a-z])([A-Z])/g, "$1-$2").replace(/[\s_]+/g, "-").toLowerCase();
|
|
92
|
-
}
|
|
93
|
-
function toPascalCase(str) {
|
|
94
|
-
return str.split(/[-_\s]+/).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join("");
|
|
95
|
-
}
|
|
96
|
-
function validateThemeName(name) {
|
|
97
|
-
return /^[a-z][a-z0-9-]*$/.test(name);
|
|
98
|
-
}
|
|
99
|
-
function getValidCategories() {
|
|
100
|
-
return [
|
|
101
|
-
"headers",
|
|
102
|
-
"heroes",
|
|
103
|
-
"content",
|
|
104
|
-
"features",
|
|
105
|
-
"testimonials",
|
|
106
|
-
"galleries",
|
|
107
|
-
"cta",
|
|
108
|
-
"footers",
|
|
109
|
-
"ecommerce",
|
|
110
|
-
"blog",
|
|
111
|
-
"contact"
|
|
112
|
-
];
|
|
113
|
-
}
|
|
91
|
+
// src/utils/file-helpers.ts
|
|
114
92
|
async function renderTemplate(templatePath, data) {
|
|
115
93
|
const template = await fs__default.default.readFile(templatePath, "utf-8");
|
|
116
94
|
return ejs__default.default.render(template, data);
|
|
@@ -195,18 +173,19 @@ function getProjectRoot() {
|
|
|
195
173
|
return process.cwd();
|
|
196
174
|
}
|
|
197
175
|
function getThemesDir() {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
return
|
|
176
|
+
const root = getProjectRoot();
|
|
177
|
+
const themesDir = path__default.default.join(root, "themes");
|
|
178
|
+
if (fs__default.default.existsSync(themesDir)) {
|
|
179
|
+
return themesDir;
|
|
202
180
|
}
|
|
181
|
+
return path__default.default.join(root, "src/themes");
|
|
203
182
|
}
|
|
204
183
|
function getFeaturesDir() {
|
|
205
184
|
return path__default.default.join(getProjectRoot(), "src/features");
|
|
206
185
|
}
|
|
207
186
|
function isOneXProject() {
|
|
208
187
|
const root = getProjectRoot();
|
|
209
|
-
return fs__default.default.existsSync(path__default.default.join(root, "
|
|
188
|
+
return fs__default.default.existsSync(path__default.default.join(root, "themes")) || fs__default.default.existsSync(path__default.default.join(root, "src/themes"));
|
|
210
189
|
}
|
|
211
190
|
function ensureOneXProject() {
|
|
212
191
|
if (!isOneXProject()) {
|
|
@@ -223,12 +202,12 @@ function listThemes() {
|
|
|
223
202
|
}
|
|
224
203
|
return fs__default.default.readdirSync(themesDir).filter((name) => {
|
|
225
204
|
const themePath = path__default.default.join(themesDir, name);
|
|
226
|
-
return fs__default.default.statSync(themePath).isDirectory() && fs__default.default.existsSync(path__default.default.join(themePath, "manifest.ts"));
|
|
205
|
+
return fs__default.default.statSync(themePath).isDirectory() && (fs__default.default.existsSync(path__default.default.join(themePath, "theme.config.ts")) || fs__default.default.existsSync(path__default.default.join(themePath, "bundle-entry.ts")) || fs__default.default.existsSync(path__default.default.join(themePath, "manifest.ts")));
|
|
227
206
|
});
|
|
228
207
|
}
|
|
229
208
|
function themeExists(themeName) {
|
|
230
209
|
const themePath = path__default.default.join(getThemesDir(), themeName);
|
|
231
|
-
return fs__default.default.existsSync(themePath) && fs__default.default.existsSync(path__default.default.join(themePath, "manifest.ts"));
|
|
210
|
+
return fs__default.default.existsSync(themePath) && (fs__default.default.existsSync(path__default.default.join(themePath, "theme.config.ts")) || fs__default.default.existsSync(path__default.default.join(themePath, "bundle-entry.ts")) || fs__default.default.existsSync(path__default.default.join(themePath, "manifest.ts")));
|
|
232
211
|
}
|
|
233
212
|
function detectPackageManager() {
|
|
234
213
|
const userAgent = process.env.npm_config_user_agent || "";
|
|
@@ -256,6 +235,35 @@ async function installDependencies(projectPath, packageManager = "npm") {
|
|
|
256
235
|
});
|
|
257
236
|
}
|
|
258
237
|
|
|
238
|
+
// src/utils/validators.ts
|
|
239
|
+
function validateName(name) {
|
|
240
|
+
return /^[a-z0-9]+(-[a-z0-9]+)*$/.test(name);
|
|
241
|
+
}
|
|
242
|
+
function toKebabCase(str) {
|
|
243
|
+
return str.replace(/([a-z])([A-Z])/g, "$1-$2").replace(/[\s_]+/g, "-").toLowerCase();
|
|
244
|
+
}
|
|
245
|
+
function toPascalCase(str) {
|
|
246
|
+
return str.split(/[-_\s]+/).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join("");
|
|
247
|
+
}
|
|
248
|
+
function validateThemeName(name) {
|
|
249
|
+
return /^[a-z][a-z0-9-]*$/.test(name);
|
|
250
|
+
}
|
|
251
|
+
function getValidCategories() {
|
|
252
|
+
return [
|
|
253
|
+
"headers",
|
|
254
|
+
"heroes",
|
|
255
|
+
"content",
|
|
256
|
+
"features",
|
|
257
|
+
"testimonials",
|
|
258
|
+
"galleries",
|
|
259
|
+
"cta",
|
|
260
|
+
"footers",
|
|
261
|
+
"ecommerce",
|
|
262
|
+
"blog",
|
|
263
|
+
"contact"
|
|
264
|
+
];
|
|
265
|
+
}
|
|
266
|
+
|
|
259
267
|
// src/commands/init.ts
|
|
260
268
|
async function initCommand(projectName, options = {}) {
|
|
261
269
|
logger.header("Create New OneX Theme Project");
|
|
@@ -422,7 +430,9 @@ Add your theme-specific blocks here.
|
|
|
422
430
|
logger.newLine();
|
|
423
431
|
logger.section("Theme structure:");
|
|
424
432
|
logger.log(" src/manifest.ts - Theme manifest and exports");
|
|
425
|
-
logger.log(
|
|
433
|
+
logger.log(
|
|
434
|
+
" src/config.ts - Design tokens (colors, typography, etc.)"
|
|
435
|
+
);
|
|
426
436
|
logger.log(" src/layout.ts - Header and footer configuration");
|
|
427
437
|
logger.log(" src/sections/ - Custom sections for your theme");
|
|
428
438
|
logger.log(" src/blocks/ - Reusable blocks");
|
|
@@ -1425,8 +1435,16 @@ async function listThemesInfo() {
|
|
|
1425
1435
|
}
|
|
1426
1436
|
logger.log("");
|
|
1427
1437
|
for (const theme of themes) {
|
|
1428
|
-
const
|
|
1429
|
-
const
|
|
1438
|
+
const themeDir = path__default.default.join(getThemesDir(), theme);
|
|
1439
|
+
const candidates = ["theme.config.ts", "bundle-entry.ts", "manifest.ts"];
|
|
1440
|
+
let manifestContent = "";
|
|
1441
|
+
for (const candidate of candidates) {
|
|
1442
|
+
const candidatePath = path__default.default.join(themeDir, candidate);
|
|
1443
|
+
if (fs__default.default.existsSync(candidatePath)) {
|
|
1444
|
+
manifestContent = fs__default.default.readFileSync(candidatePath, "utf-8");
|
|
1445
|
+
break;
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1430
1448
|
const nameMatch = manifestContent.match(/name:\s*["'](.+)["']/);
|
|
1431
1449
|
const versionMatch = manifestContent.match(/version:\s*["'](.+)["']/);
|
|
1432
1450
|
const descMatch = manifestContent.match(/description:\s*["'](.+)["']/);
|
|
@@ -1968,13 +1986,11 @@ function getS3Client() {
|
|
|
1968
1986
|
return new clientS3.S3Client({
|
|
1969
1987
|
endpoint: endpointUrl,
|
|
1970
1988
|
region: "us-east-1",
|
|
1971
|
-
// MinIO doesn't use real regions
|
|
1972
1989
|
credentials: {
|
|
1973
1990
|
accessKeyId: process.env.MINIO_ACCESS_KEY || "minioadmin",
|
|
1974
1991
|
secretAccessKey: process.env.MINIO_SECRET_KEY || "minioadmin"
|
|
1975
1992
|
},
|
|
1976
1993
|
forcePathStyle: true
|
|
1977
|
-
// Required for MinIO
|
|
1978
1994
|
});
|
|
1979
1995
|
}
|
|
1980
1996
|
if (adapterMode === "local") {
|
|
@@ -2044,36 +2060,40 @@ async function readManifest() {
|
|
|
2044
2060
|
"No manifest.ts or package.json found. Are you in a theme directory?"
|
|
2045
2061
|
);
|
|
2046
2062
|
}
|
|
2047
|
-
function
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
".ts": "text/plain"
|
|
2062
|
-
};
|
|
2063
|
-
return types[ext] || "application/octet-stream";
|
|
2063
|
+
async function createZipFromDir(sourceDir, outputPath, excludePatterns = []) {
|
|
2064
|
+
return new Promise((resolve, reject) => {
|
|
2065
|
+
const output = fs__default.default.createWriteStream(outputPath);
|
|
2066
|
+
const archive = archiver__default.default("zip", { zlib: { level: 6 } });
|
|
2067
|
+
output.on("close", () => resolve());
|
|
2068
|
+
archive.on("error", (err) => reject(err));
|
|
2069
|
+
archive.pipe(output);
|
|
2070
|
+
archive.glob("**/*", {
|
|
2071
|
+
cwd: sourceDir,
|
|
2072
|
+
dot: true,
|
|
2073
|
+
ignore: excludePatterns
|
|
2074
|
+
});
|
|
2075
|
+
archive.finalize();
|
|
2076
|
+
});
|
|
2064
2077
|
}
|
|
2065
|
-
async function
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
)
|
|
2078
|
+
async function findSourceDir(themeId, explicitDir) {
|
|
2079
|
+
if (explicitDir) {
|
|
2080
|
+
if (await fs__default.default.pathExists(explicitDir)) return explicitDir;
|
|
2081
|
+
return null;
|
|
2082
|
+
}
|
|
2083
|
+
const searchPaths = [
|
|
2084
|
+
process.cwd(),
|
|
2085
|
+
path__default.default.resolve(process.cwd(), `../../themes/${themeId}`),
|
|
2086
|
+
path__default.default.resolve(process.cwd(), `../themes/${themeId}`)
|
|
2087
|
+
];
|
|
2088
|
+
const markers = ["theme.config.ts", "bundle-entry.ts"];
|
|
2089
|
+
for (const dir of searchPaths) {
|
|
2090
|
+
for (const marker of markers) {
|
|
2091
|
+
if (await fs__default.default.pathExists(path__default.default.join(dir, marker))) {
|
|
2092
|
+
return dir;
|
|
2093
|
+
}
|
|
2094
|
+
}
|
|
2095
|
+
}
|
|
2096
|
+
return null;
|
|
2077
2097
|
}
|
|
2078
2098
|
async function updateLatestPointer(s3Client, bucket, themeId, version) {
|
|
2079
2099
|
const latestData = {
|
|
@@ -2091,12 +2111,18 @@ async function updateLatestPointer(s3Client, bucket, themeId, version) {
|
|
|
2091
2111
|
}
|
|
2092
2112
|
async function uploadCommand(options) {
|
|
2093
2113
|
logger.header("Upload Theme to S3");
|
|
2094
|
-
ensureOneXProject();
|
|
2095
2114
|
const spinner = ora__default.default("Preparing theme upload...").start();
|
|
2096
2115
|
try {
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2116
|
+
let themeId;
|
|
2117
|
+
let version;
|
|
2118
|
+
if (options.theme) {
|
|
2119
|
+
themeId = options.theme;
|
|
2120
|
+
version = options.version || "1.0.0";
|
|
2121
|
+
} else {
|
|
2122
|
+
const manifest = await readManifest();
|
|
2123
|
+
themeId = manifest.themeId;
|
|
2124
|
+
version = options.version || manifest.version || "1.0.0";
|
|
2125
|
+
}
|
|
2100
2126
|
spinner.text = `Found theme: ${themeId}@${version}`;
|
|
2101
2127
|
const bucket = options.bucket || getBucketName(options.environment);
|
|
2102
2128
|
const s3Client = getS3Client();
|
|
@@ -2117,67 +2143,113 @@ async function uploadCommand(options) {
|
|
|
2117
2143
|
process.exit(1);
|
|
2118
2144
|
}
|
|
2119
2145
|
spinner.succeed(`Found compiled theme at: ${compiledDir}`);
|
|
2120
|
-
spinner.start(
|
|
2121
|
-
const
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
spinner.fail(chalk4__default.default.red("No files found in compiled theme directory"));
|
|
2128
|
-
process.exit(1);
|
|
2129
|
-
}
|
|
2130
|
-
spinner.succeed(`Found ${files.length} files to upload`);
|
|
2146
|
+
spinner.start("Creating bundle.zip...");
|
|
2147
|
+
const tmpDir = os__default.default.tmpdir();
|
|
2148
|
+
const bundleZipPath = path__default.default.join(tmpDir, `${themeId}-${version}-bundle.zip`);
|
|
2149
|
+
await createZipFromDir(compiledDir, bundleZipPath);
|
|
2150
|
+
const bundleZipBuffer = await fs__default.default.readFile(bundleZipPath);
|
|
2151
|
+
const bundleSizeMB = (bundleZipBuffer.length / 1024 / 1024).toFixed(2);
|
|
2152
|
+
spinner.succeed(`Created bundle.zip (${bundleSizeMB} MB)`);
|
|
2131
2153
|
if (options.dryRun) {
|
|
2132
|
-
spinner.info(chalk4__default.default.yellow("Dry run mode
|
|
2133
|
-
console.log(
|
|
2134
|
-
|
|
2135
|
-
displayFiles.forEach((file) => console.log(chalk4__default.default.gray(` - ${file}`)));
|
|
2136
|
-
if (files.length > 10) {
|
|
2137
|
-
console.log(chalk4__default.default.gray(` ... and ${files.length - 10} more files
|
|
2138
|
-
`));
|
|
2139
|
-
}
|
|
2140
|
-
console.log(chalk4__default.default.cyan(`
|
|
2141
|
-
S3 bucket: ${bucket}`));
|
|
2154
|
+
spinner.info(chalk4__default.default.yellow("Dry run mode \u2014 no files will be uploaded"));
|
|
2155
|
+
console.log();
|
|
2156
|
+
console.log(chalk4__default.default.gray(` bundle.zip: ${bundleSizeMB} MB`));
|
|
2142
2157
|
console.log(
|
|
2143
|
-
chalk4__default.default.cyan(
|
|
2144
|
-
`
|
|
2158
|
+
chalk4__default.default.cyan(
|
|
2159
|
+
` S3 path: s3://${bucket}/themes/${themeId}/${version}/bundle.zip`
|
|
2160
|
+
)
|
|
2145
2161
|
);
|
|
2162
|
+
if (!options.skipSource) {
|
|
2163
|
+
const sourceDir = await findSourceDir(themeId, options.sourceDir);
|
|
2164
|
+
if (sourceDir) {
|
|
2165
|
+
console.log(chalk4__default.default.gray(` source dir: ${sourceDir}`));
|
|
2166
|
+
console.log(
|
|
2167
|
+
chalk4__default.default.cyan(
|
|
2168
|
+
` S3 path: s3://${bucket}/themes/${themeId}/${version}/source.zip`
|
|
2169
|
+
)
|
|
2170
|
+
);
|
|
2171
|
+
} else {
|
|
2172
|
+
console.log(
|
|
2173
|
+
chalk4__default.default.yellow(" source dir: not found (source.zip will be skipped)")
|
|
2174
|
+
);
|
|
2175
|
+
}
|
|
2176
|
+
}
|
|
2177
|
+
console.log();
|
|
2178
|
+
await fs__default.default.remove(bundleZipPath);
|
|
2146
2179
|
return;
|
|
2147
2180
|
}
|
|
2148
|
-
spinner.start(
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2181
|
+
spinner.start("Uploading bundle.zip to S3...");
|
|
2182
|
+
const bundleS3Key = `themes/${themeId}/${version}/bundle.zip`;
|
|
2183
|
+
await s3Client.send(
|
|
2184
|
+
new clientS3.PutObjectCommand({
|
|
2185
|
+
Bucket: bucket,
|
|
2186
|
+
Key: bundleS3Key,
|
|
2187
|
+
Body: bundleZipBuffer,
|
|
2188
|
+
ContentType: "application/zip"
|
|
2189
|
+
})
|
|
2190
|
+
);
|
|
2191
|
+
spinner.succeed(
|
|
2192
|
+
`Uploaded bundle.zip ${chalk4__default.default.gray(`\u2192 s3://${bucket}/${bundleS3Key}`)}`
|
|
2193
|
+
);
|
|
2194
|
+
await fs__default.default.remove(bundleZipPath);
|
|
2195
|
+
let sourceUploaded = false;
|
|
2196
|
+
if (!options.skipSource) {
|
|
2197
|
+
spinner.start("Looking for source directory...");
|
|
2198
|
+
const sourceDir = await findSourceDir(themeId, options.sourceDir);
|
|
2199
|
+
if (sourceDir) {
|
|
2200
|
+
spinner.succeed(`Found source at: ${sourceDir}`);
|
|
2201
|
+
spinner.start("Creating source.zip...");
|
|
2202
|
+
const sourceZipPath = path__default.default.join(
|
|
2203
|
+
tmpDir,
|
|
2204
|
+
`${themeId}-${version}-source.zip`
|
|
2205
|
+
);
|
|
2206
|
+
await createZipFromDir(sourceDir, sourceZipPath, [
|
|
2207
|
+
"node_modules/**",
|
|
2208
|
+
"dist/**",
|
|
2209
|
+
".git/**",
|
|
2210
|
+
"*.zip",
|
|
2211
|
+
".next/**",
|
|
2212
|
+
".turbo/**"
|
|
2213
|
+
]);
|
|
2214
|
+
const sourceZipBuffer = await fs__default.default.readFile(sourceZipPath);
|
|
2215
|
+
const sourceSizeMB = (sourceZipBuffer.length / 1024 / 1024).toFixed(2);
|
|
2216
|
+
spinner.succeed(`Created source.zip (${sourceSizeMB} MB)`);
|
|
2217
|
+
spinner.start("Uploading source.zip to S3...");
|
|
2218
|
+
const sourceS3Key = `themes/${themeId}/${version}/source.zip`;
|
|
2219
|
+
await s3Client.send(
|
|
2220
|
+
new clientS3.PutObjectCommand({
|
|
2221
|
+
Bucket: bucket,
|
|
2222
|
+
Key: sourceS3Key,
|
|
2223
|
+
Body: sourceZipBuffer,
|
|
2224
|
+
ContentType: "application/zip"
|
|
2225
|
+
})
|
|
2226
|
+
);
|
|
2227
|
+
spinner.succeed(
|
|
2228
|
+
`Uploaded source.zip ${chalk4__default.default.gray(`\u2192 s3://${bucket}/${sourceS3Key}`)}`
|
|
2229
|
+
);
|
|
2230
|
+
await fs__default.default.remove(sourceZipPath);
|
|
2231
|
+
sourceUploaded = true;
|
|
2232
|
+
} else {
|
|
2233
|
+
spinner.warn(
|
|
2234
|
+
chalk4__default.default.yellow("Source directory not found \u2014 skipping source.zip")
|
|
2235
|
+
);
|
|
2236
|
+
}
|
|
2168
2237
|
}
|
|
2169
|
-
spinner.succeed(`Uploaded ${total} files to S3`);
|
|
2170
2238
|
spinner.start("Updating latest.json pointer...");
|
|
2171
2239
|
await updateLatestPointer(s3Client, bucket, themeId, version);
|
|
2172
2240
|
spinner.succeed("Updated latest.json pointer");
|
|
2173
2241
|
console.log();
|
|
2174
|
-
logger.success(chalk4__default.default.green.bold("
|
|
2242
|
+
logger.success(chalk4__default.default.green.bold("Theme uploaded successfully!"));
|
|
2175
2243
|
console.log();
|
|
2176
2244
|
console.log(
|
|
2177
2245
|
chalk4__default.default.cyan(" Theme: ") + chalk4__default.default.white(`${themeId}@${version}`)
|
|
2178
2246
|
);
|
|
2179
2247
|
console.log(chalk4__default.default.cyan(" Bucket: ") + chalk4__default.default.white(bucket));
|
|
2180
|
-
console.log(
|
|
2248
|
+
console.log(
|
|
2249
|
+
chalk4__default.default.cyan(" Files: ") + chalk4__default.default.white(
|
|
2250
|
+
`bundle.zip${sourceUploaded ? " + source.zip" : ""}`
|
|
2251
|
+
)
|
|
2252
|
+
);
|
|
2181
2253
|
console.log(
|
|
2182
2254
|
chalk4__default.default.cyan(" Path: ") + chalk4__default.default.gray(`s3://${bucket}/themes/${themeId}/${version}/`)
|
|
2183
2255
|
);
|
|
@@ -2281,79 +2353,45 @@ async function resolveLatestVersion(s3Client, bucket, themeId) {
|
|
|
2281
2353
|
);
|
|
2282
2354
|
}
|
|
2283
2355
|
}
|
|
2284
|
-
async function
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
`Failed to download manifest for ${themeId}@${version}: ${error.message}
|
|
2297
|
-
The theme may not exist in S3 bucket "${bucket}".`
|
|
2298
|
-
);
|
|
2299
|
-
}
|
|
2300
|
-
}
|
|
2301
|
-
async function downloadFile(s3Client, bucket, themeId, version, file, outputDir) {
|
|
2302
|
-
const s3Key = `themes/${themeId}/${version}/${file}`;
|
|
2303
|
-
const localPath = path__default.default.join(outputDir, file);
|
|
2304
|
-
await fs__default.default.ensureDir(path__default.default.dirname(localPath));
|
|
2305
|
-
try {
|
|
2306
|
-
const response = await s3Client.send(
|
|
2307
|
-
new clientS3.GetObjectCommand({
|
|
2308
|
-
Bucket: bucket,
|
|
2309
|
-
Key: s3Key
|
|
2310
|
-
})
|
|
2311
|
-
);
|
|
2312
|
-
const content = await streamToBuffer(response.Body);
|
|
2313
|
-
await fs__default.default.writeFile(localPath, content);
|
|
2314
|
-
} catch (error) {
|
|
2315
|
-
throw new Error(`Failed to download ${file}: ${error.message}`);
|
|
2316
|
-
}
|
|
2317
|
-
}
|
|
2318
|
-
function collectFilesToDownload(manifest) {
|
|
2319
|
-
const files = ["manifest.json"];
|
|
2320
|
-
if (manifest.output) {
|
|
2321
|
-
if (manifest.output.entry) {
|
|
2322
|
-
files.push(manifest.output.entry);
|
|
2323
|
-
}
|
|
2324
|
-
if (manifest.output.chunks) {
|
|
2325
|
-
files.push(...manifest.output.chunks);
|
|
2326
|
-
}
|
|
2327
|
-
if (manifest.output.assets) {
|
|
2328
|
-
files.push(...manifest.output.assets);
|
|
2356
|
+
async function createCompatibilityFiles(outputDir, manifest) {
|
|
2357
|
+
var _a;
|
|
2358
|
+
const entryFile = ((_a = manifest.output) == null ? void 0 : _a.entry) || "bundle-entry.js";
|
|
2359
|
+
if (entryFile !== "bundle-entry.js" && entryFile.startsWith("bundle-entry-")) {
|
|
2360
|
+
const hashedPath = path__default.default.join(outputDir, entryFile);
|
|
2361
|
+
const stablePath = path__default.default.join(outputDir, "bundle-entry.js");
|
|
2362
|
+
if (await fs__default.default.pathExists(hashedPath)) {
|
|
2363
|
+
await fs__default.default.copy(hashedPath, stablePath);
|
|
2364
|
+
const mapPath = hashedPath + ".map";
|
|
2365
|
+
if (await fs__default.default.pathExists(mapPath)) {
|
|
2366
|
+
await fs__default.default.copy(mapPath, stablePath + ".map");
|
|
2367
|
+
}
|
|
2329
2368
|
}
|
|
2330
2369
|
}
|
|
2331
|
-
return files;
|
|
2332
|
-
}
|
|
2333
|
-
async function createCompatibilityFiles(outputDir) {
|
|
2334
2370
|
const sectionsRegistryPath = path__default.default.join(outputDir, "sections-registry.js");
|
|
2335
2371
|
const content = `// Re-export all sections from bundle-entry
|
|
2336
2372
|
// This file exists to maintain compatibility with the import path
|
|
2337
2373
|
export * from './bundle-entry.js';
|
|
2338
2374
|
`;
|
|
2339
2375
|
await fs__default.default.writeFile(sectionsRegistryPath, content, "utf-8");
|
|
2376
|
+
const pkgJsonPath = path__default.default.join(outputDir, "package.json");
|
|
2377
|
+
await fs__default.default.writeFile(pkgJsonPath, '{\n "type": "module"\n}\n', "utf-8");
|
|
2340
2378
|
}
|
|
2341
2379
|
function showDownloadFailureHelp(themeId, bucket) {
|
|
2342
2380
|
console.log();
|
|
2343
|
-
logger.error(chalk4__default.default.red.bold("
|
|
2381
|
+
logger.error(chalk4__default.default.red.bold("Theme download failed"));
|
|
2344
2382
|
console.log();
|
|
2345
2383
|
console.log(chalk4__default.default.yellow("Possible reasons:"));
|
|
2346
2384
|
console.log(chalk4__default.default.gray(" 1. Theme not uploaded to S3 yet"));
|
|
2347
2385
|
console.log(chalk4__default.default.gray(" 2. AWS credentials not configured correctly"));
|
|
2348
2386
|
console.log(chalk4__default.default.gray(" 3. Bucket name or region is incorrect"));
|
|
2349
|
-
console.log(chalk4__default.default.gray(" 4.
|
|
2387
|
+
console.log(chalk4__default.default.gray(" 4. bundle.zip is missing or corrupted"));
|
|
2350
2388
|
console.log();
|
|
2351
2389
|
console.log(chalk4__default.default.cyan.bold("To fix this:"));
|
|
2352
2390
|
console.log();
|
|
2353
2391
|
console.log(chalk4__default.default.white("1. Compile and upload the theme:"));
|
|
2354
2392
|
console.log(chalk4__default.default.gray(` cd themes/${themeId}`));
|
|
2355
2393
|
console.log(chalk4__default.default.gray(" pnpm build"));
|
|
2356
|
-
console.log(chalk4__default.default.gray("
|
|
2394
|
+
console.log(chalk4__default.default.gray(" onex upload"));
|
|
2357
2395
|
console.log();
|
|
2358
2396
|
console.log(chalk4__default.default.white("2. Verify AWS credentials are set:"));
|
|
2359
2397
|
console.log(
|
|
@@ -2369,7 +2407,11 @@ function showDownloadFailureHelp(themeId, bucket) {
|
|
|
2369
2407
|
);
|
|
2370
2408
|
console.log();
|
|
2371
2409
|
console.log(chalk4__default.default.white("4. Verify theme exists in S3:"));
|
|
2372
|
-
console.log(
|
|
2410
|
+
console.log(
|
|
2411
|
+
chalk4__default.default.gray(
|
|
2412
|
+
` aws s3 ls s3://${bucket}/themes/${themeId}/`
|
|
2413
|
+
)
|
|
2414
|
+
);
|
|
2373
2415
|
console.log();
|
|
2374
2416
|
}
|
|
2375
2417
|
async function downloadCommand(options) {
|
|
@@ -2397,55 +2439,44 @@ async function downloadCommand(options) {
|
|
|
2397
2439
|
spinner.succeed(
|
|
2398
2440
|
`Resolved latest version: ${chalk4__default.default.cyan(resolvedVersion)}`
|
|
2399
2441
|
);
|
|
2400
|
-
spinner.start("Downloading manifest...");
|
|
2401
2442
|
}
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2443
|
+
spinner.start(
|
|
2444
|
+
`Downloading bundle.zip for ${themeId}@${resolvedVersion}...`
|
|
2445
|
+
);
|
|
2446
|
+
const s3Key = `themes/${themeId}/${resolvedVersion}/bundle.zip`;
|
|
2447
|
+
const response = await s3Client.send(
|
|
2448
|
+
new clientS3.GetObjectCommand({
|
|
2449
|
+
Bucket: bucket,
|
|
2450
|
+
Key: s3Key
|
|
2451
|
+
})
|
|
2407
2452
|
);
|
|
2408
|
-
|
|
2409
|
-
|
|
2453
|
+
const zipBuffer = await streamToBuffer(response.Body);
|
|
2454
|
+
const sizeMB = (zipBuffer.length / 1024 / 1024).toFixed(2);
|
|
2455
|
+
spinner.succeed(`Downloaded bundle.zip (${sizeMB} MB)`);
|
|
2456
|
+
spinner.start("Extracting bundle...");
|
|
2410
2457
|
await fs__default.default.remove(outputDir);
|
|
2411
2458
|
await fs__default.default.ensureDir(outputDir);
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
const
|
|
2415
|
-
|
|
2416
|
-
const
|
|
2417
|
-
const
|
|
2418
|
-
|
|
2419
|
-
const batch = files.slice(i, i + batchSize);
|
|
2420
|
-
await Promise.all(
|
|
2421
|
-
batch.map(async (file) => {
|
|
2422
|
-
await downloadFile(
|
|
2423
|
-
s3Client,
|
|
2424
|
-
bucket,
|
|
2425
|
-
themeId,
|
|
2426
|
-
resolvedVersion,
|
|
2427
|
-
file,
|
|
2428
|
-
outputDir
|
|
2429
|
-
);
|
|
2430
|
-
downloaded++;
|
|
2431
|
-
spinner.text = `Downloading... ${downloaded}/${total} files (${Math.round(downloaded / total * 100)}%)`;
|
|
2432
|
-
})
|
|
2433
|
-
);
|
|
2434
|
-
}
|
|
2435
|
-
spinner.succeed(`Downloaded ${total} files`);
|
|
2436
|
-
await createCompatibilityFiles(outputDir);
|
|
2459
|
+
const zip = new AdmZip__default.default(zipBuffer);
|
|
2460
|
+
zip.extractAllTo(outputDir, true);
|
|
2461
|
+
const entries = zip.getEntries().filter((e) => !e.isDirectory);
|
|
2462
|
+
spinner.succeed(`Extracted ${entries.length} files to ${outputDir}`);
|
|
2463
|
+
const manifestPath = path__default.default.join(outputDir, "manifest.json");
|
|
2464
|
+
const manifest = await fs__default.default.readJson(manifestPath);
|
|
2465
|
+
await createCompatibilityFiles(outputDir, manifest);
|
|
2437
2466
|
console.log();
|
|
2438
|
-
logger.success(chalk4__default.default.green.bold("
|
|
2467
|
+
logger.success(chalk4__default.default.green.bold("Theme downloaded successfully!"));
|
|
2439
2468
|
console.log();
|
|
2440
2469
|
console.log(
|
|
2441
2470
|
chalk4__default.default.cyan(" Theme: ") + chalk4__default.default.white(`${themeId}@${resolvedVersion}`)
|
|
2442
2471
|
);
|
|
2443
2472
|
console.log(chalk4__default.default.cyan(" Bucket: ") + chalk4__default.default.white(bucket));
|
|
2444
2473
|
console.log(chalk4__default.default.cyan(" Output: ") + chalk4__default.default.white(outputDir));
|
|
2445
|
-
console.log(chalk4__default.default.cyan(" Files: ") + chalk4__default.default.white(
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2474
|
+
console.log(chalk4__default.default.cyan(" Files: ") + chalk4__default.default.white(entries.length));
|
|
2475
|
+
if (manifest.counts) {
|
|
2476
|
+
console.log(
|
|
2477
|
+
chalk4__default.default.cyan(" Sections:") + chalk4__default.default.white(` ${manifest.counts.sections}`)
|
|
2478
|
+
);
|
|
2479
|
+
}
|
|
2449
2480
|
console.log();
|
|
2450
2481
|
} catch (error) {
|
|
2451
2482
|
spinner.fail(chalk4__default.default.red("Download failed"));
|
|
@@ -2456,8 +2487,215 @@ async function downloadCommand(options) {
|
|
|
2456
2487
|
process.exit(1);
|
|
2457
2488
|
}
|
|
2458
2489
|
}
|
|
2490
|
+
function getS3Client3() {
|
|
2491
|
+
const adapterMode = (process.env.ADAPTER_MODE || "aws").trim().toLowerCase();
|
|
2492
|
+
if (adapterMode === "vps") {
|
|
2493
|
+
const endpoint = process.env.MINIO_ENDPOINT || "localhost:9000";
|
|
2494
|
+
const secure = process.env.MINIO_SECURE === "true";
|
|
2495
|
+
const endpointUrl = endpoint.startsWith("http") ? endpoint : `${secure ? "https" : "http"}://${endpoint}`;
|
|
2496
|
+
return new clientS3.S3Client({
|
|
2497
|
+
endpoint: endpointUrl,
|
|
2498
|
+
region: "us-east-1",
|
|
2499
|
+
credentials: {
|
|
2500
|
+
accessKeyId: process.env.MINIO_ACCESS_KEY || "minioadmin",
|
|
2501
|
+
secretAccessKey: process.env.MINIO_SECRET_KEY || "minioadmin"
|
|
2502
|
+
},
|
|
2503
|
+
forcePathStyle: true
|
|
2504
|
+
});
|
|
2505
|
+
}
|
|
2506
|
+
if (adapterMode === "local") {
|
|
2507
|
+
return new clientS3.S3Client({
|
|
2508
|
+
endpoint: "http://localhost:4569",
|
|
2509
|
+
region: "ap-southeast-1",
|
|
2510
|
+
credentials: {
|
|
2511
|
+
accessKeyId: "S3RVER",
|
|
2512
|
+
secretAccessKey: "S3RVER"
|
|
2513
|
+
},
|
|
2514
|
+
forcePathStyle: true
|
|
2515
|
+
});
|
|
2516
|
+
}
|
|
2517
|
+
return new clientS3.S3Client({
|
|
2518
|
+
region: process.env.AWS_REGION || "ap-southeast-1"
|
|
2519
|
+
});
|
|
2520
|
+
}
|
|
2521
|
+
function getBucketName3(env) {
|
|
2522
|
+
if (process.env.BUCKET_NAME) {
|
|
2523
|
+
return process.env.BUCKET_NAME;
|
|
2524
|
+
}
|
|
2525
|
+
const environment = env || process.env.ENVIRONMENT || "staging";
|
|
2526
|
+
return environment === "production" ? "onex-themes-prod" : "onex-themes-staging";
|
|
2527
|
+
}
|
|
2528
|
+
async function streamToString2(stream) {
|
|
2529
|
+
const chunks = [];
|
|
2530
|
+
try {
|
|
2531
|
+
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
|
|
2532
|
+
const chunk = temp.value;
|
|
2533
|
+
chunks.push(Buffer.from(chunk));
|
|
2534
|
+
}
|
|
2535
|
+
} catch (temp) {
|
|
2536
|
+
error = [temp];
|
|
2537
|
+
} finally {
|
|
2538
|
+
try {
|
|
2539
|
+
more && (temp = iter.return) && await temp.call(iter);
|
|
2540
|
+
} finally {
|
|
2541
|
+
if (error)
|
|
2542
|
+
throw error[0];
|
|
2543
|
+
}
|
|
2544
|
+
}
|
|
2545
|
+
return Buffer.concat(chunks).toString("utf-8");
|
|
2546
|
+
}
|
|
2547
|
+
async function streamToBuffer2(stream) {
|
|
2548
|
+
const chunks = [];
|
|
2549
|
+
try {
|
|
2550
|
+
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
|
|
2551
|
+
const chunk = temp.value;
|
|
2552
|
+
chunks.push(Buffer.from(chunk));
|
|
2553
|
+
}
|
|
2554
|
+
} catch (temp) {
|
|
2555
|
+
error = [temp];
|
|
2556
|
+
} finally {
|
|
2557
|
+
try {
|
|
2558
|
+
more && (temp = iter.return) && await temp.call(iter);
|
|
2559
|
+
} finally {
|
|
2560
|
+
if (error)
|
|
2561
|
+
throw error[0];
|
|
2562
|
+
}
|
|
2563
|
+
}
|
|
2564
|
+
return Buffer.concat(chunks);
|
|
2565
|
+
}
|
|
2566
|
+
async function resolveLatestVersion2(s3Client, bucket, themeId) {
|
|
2567
|
+
try {
|
|
2568
|
+
const response = await s3Client.send(
|
|
2569
|
+
new clientS3.GetObjectCommand({
|
|
2570
|
+
Bucket: bucket,
|
|
2571
|
+
Key: `themes/${themeId}/latest.json`
|
|
2572
|
+
})
|
|
2573
|
+
);
|
|
2574
|
+
const body = await streamToString2(response.Body);
|
|
2575
|
+
return JSON.parse(body).version;
|
|
2576
|
+
} catch (error) {
|
|
2577
|
+
throw new Error(
|
|
2578
|
+
`Failed to resolve latest version for theme "${themeId}": ${error.message}`
|
|
2579
|
+
);
|
|
2580
|
+
}
|
|
2581
|
+
}
|
|
2582
|
+
function runInstall(cwd) {
|
|
2583
|
+
return new Promise((resolve) => {
|
|
2584
|
+
const proc = child_process.spawn("pnpm", ["install"], {
|
|
2585
|
+
cwd,
|
|
2586
|
+
stdio: "inherit",
|
|
2587
|
+
shell: true
|
|
2588
|
+
});
|
|
2589
|
+
proc.on("close", (code) => resolve(code === 0));
|
|
2590
|
+
proc.on("error", () => resolve(false));
|
|
2591
|
+
});
|
|
2592
|
+
}
|
|
2593
|
+
async function cloneCommand(themeName, options) {
|
|
2594
|
+
logger.header("Clone Theme Source");
|
|
2595
|
+
const spinner = ora__default.default("Initializing clone...").start();
|
|
2596
|
+
try {
|
|
2597
|
+
const bucket = options.bucket || getBucketName3(options.environment);
|
|
2598
|
+
const outputDir = options.output || path__default.default.resolve(process.cwd(), themeName);
|
|
2599
|
+
const s3Client = getS3Client3();
|
|
2600
|
+
if (await fs__default.default.pathExists(outputDir)) {
|
|
2601
|
+
spinner.fail(
|
|
2602
|
+
chalk4__default.default.red(`Directory already exists: ${outputDir}`)
|
|
2603
|
+
);
|
|
2604
|
+
logger.info(
|
|
2605
|
+
chalk4__default.default.gray(
|
|
2606
|
+
"Use -o to specify a different output directory, or remove the existing directory."
|
|
2607
|
+
)
|
|
2608
|
+
);
|
|
2609
|
+
process.exit(1);
|
|
2610
|
+
}
|
|
2611
|
+
let version = options.version || "latest";
|
|
2612
|
+
if (version === "latest") {
|
|
2613
|
+
spinner.text = "Resolving latest version...";
|
|
2614
|
+
version = await resolveLatestVersion2(s3Client, bucket, themeName);
|
|
2615
|
+
spinner.succeed(`Resolved latest version: ${chalk4__default.default.cyan(version)}`);
|
|
2616
|
+
}
|
|
2617
|
+
spinner.start(
|
|
2618
|
+
`Downloading source.zip for ${themeName}@${version}...`
|
|
2619
|
+
);
|
|
2620
|
+
const s3Key = `themes/${themeName}/${version}/source.zip`;
|
|
2621
|
+
let zipBuffer;
|
|
2622
|
+
try {
|
|
2623
|
+
const response = await s3Client.send(
|
|
2624
|
+
new clientS3.GetObjectCommand({
|
|
2625
|
+
Bucket: bucket,
|
|
2626
|
+
Key: s3Key
|
|
2627
|
+
})
|
|
2628
|
+
);
|
|
2629
|
+
zipBuffer = await streamToBuffer2(response.Body);
|
|
2630
|
+
} catch (error) {
|
|
2631
|
+
spinner.fail(chalk4__default.default.red(`Source not found: s3://${bucket}/${s3Key}`));
|
|
2632
|
+
console.log();
|
|
2633
|
+
console.log(
|
|
2634
|
+
chalk4__default.default.yellow("The theme source may not have been uploaded yet.")
|
|
2635
|
+
);
|
|
2636
|
+
console.log(
|
|
2637
|
+
chalk4__default.default.gray(
|
|
2638
|
+
`Upload source with: onex upload --theme ${themeName}`
|
|
2639
|
+
)
|
|
2640
|
+
);
|
|
2641
|
+
console.log();
|
|
2642
|
+
process.exit(1);
|
|
2643
|
+
}
|
|
2644
|
+
const sizeMB = (zipBuffer.length / 1024 / 1024).toFixed(2);
|
|
2645
|
+
spinner.succeed(`Downloaded source.zip (${sizeMB} MB)`);
|
|
2646
|
+
spinner.start(`Extracting to ${outputDir}...`);
|
|
2647
|
+
await fs__default.default.ensureDir(outputDir);
|
|
2648
|
+
const zip = new AdmZip__default.default(zipBuffer);
|
|
2649
|
+
zip.extractAllTo(outputDir, true);
|
|
2650
|
+
const entries = zip.getEntries().filter((e) => !e.isDirectory);
|
|
2651
|
+
spinner.succeed(`Extracted ${entries.length} files`);
|
|
2652
|
+
if (options.install !== false) {
|
|
2653
|
+
const hasPkgJson = await fs__default.default.pathExists(
|
|
2654
|
+
path__default.default.join(outputDir, "package.json")
|
|
2655
|
+
);
|
|
2656
|
+
if (hasPkgJson) {
|
|
2657
|
+
spinner.start("Installing dependencies...");
|
|
2658
|
+
const success = await runInstall(outputDir);
|
|
2659
|
+
if (success) {
|
|
2660
|
+
spinner.succeed("Dependencies installed");
|
|
2661
|
+
} else {
|
|
2662
|
+
spinner.warn(
|
|
2663
|
+
chalk4__default.default.yellow(
|
|
2664
|
+
"Failed to install dependencies \u2014 run 'pnpm install' manually"
|
|
2665
|
+
)
|
|
2666
|
+
);
|
|
2667
|
+
}
|
|
2668
|
+
}
|
|
2669
|
+
}
|
|
2670
|
+
console.log();
|
|
2671
|
+
logger.success(chalk4__default.default.green.bold("Theme cloned successfully!"));
|
|
2672
|
+
console.log();
|
|
2673
|
+
console.log(
|
|
2674
|
+
chalk4__default.default.cyan(" Theme: ") + chalk4__default.default.white(`${themeName}@${version}`)
|
|
2675
|
+
);
|
|
2676
|
+
console.log(chalk4__default.default.cyan(" Location: ") + chalk4__default.default.white(outputDir));
|
|
2677
|
+
console.log(chalk4__default.default.cyan(" Files: ") + chalk4__default.default.white(entries.length));
|
|
2678
|
+
console.log();
|
|
2679
|
+
console.log(chalk4__default.default.cyan("Next steps:"));
|
|
2680
|
+
console.log(
|
|
2681
|
+
chalk4__default.default.gray(` cd ${path__default.default.relative(process.cwd(), outputDir)}`)
|
|
2682
|
+
);
|
|
2683
|
+
if (options.install === false) {
|
|
2684
|
+
console.log(chalk4__default.default.gray(" pnpm install"));
|
|
2685
|
+
}
|
|
2686
|
+
console.log(chalk4__default.default.gray(" onex build"));
|
|
2687
|
+
console.log();
|
|
2688
|
+
} catch (error) {
|
|
2689
|
+
spinner.fail(chalk4__default.default.red(`Clone failed: ${error.message}`));
|
|
2690
|
+
logger.error(error.stack || error.message);
|
|
2691
|
+
process.exit(1);
|
|
2692
|
+
}
|
|
2693
|
+
}
|
|
2459
2694
|
|
|
2460
2695
|
// src/cli.ts
|
|
2696
|
+
var projectRoot = getProjectRoot();
|
|
2697
|
+
dotenv__default.default.config({ path: path__default.default.join(projectRoot, ".env.local"), quiet: true });
|
|
2698
|
+
dotenv__default.default.config({ path: path__default.default.join(projectRoot, ".env"), quiet: true });
|
|
2461
2699
|
var program = new commander.Command();
|
|
2462
2700
|
program.name("onex").description("CLI tool for OneX theme development").version("0.1.0");
|
|
2463
2701
|
program.command("init").description("Create a new OneX theme project").argument("[project-name]", "Name of the project").option(
|
|
@@ -2489,7 +2727,7 @@ program.command("upload").description("Upload compiled theme to S3 bucket").opti
|
|
|
2489
2727
|
"-e, --environment <env>",
|
|
2490
2728
|
"Environment (staging|production)",
|
|
2491
2729
|
"staging"
|
|
2492
|
-
).option("--dry-run", "Show what would be uploaded without uploading").action(uploadCommand);
|
|
2730
|
+
).option("--dry-run", "Show what would be uploaded without uploading").option("--skip-source", "Skip uploading source.zip").option("--source-dir <dir>", "Source directory path").action(uploadCommand);
|
|
2493
2731
|
program.command("download").description("Download theme from S3 bucket").option("-t, --theme-id <id>", "Theme ID to download").option(
|
|
2494
2732
|
"-v, --version <version>",
|
|
2495
2733
|
"Theme version (default: latest)",
|
|
@@ -2499,6 +2737,15 @@ program.command("download").description("Download theme from S3 bucket").option(
|
|
|
2499
2737
|
"Environment (staging|production)",
|
|
2500
2738
|
"staging"
|
|
2501
2739
|
).option("-o, --output <dir>", "Output directory", "./active-theme").action(downloadCommand);
|
|
2740
|
+
program.command("clone").description("Clone theme source code from S3").argument("<theme-name>", "Theme to clone").option(
|
|
2741
|
+
"-v, --version <version>",
|
|
2742
|
+
"Theme version (default: latest)",
|
|
2743
|
+
"latest"
|
|
2744
|
+
).option("-o, --output <dir>", "Output directory").option("-b, --bucket <name>", "S3 bucket name").option(
|
|
2745
|
+
"-e, --environment <env>",
|
|
2746
|
+
"Environment (staging|production)",
|
|
2747
|
+
"staging"
|
|
2748
|
+
).option("--no-install", "Skip running pnpm install after clone").action(cloneCommand);
|
|
2502
2749
|
program.configureOutput({
|
|
2503
2750
|
writeErr: (str) => process.stderr.write(chalk4__default.default.red(str))
|
|
2504
2751
|
});
|