@hapico/cli 0.0.21 → 0.0.23
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/bin/index.js +75 -24
- package/dist/index.js +75 -24
- package/index.ts +114 -34
- package/package.json +1 -1
package/bin/index.js
CHANGED
|
@@ -123,6 +123,18 @@ const tryJSONParse = (str) => {
|
|
|
123
123
|
}
|
|
124
124
|
};
|
|
125
125
|
exports.tryJSONParse = tryJSONParse;
|
|
126
|
+
// only support .ts, .tsx, .js, .jsx, .json, .css, .html, .env files
|
|
127
|
+
const supportedExtensions = [
|
|
128
|
+
".ts",
|
|
129
|
+
".tsx",
|
|
130
|
+
".js",
|
|
131
|
+
".jsx",
|
|
132
|
+
".json",
|
|
133
|
+
".css",
|
|
134
|
+
".html",
|
|
135
|
+
".env",
|
|
136
|
+
];
|
|
137
|
+
const ignoreFolders = ["node_modules", ".git", ".hg", ".svn"];
|
|
126
138
|
const compileES5 = (code, filePath) => {
|
|
127
139
|
if (filePath && !filePath.endsWith(".ts") && !filePath.endsWith(".tsx")) {
|
|
128
140
|
return code;
|
|
@@ -143,7 +155,7 @@ const compileES5 = (code, filePath) => {
|
|
|
143
155
|
return result.code;
|
|
144
156
|
}
|
|
145
157
|
catch (error) {
|
|
146
|
-
console.log(chalk_1.default.red(`Error compiling code
|
|
158
|
+
console.log(chalk_1.default.red(`Error compiling code at ${filePath}`));
|
|
147
159
|
return "";
|
|
148
160
|
}
|
|
149
161
|
};
|
|
@@ -172,12 +184,23 @@ class FileManager {
|
|
|
172
184
|
traverseDirectory(fullPath);
|
|
173
185
|
}
|
|
174
186
|
else if (entry.isFile()) {
|
|
187
|
+
// skip các file trong thư mục bị ignore
|
|
188
|
+
if (ignoreFolders.some((folder) => fullPath.includes(folder))) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
// chỉ hổ trợ các files nằm trong ./src
|
|
192
|
+
if (!fullPath.includes("/src/") && !fullPath.includes("\\src\\")) {
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
175
195
|
const content = fs.readFileSync(fullPath, { encoding: "utf8" });
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
196
|
+
const extname = path.extname(fullPath);
|
|
197
|
+
if (supportedExtensions.includes(extname)) {
|
|
198
|
+
files.push({
|
|
199
|
+
path: this.replaceSplashWithSeparator(fullPath.replace(this.basePath + path.sep, "./")),
|
|
200
|
+
content,
|
|
201
|
+
es5: (_a = (0, exports.compileES5)(content, fullPath)) !== null && _a !== void 0 ? _a : "",
|
|
202
|
+
});
|
|
203
|
+
}
|
|
181
204
|
}
|
|
182
205
|
});
|
|
183
206
|
};
|
|
@@ -371,12 +394,12 @@ class RoomState {
|
|
|
371
394
|
return this.isConnected;
|
|
372
395
|
}
|
|
373
396
|
}
|
|
374
|
-
commander_1.program.version("0.0.
|
|
397
|
+
commander_1.program.version("0.0.23").description("Hapico CLI for project management");
|
|
375
398
|
commander_1.program
|
|
376
399
|
.command("clone <id>")
|
|
377
400
|
.description("Clone a project by ID")
|
|
378
401
|
.action(async (id) => {
|
|
379
|
-
var _a, _b;
|
|
402
|
+
var _a, _b, _c, _d;
|
|
380
403
|
const { accessToken } = getStoredToken();
|
|
381
404
|
if (!accessToken) {
|
|
382
405
|
console.error(chalk_1.default.red("✗ You need to login first. Use 'hapico login' command."));
|
|
@@ -390,11 +413,13 @@ commander_1.program
|
|
|
390
413
|
let files = [];
|
|
391
414
|
const apiSpinner = (0, ora_1.default)(chalk_1.default.blue("Fetching project data...")).start();
|
|
392
415
|
try {
|
|
416
|
+
// ===== 1. Lấy version public/published (giữ nguyên như cũ) =====
|
|
393
417
|
const response = await axios_1.default.get(`https://base.myworkbeast.com/api/views/${id}`);
|
|
394
418
|
const code = (_a = response === null || response === void 0 ? void 0 : response.data) === null || _a === void 0 ? void 0 : _a.code;
|
|
395
419
|
const decompressedCode = pako_1.default.inflate(Uint8Array.from(atob(code), (c) => c.charCodeAt(0)), { to: "string" });
|
|
396
420
|
files = ((_b = (0, exports.tryJSONParse)(decompressedCode)) === null || _b === void 0 ? void 0 : _b.files) || [];
|
|
397
421
|
apiSpinner.succeed(chalk_1.default.green("Project data fetched successfully!"));
|
|
422
|
+
// ===== 2. Download + extract template =====
|
|
398
423
|
const templateSpinner = (0, ora_1.default)(chalk_1.default.blue("Downloading template...")).start();
|
|
399
424
|
const TEMPLATE_URL = "https://files.hcm04.vstorage.vngcloud.vn/assets/template_zalominiapp_devmode.zip";
|
|
400
425
|
const templateResponse = await axios_1.default.get(TEMPLATE_URL, {
|
|
@@ -412,9 +437,10 @@ commander_1.program
|
|
|
412
437
|
if (fs.existsSync(macosxDir)) {
|
|
413
438
|
fs.rmSync(macosxDir, { recursive: true, force: true });
|
|
414
439
|
}
|
|
415
|
-
// Save project ID
|
|
440
|
+
// Save project ID
|
|
416
441
|
saveProjectId(outputDir, id);
|
|
417
442
|
console.log(chalk_1.default.green("Project cloned successfully!"));
|
|
443
|
+
// ===== 3. Save file từ version public =====
|
|
418
444
|
const saveSpinner = (0, ora_1.default)(chalk_1.default.blue("Saving project files...")).start();
|
|
419
445
|
files.forEach((file) => {
|
|
420
446
|
const filePath = path.join(process.cwd(), id, "src", file.path);
|
|
@@ -425,6 +451,31 @@ commander_1.program
|
|
|
425
451
|
fs.writeFileSync(filePath, file.content);
|
|
426
452
|
});
|
|
427
453
|
saveSpinner.succeed(chalk_1.default.green("Project files saved successfully!"));
|
|
454
|
+
// ===== 4. TỰ ĐỘNG PULL PHIÊN BẢN MỚI NHẤT (draft) – ĐÂY LÀ PHẦN MỚI =====
|
|
455
|
+
const pullSpinner = (0, ora_1.default)(chalk_1.default.blue("Pulling latest changes from server...")).start();
|
|
456
|
+
try {
|
|
457
|
+
const pullResponse = await axios_1.default.get(`https://base.myworkbeast.com/api/views/v3/${id}`, {
|
|
458
|
+
headers: {
|
|
459
|
+
Authorization: `Bearer ${accessToken}`,
|
|
460
|
+
"Content-Type": "application/json",
|
|
461
|
+
},
|
|
462
|
+
});
|
|
463
|
+
const pullCode = (_c = pullResponse === null || pullResponse === void 0 ? void 0 : pullResponse.data) === null || _c === void 0 ? void 0 : _c.code;
|
|
464
|
+
if (!pullCode) {
|
|
465
|
+
pullSpinner.info(chalk_1.default.cyan("No draft version found – using published version."));
|
|
466
|
+
}
|
|
467
|
+
else {
|
|
468
|
+
const pullDecompressed = pako_1.default.inflate(Uint8Array.from(atob(pullCode), (c) => c.charCodeAt(0)), { to: "string" });
|
|
469
|
+
const latestFiles = ((_d = (0, exports.tryJSONParse)(pullDecompressed)) === null || _d === void 0 ? void 0 : _d.files) || [];
|
|
470
|
+
const fileManager = new FileManager(path.join(outputDir, "src"));
|
|
471
|
+
fileManager.syncFiles(latestFiles);
|
|
472
|
+
pullSpinner.succeed(chalk_1.default.green("✓ Latest changes pulled successfully!"));
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
catch (pullErr) {
|
|
476
|
+
pullSpinner.warn(chalk_1.default.yellow(`⚠ Could not pull latest changes: ${pullErr.message}\n Run "hapico pull" manually later.`));
|
|
477
|
+
}
|
|
478
|
+
// ===== 5. Hướng dẫn chạy dev =====
|
|
428
479
|
console.log(chalk_1.default.cyan(`💡 Run ${chalk_1.default.bold("cd ${id} && npm install && hapico dev")} to start the project.`));
|
|
429
480
|
}
|
|
430
481
|
catch (error) {
|
|
@@ -434,7 +485,7 @@ commander_1.program
|
|
|
434
485
|
commander_1.program
|
|
435
486
|
.command("dev")
|
|
436
487
|
.description("Start the project in development mode")
|
|
437
|
-
.option(
|
|
488
|
+
.option("--zversion <version>", "Zalo version for QR code")
|
|
438
489
|
.action((options) => {
|
|
439
490
|
var _a;
|
|
440
491
|
const { accessToken } = getStoredToken();
|
|
@@ -507,19 +558,10 @@ commander_1.program
|
|
|
507
558
|
".jsx",
|
|
508
559
|
".json",
|
|
509
560
|
".css",
|
|
510
|
-
".html",
|
|
511
561
|
".env",
|
|
512
562
|
".env.local",
|
|
513
563
|
".env.development",
|
|
514
564
|
".env.production",
|
|
515
|
-
".jsonc",
|
|
516
|
-
".yml",
|
|
517
|
-
".yaml",
|
|
518
|
-
".md",
|
|
519
|
-
".markdown",
|
|
520
|
-
".txt",
|
|
521
|
-
".xml",
|
|
522
|
-
".config",
|
|
523
565
|
];
|
|
524
566
|
const filteredFiles = initialFiles.filter((file) => {
|
|
525
567
|
return supportExtensions.some((ext) => file.path.endsWith(ext));
|
|
@@ -558,12 +600,21 @@ commander_1.program
|
|
|
558
600
|
return;
|
|
559
601
|
}
|
|
560
602
|
const projectType = project.data.type || "view";
|
|
561
|
-
const zversion = options.zversion
|
|
603
|
+
const zversion = options.zversion;
|
|
562
604
|
if (projectType === "zalominiapp") {
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
605
|
+
console.log("zversion", zversion);
|
|
606
|
+
if (!zversion) {
|
|
607
|
+
qrcode_terminal_1.default.generate(`https://zalo.me/s/3218692650896662017/player/${projectId}`, { small: true }, (qrcode) => {
|
|
608
|
+
console.log(chalk_1.default.cyan("📱 Scan this QR code to connect to the project:"));
|
|
609
|
+
console.log(qrcode);
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
else {
|
|
613
|
+
qrcode_terminal_1.default.generate(`https://zalo.me/s/3218692650896662017/player/${projectId}?env=TESTING&version=${zversion}`, { small: true }, (qrcode) => {
|
|
614
|
+
console.log(chalk_1.default.cyan("📱 Scan this QR code to connect to the project:"));
|
|
615
|
+
console.log(qrcode);
|
|
616
|
+
});
|
|
617
|
+
}
|
|
567
618
|
return;
|
|
568
619
|
}
|
|
569
620
|
else {
|
package/dist/index.js
CHANGED
|
@@ -123,6 +123,18 @@ const tryJSONParse = (str) => {
|
|
|
123
123
|
}
|
|
124
124
|
};
|
|
125
125
|
exports.tryJSONParse = tryJSONParse;
|
|
126
|
+
// only support .ts, .tsx, .js, .jsx, .json, .css, .html, .env files
|
|
127
|
+
const supportedExtensions = [
|
|
128
|
+
".ts",
|
|
129
|
+
".tsx",
|
|
130
|
+
".js",
|
|
131
|
+
".jsx",
|
|
132
|
+
".json",
|
|
133
|
+
".css",
|
|
134
|
+
".html",
|
|
135
|
+
".env",
|
|
136
|
+
];
|
|
137
|
+
const ignoreFolders = ["node_modules", ".git", ".hg", ".svn"];
|
|
126
138
|
const compileES5 = (code, filePath) => {
|
|
127
139
|
if (filePath && !filePath.endsWith(".ts") && !filePath.endsWith(".tsx")) {
|
|
128
140
|
return code;
|
|
@@ -143,7 +155,7 @@ const compileES5 = (code, filePath) => {
|
|
|
143
155
|
return result.code;
|
|
144
156
|
}
|
|
145
157
|
catch (error) {
|
|
146
|
-
console.log(chalk_1.default.red(`Error compiling code
|
|
158
|
+
console.log(chalk_1.default.red(`Error compiling code at ${filePath}`));
|
|
147
159
|
return "";
|
|
148
160
|
}
|
|
149
161
|
};
|
|
@@ -172,12 +184,23 @@ class FileManager {
|
|
|
172
184
|
traverseDirectory(fullPath);
|
|
173
185
|
}
|
|
174
186
|
else if (entry.isFile()) {
|
|
187
|
+
// skip các file trong thư mục bị ignore
|
|
188
|
+
if (ignoreFolders.some((folder) => fullPath.includes(folder))) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
// chỉ hổ trợ các files nằm trong ./src
|
|
192
|
+
if (!fullPath.includes("/src/") && !fullPath.includes("\\src\\")) {
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
175
195
|
const content = fs.readFileSync(fullPath, { encoding: "utf8" });
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
196
|
+
const extname = path.extname(fullPath);
|
|
197
|
+
if (supportedExtensions.includes(extname)) {
|
|
198
|
+
files.push({
|
|
199
|
+
path: this.replaceSplashWithSeparator(fullPath.replace(this.basePath + path.sep, "./")),
|
|
200
|
+
content,
|
|
201
|
+
es5: (_a = (0, exports.compileES5)(content, fullPath)) !== null && _a !== void 0 ? _a : "",
|
|
202
|
+
});
|
|
203
|
+
}
|
|
181
204
|
}
|
|
182
205
|
});
|
|
183
206
|
};
|
|
@@ -371,12 +394,12 @@ class RoomState {
|
|
|
371
394
|
return this.isConnected;
|
|
372
395
|
}
|
|
373
396
|
}
|
|
374
|
-
commander_1.program.version("0.0.
|
|
397
|
+
commander_1.program.version("0.0.23").description("Hapico CLI for project management");
|
|
375
398
|
commander_1.program
|
|
376
399
|
.command("clone <id>")
|
|
377
400
|
.description("Clone a project by ID")
|
|
378
401
|
.action(async (id) => {
|
|
379
|
-
var _a, _b;
|
|
402
|
+
var _a, _b, _c, _d;
|
|
380
403
|
const { accessToken } = getStoredToken();
|
|
381
404
|
if (!accessToken) {
|
|
382
405
|
console.error(chalk_1.default.red("✗ You need to login first. Use 'hapico login' command."));
|
|
@@ -390,11 +413,13 @@ commander_1.program
|
|
|
390
413
|
let files = [];
|
|
391
414
|
const apiSpinner = (0, ora_1.default)(chalk_1.default.blue("Fetching project data...")).start();
|
|
392
415
|
try {
|
|
416
|
+
// ===== 1. Lấy version public/published (giữ nguyên như cũ) =====
|
|
393
417
|
const response = await axios_1.default.get(`https://base.myworkbeast.com/api/views/${id}`);
|
|
394
418
|
const code = (_a = response === null || response === void 0 ? void 0 : response.data) === null || _a === void 0 ? void 0 : _a.code;
|
|
395
419
|
const decompressedCode = pako_1.default.inflate(Uint8Array.from(atob(code), (c) => c.charCodeAt(0)), { to: "string" });
|
|
396
420
|
files = ((_b = (0, exports.tryJSONParse)(decompressedCode)) === null || _b === void 0 ? void 0 : _b.files) || [];
|
|
397
421
|
apiSpinner.succeed(chalk_1.default.green("Project data fetched successfully!"));
|
|
422
|
+
// ===== 2. Download + extract template =====
|
|
398
423
|
const templateSpinner = (0, ora_1.default)(chalk_1.default.blue("Downloading template...")).start();
|
|
399
424
|
const TEMPLATE_URL = "https://files.hcm04.vstorage.vngcloud.vn/assets/template_zalominiapp_devmode.zip";
|
|
400
425
|
const templateResponse = await axios_1.default.get(TEMPLATE_URL, {
|
|
@@ -412,9 +437,10 @@ commander_1.program
|
|
|
412
437
|
if (fs.existsSync(macosxDir)) {
|
|
413
438
|
fs.rmSync(macosxDir, { recursive: true, force: true });
|
|
414
439
|
}
|
|
415
|
-
// Save project ID
|
|
440
|
+
// Save project ID
|
|
416
441
|
saveProjectId(outputDir, id);
|
|
417
442
|
console.log(chalk_1.default.green("Project cloned successfully!"));
|
|
443
|
+
// ===== 3. Save file từ version public =====
|
|
418
444
|
const saveSpinner = (0, ora_1.default)(chalk_1.default.blue("Saving project files...")).start();
|
|
419
445
|
files.forEach((file) => {
|
|
420
446
|
const filePath = path.join(process.cwd(), id, "src", file.path);
|
|
@@ -425,6 +451,31 @@ commander_1.program
|
|
|
425
451
|
fs.writeFileSync(filePath, file.content);
|
|
426
452
|
});
|
|
427
453
|
saveSpinner.succeed(chalk_1.default.green("Project files saved successfully!"));
|
|
454
|
+
// ===== 4. TỰ ĐỘNG PULL PHIÊN BẢN MỚI NHẤT (draft) – ĐÂY LÀ PHẦN MỚI =====
|
|
455
|
+
const pullSpinner = (0, ora_1.default)(chalk_1.default.blue("Pulling latest changes from server...")).start();
|
|
456
|
+
try {
|
|
457
|
+
const pullResponse = await axios_1.default.get(`https://base.myworkbeast.com/api/views/v3/${id}`, {
|
|
458
|
+
headers: {
|
|
459
|
+
Authorization: `Bearer ${accessToken}`,
|
|
460
|
+
"Content-Type": "application/json",
|
|
461
|
+
},
|
|
462
|
+
});
|
|
463
|
+
const pullCode = (_c = pullResponse === null || pullResponse === void 0 ? void 0 : pullResponse.data) === null || _c === void 0 ? void 0 : _c.code;
|
|
464
|
+
if (!pullCode) {
|
|
465
|
+
pullSpinner.info(chalk_1.default.cyan("No draft version found – using published version."));
|
|
466
|
+
}
|
|
467
|
+
else {
|
|
468
|
+
const pullDecompressed = pako_1.default.inflate(Uint8Array.from(atob(pullCode), (c) => c.charCodeAt(0)), { to: "string" });
|
|
469
|
+
const latestFiles = ((_d = (0, exports.tryJSONParse)(pullDecompressed)) === null || _d === void 0 ? void 0 : _d.files) || [];
|
|
470
|
+
const fileManager = new FileManager(path.join(outputDir, "src"));
|
|
471
|
+
fileManager.syncFiles(latestFiles);
|
|
472
|
+
pullSpinner.succeed(chalk_1.default.green("✓ Latest changes pulled successfully!"));
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
catch (pullErr) {
|
|
476
|
+
pullSpinner.warn(chalk_1.default.yellow(`⚠ Could not pull latest changes: ${pullErr.message}\n Run "hapico pull" manually later.`));
|
|
477
|
+
}
|
|
478
|
+
// ===== 5. Hướng dẫn chạy dev =====
|
|
428
479
|
console.log(chalk_1.default.cyan(`💡 Run ${chalk_1.default.bold("cd ${id} && npm install && hapico dev")} to start the project.`));
|
|
429
480
|
}
|
|
430
481
|
catch (error) {
|
|
@@ -434,7 +485,7 @@ commander_1.program
|
|
|
434
485
|
commander_1.program
|
|
435
486
|
.command("dev")
|
|
436
487
|
.description("Start the project in development mode")
|
|
437
|
-
.option(
|
|
488
|
+
.option("--zversion <version>", "Zalo version for QR code")
|
|
438
489
|
.action((options) => {
|
|
439
490
|
var _a;
|
|
440
491
|
const { accessToken } = getStoredToken();
|
|
@@ -507,19 +558,10 @@ commander_1.program
|
|
|
507
558
|
".jsx",
|
|
508
559
|
".json",
|
|
509
560
|
".css",
|
|
510
|
-
".html",
|
|
511
561
|
".env",
|
|
512
562
|
".env.local",
|
|
513
563
|
".env.development",
|
|
514
564
|
".env.production",
|
|
515
|
-
".jsonc",
|
|
516
|
-
".yml",
|
|
517
|
-
".yaml",
|
|
518
|
-
".md",
|
|
519
|
-
".markdown",
|
|
520
|
-
".txt",
|
|
521
|
-
".xml",
|
|
522
|
-
".config",
|
|
523
565
|
];
|
|
524
566
|
const filteredFiles = initialFiles.filter((file) => {
|
|
525
567
|
return supportExtensions.some((ext) => file.path.endsWith(ext));
|
|
@@ -558,12 +600,21 @@ commander_1.program
|
|
|
558
600
|
return;
|
|
559
601
|
}
|
|
560
602
|
const projectType = project.data.type || "view";
|
|
561
|
-
const zversion = options.zversion
|
|
603
|
+
const zversion = options.zversion;
|
|
562
604
|
if (projectType === "zalominiapp") {
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
605
|
+
console.log("zversion", zversion);
|
|
606
|
+
if (!zversion) {
|
|
607
|
+
qrcode_terminal_1.default.generate(`https://zalo.me/s/3218692650896662017/player/${projectId}`, { small: true }, (qrcode) => {
|
|
608
|
+
console.log(chalk_1.default.cyan("📱 Scan this QR code to connect to the project:"));
|
|
609
|
+
console.log(qrcode);
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
else {
|
|
613
|
+
qrcode_terminal_1.default.generate(`https://zalo.me/s/3218692650896662017/player/${projectId}?env=TESTING&version=${zversion}`, { small: true }, (qrcode) => {
|
|
614
|
+
console.log(chalk_1.default.cyan("📱 Scan this QR code to connect to the project:"));
|
|
615
|
+
console.log(qrcode);
|
|
616
|
+
});
|
|
617
|
+
}
|
|
567
618
|
return;
|
|
568
619
|
}
|
|
569
620
|
else {
|
package/index.ts
CHANGED
|
@@ -130,6 +130,20 @@ export const tryJSONParse = (str: string): any => {
|
|
|
130
130
|
}
|
|
131
131
|
};
|
|
132
132
|
|
|
133
|
+
// only support .ts, .tsx, .js, .jsx, .json, .css, .html, .env files
|
|
134
|
+
const supportedExtensions = [
|
|
135
|
+
".ts",
|
|
136
|
+
".tsx",
|
|
137
|
+
".js",
|
|
138
|
+
".jsx",
|
|
139
|
+
".json",
|
|
140
|
+
".css",
|
|
141
|
+
".html",
|
|
142
|
+
".env",
|
|
143
|
+
];
|
|
144
|
+
|
|
145
|
+
const ignoreFolders = ["node_modules", ".git", ".hg", ".svn"];
|
|
146
|
+
|
|
133
147
|
export const compileES5 = (code: string, filePath?: string) => {
|
|
134
148
|
if (filePath && !filePath.endsWith(".ts") && !filePath.endsWith(".tsx")) {
|
|
135
149
|
return code;
|
|
@@ -151,7 +165,7 @@ export const compileES5 = (code: string, filePath?: string) => {
|
|
|
151
165
|
compileCache.set(code, result.code || "");
|
|
152
166
|
return result.code;
|
|
153
167
|
} catch (error: any) {
|
|
154
|
-
console.log(chalk.red(`Error compiling code
|
|
168
|
+
console.log(chalk.red(`Error compiling code at ${filePath}`));
|
|
155
169
|
return "";
|
|
156
170
|
}
|
|
157
171
|
};
|
|
@@ -188,14 +202,27 @@ class FileManager {
|
|
|
188
202
|
if (entry.isDirectory()) {
|
|
189
203
|
traverseDirectory(fullPath);
|
|
190
204
|
} else if (entry.isFile()) {
|
|
205
|
+
// skip các file trong thư mục bị ignore
|
|
206
|
+
if (ignoreFolders.some((folder) => fullPath.includes(folder))) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// chỉ hổ trợ các files nằm trong ./src
|
|
211
|
+
if (!fullPath.includes("/src/") && !fullPath.includes("\\src\\")) {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
|
|
191
215
|
const content = fs.readFileSync(fullPath, { encoding: "utf8" });
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
216
|
+
const extname = path.extname(fullPath);
|
|
217
|
+
if (supportedExtensions.includes(extname)) {
|
|
218
|
+
files.push({
|
|
219
|
+
path: this.replaceSplashWithSeparator(
|
|
220
|
+
fullPath.replace(this.basePath + path.sep, "./")
|
|
221
|
+
),
|
|
222
|
+
content,
|
|
223
|
+
es5: compileES5(content, fullPath) ?? "",
|
|
224
|
+
});
|
|
225
|
+
}
|
|
199
226
|
}
|
|
200
227
|
});
|
|
201
228
|
};
|
|
@@ -447,7 +474,7 @@ class RoomState {
|
|
|
447
474
|
}
|
|
448
475
|
}
|
|
449
476
|
|
|
450
|
-
program.version("0.0.
|
|
477
|
+
program.version("0.0.23").description("Hapico CLI for project management");
|
|
451
478
|
|
|
452
479
|
program
|
|
453
480
|
.command("clone <id>")
|
|
@@ -470,17 +497,19 @@ program
|
|
|
470
497
|
const apiSpinner: Ora = ora(chalk.blue("Fetching project data...")).start();
|
|
471
498
|
|
|
472
499
|
try {
|
|
500
|
+
// ===== 1. Lấy version public/published (giữ nguyên như cũ) =====
|
|
473
501
|
const response: ApiResponse = await axios.get(
|
|
474
502
|
`https://base.myworkbeast.com/api/views/${id}`
|
|
475
503
|
);
|
|
476
504
|
const code = response?.data?.code;
|
|
477
505
|
const decompressedCode = pako.inflate(
|
|
478
|
-
Uint8Array.from(atob(code), (c) => c.charCodeAt(0)),
|
|
506
|
+
Uint8Array.from(atob(code), (c) => c.charCodeAt(0)),
|
|
479
507
|
{ to: "string" }
|
|
480
508
|
);
|
|
481
509
|
files = tryJSONParse(decompressedCode)?.files || [];
|
|
482
510
|
apiSpinner.succeed(chalk.green("Project data fetched successfully!"));
|
|
483
511
|
|
|
512
|
+
// ===== 2. Download + extract template =====
|
|
484
513
|
const templateSpinner: Ora = ora(
|
|
485
514
|
chalk.blue("Downloading template...")
|
|
486
515
|
).start();
|
|
@@ -509,11 +538,11 @@ program
|
|
|
509
538
|
fs.rmSync(macosxDir, { recursive: true, force: true });
|
|
510
539
|
}
|
|
511
540
|
|
|
512
|
-
// Save project ID
|
|
541
|
+
// Save project ID
|
|
513
542
|
saveProjectId(outputDir, id);
|
|
514
|
-
|
|
515
543
|
console.log(chalk.green("Project cloned successfully!"));
|
|
516
544
|
|
|
545
|
+
// ===== 3. Save file từ version public =====
|
|
517
546
|
const saveSpinner: Ora = ora(
|
|
518
547
|
chalk.blue("Saving project files...")
|
|
519
548
|
).start();
|
|
@@ -528,6 +557,52 @@ program
|
|
|
528
557
|
fs.writeFileSync(filePath, file.content);
|
|
529
558
|
});
|
|
530
559
|
saveSpinner.succeed(chalk.green("Project files saved successfully!"));
|
|
560
|
+
|
|
561
|
+
// ===== 4. TỰ ĐỘNG PULL PHIÊN BẢN MỚI NHẤT (draft) – ĐÂY LÀ PHẦN MỚI =====
|
|
562
|
+
const pullSpinner: Ora = ora(
|
|
563
|
+
chalk.blue("Pulling latest changes from server...")
|
|
564
|
+
).start();
|
|
565
|
+
|
|
566
|
+
try {
|
|
567
|
+
const pullResponse = await axios.get(
|
|
568
|
+
`https://base.myworkbeast.com/api/views/v3/${id}`,
|
|
569
|
+
{
|
|
570
|
+
headers: {
|
|
571
|
+
Authorization: `Bearer ${accessToken}`,
|
|
572
|
+
"Content-Type": "application/json",
|
|
573
|
+
},
|
|
574
|
+
}
|
|
575
|
+
);
|
|
576
|
+
|
|
577
|
+
const pullCode = pullResponse?.data?.code;
|
|
578
|
+
if (!pullCode) {
|
|
579
|
+
pullSpinner.info(
|
|
580
|
+
chalk.cyan("No draft version found – using published version.")
|
|
581
|
+
);
|
|
582
|
+
} else {
|
|
583
|
+
const pullDecompressed = pako.inflate(
|
|
584
|
+
Uint8Array.from(atob(pullCode), (c) => c.charCodeAt(0)),
|
|
585
|
+
{ to: "string" }
|
|
586
|
+
);
|
|
587
|
+
const latestFiles: FileContent[] =
|
|
588
|
+
tryJSONParse(pullDecompressed)?.files || [];
|
|
589
|
+
|
|
590
|
+
const fileManager = new FileManager(path.join(outputDir, "src"));
|
|
591
|
+
fileManager.syncFiles(latestFiles);
|
|
592
|
+
|
|
593
|
+
pullSpinner.succeed(
|
|
594
|
+
chalk.green("✓ Latest changes pulled successfully!")
|
|
595
|
+
);
|
|
596
|
+
}
|
|
597
|
+
} catch (pullErr: any) {
|
|
598
|
+
pullSpinner.warn(
|
|
599
|
+
chalk.yellow(
|
|
600
|
+
`⚠ Could not pull latest changes: ${pullErr.message}\n Run "hapico pull" manually later.`
|
|
601
|
+
)
|
|
602
|
+
);
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
// ===== 5. Hướng dẫn chạy dev =====
|
|
531
606
|
console.log(
|
|
532
607
|
chalk.cyan(
|
|
533
608
|
`💡 Run ${chalk.bold("cd ${id} && npm install && hapico dev")} to start the project.`
|
|
@@ -541,7 +616,7 @@ program
|
|
|
541
616
|
program
|
|
542
617
|
.command("dev")
|
|
543
618
|
.description("Start the project in development mode")
|
|
544
|
-
.option(
|
|
619
|
+
.option("--zversion <version>", "Zalo version for QR code")
|
|
545
620
|
.action((options) => {
|
|
546
621
|
const { accessToken } = getStoredToken();
|
|
547
622
|
if (!accessToken) {
|
|
@@ -637,19 +712,10 @@ program
|
|
|
637
712
|
".jsx",
|
|
638
713
|
".json",
|
|
639
714
|
".css",
|
|
640
|
-
".html",
|
|
641
715
|
".env",
|
|
642
716
|
".env.local",
|
|
643
717
|
".env.development",
|
|
644
718
|
".env.production",
|
|
645
|
-
".jsonc",
|
|
646
|
-
".yml",
|
|
647
|
-
".yaml",
|
|
648
|
-
".md",
|
|
649
|
-
".markdown",
|
|
650
|
-
".txt",
|
|
651
|
-
".xml",
|
|
652
|
-
".config",
|
|
653
719
|
];
|
|
654
720
|
const filteredFiles = initialFiles.filter((file) => {
|
|
655
721
|
return supportExtensions.some((ext) => file.path.endsWith(ext));
|
|
@@ -705,19 +771,33 @@ program
|
|
|
705
771
|
}
|
|
706
772
|
|
|
707
773
|
const projectType = project.data.type || "view";
|
|
708
|
-
const zversion = options.zversion
|
|
774
|
+
const zversion = options.zversion;
|
|
709
775
|
|
|
710
776
|
if (projectType === "zalominiapp") {
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
777
|
+
console.log("zversion", zversion);
|
|
778
|
+
if (!zversion) {
|
|
779
|
+
QRCode.generate(
|
|
780
|
+
`https://zalo.me/s/3218692650896662017/player/${projectId}`,
|
|
781
|
+
{ small: true },
|
|
782
|
+
(qrcode) => {
|
|
783
|
+
console.log(
|
|
784
|
+
chalk.cyan("📱 Scan this QR code to connect to the project:")
|
|
785
|
+
);
|
|
786
|
+
console.log(qrcode);
|
|
787
|
+
}
|
|
788
|
+
);
|
|
789
|
+
} else {
|
|
790
|
+
QRCode.generate(
|
|
791
|
+
`https://zalo.me/s/3218692650896662017/player/${projectId}?env=TESTING&version=${zversion}`,
|
|
792
|
+
{ small: true },
|
|
793
|
+
(qrcode) => {
|
|
794
|
+
console.log(
|
|
795
|
+
chalk.cyan("📱 Scan this QR code to connect to the project:")
|
|
796
|
+
);
|
|
797
|
+
console.log(qrcode);
|
|
798
|
+
}
|
|
799
|
+
);
|
|
800
|
+
}
|
|
721
801
|
return;
|
|
722
802
|
} else {
|
|
723
803
|
const previewUrl = `https://com.ai.vn/dev_preview/${projectId}`;
|
|
@@ -1490,4 +1570,4 @@ ${file.content}
|
|
|
1490
1570
|
console.log(chalk.green(`✓ File list saved to ${outputFile}`));
|
|
1491
1571
|
});
|
|
1492
1572
|
|
|
1493
|
-
program.parse(process.argv);
|
|
1573
|
+
program.parse(process.argv);
|