@lark-apaas/fullstack-cli 1.1.6-alpha.12 → 1.1.6-alpha.14

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/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/index.ts
2
- import fs14 from "fs";
3
- import path14 from "path";
2
+ import fs18 from "fs";
3
+ import path16 from "path";
4
4
  import { fileURLToPath as fileURLToPath3 } from "url";
5
5
  import { config as dotenvConfig } from "dotenv";
6
6
 
@@ -168,15 +168,15 @@ async function run(options = {}) {
168
168
  console.error("[gen-db-schema] schema.ts not generated");
169
169
  throw new Error("drizzle-kit introspect failed to generate schema.ts");
170
170
  }
171
- fs.mkdirSync(path.dirname(SCHEMA_FILE), { recursive: true });
172
- fs.copyFileSync(generatedSchema, SCHEMA_FILE);
173
- console.log(`[gen-db-schema] \u2713 Copied to ${outputPath}`);
174
171
  const { postprocessDrizzleSchema } = require2("@lark-apaas/devtool-kits");
175
- const stats = postprocessDrizzleSchema(SCHEMA_FILE);
172
+ const stats = postprocessDrizzleSchema(generatedSchema);
176
173
  if (stats?.unmatchedUnknown?.length) {
177
174
  console.warn("[gen-db-schema] Unmatched custom types detected:", stats.unmatchedUnknown);
178
175
  }
179
176
  console.log("[gen-db-schema] \u2713 Postprocessed schema");
177
+ fs.mkdirSync(path.dirname(SCHEMA_FILE), { recursive: true });
178
+ fs.copyFileSync(generatedSchema, SCHEMA_FILE);
179
+ console.log(`[gen-db-schema] \u2713 Copied to ${outputPath}`);
180
180
  try {
181
181
  if (options.enableNestModuleGenerate) {
182
182
  const { parseAndGenerateNestResourceTemplate } = require2("@lark-apaas/devtool-kits");
@@ -216,8 +216,8 @@ var genDbSchemaCommand = {
216
216
  };
217
217
 
218
218
  // src/commands/sync/run.handler.ts
219
- import path2 from "path";
220
- import fs2 from "fs";
219
+ import path3 from "path";
220
+ import fs3 from "fs";
221
221
  import { fileURLToPath as fileURLToPath2 } from "url";
222
222
 
223
223
  // src/config/sync.ts
@@ -254,6 +254,12 @@ var syncConfig = {
254
254
  type: "delete-directory",
255
255
  to: ".swc"
256
256
  // 删除 .swc 目录(如果存在)
257
+ },
258
+ // 4. 从 .gitignore 中移除 package-lock.json
259
+ {
260
+ type: "remove-line",
261
+ to: ".gitignore",
262
+ pattern: "package-lock.json"
257
263
  }
258
264
  ],
259
265
  // 文件权限设置
@@ -274,18 +280,39 @@ function genSyncConfig(perms = {}) {
274
280
  return syncConfig;
275
281
  }
276
282
 
283
+ // src/utils/file-ops.ts
284
+ import fs2 from "fs";
285
+ import path2 from "path";
286
+ function removeLineFromFile(filePath, pattern) {
287
+ if (!fs2.existsSync(filePath)) {
288
+ console.log(`[fullstack-cli] \u25CB ${path2.basename(filePath)} (not found)`);
289
+ return false;
290
+ }
291
+ const content = fs2.readFileSync(filePath, "utf-8");
292
+ const lines = content.split("\n");
293
+ const trimmedPattern = pattern.trim();
294
+ const filteredLines = lines.filter((line) => line.trim() !== trimmedPattern);
295
+ if (filteredLines.length === lines.length) {
296
+ console.log(`[fullstack-cli] \u25CB ${path2.basename(filePath)} (pattern not found: ${pattern})`);
297
+ return false;
298
+ }
299
+ fs2.writeFileSync(filePath, filteredLines.join("\n"));
300
+ console.log(`[fullstack-cli] \u2713 ${path2.basename(filePath)} (removed: ${pattern})`);
301
+ return true;
302
+ }
303
+
277
304
  // src/commands/sync/run.handler.ts
278
305
  async function run2(options) {
279
306
  const userProjectRoot = process.env.INIT_CWD || process.cwd();
280
307
  const __filename = fileURLToPath2(import.meta.url);
281
- const __dirname2 = path2.dirname(__filename);
282
- const pluginRoot = path2.resolve(__dirname2, "..");
308
+ const __dirname2 = path3.dirname(__filename);
309
+ const pluginRoot = path3.resolve(__dirname2, "..");
283
310
  if (userProjectRoot === pluginRoot) {
284
311
  console.log("[fullstack-cli] Skip syncing (installing plugin itself)");
285
312
  process.exit(0);
286
313
  }
287
- const userPackageJson = path2.join(userProjectRoot, "package.json");
288
- if (!fs2.existsSync(userPackageJson)) {
314
+ const userPackageJson = path3.join(userProjectRoot, "package.json");
315
+ if (!fs3.existsSync(userPackageJson)) {
289
316
  console.log("[fullstack-cli] Skip syncing (not a valid npm project)");
290
317
  process.exit(0);
291
318
  }
@@ -313,7 +340,7 @@ async function run2(options) {
313
340
  }
314
341
  async function syncRule(rule, pluginRoot, userProjectRoot) {
315
342
  if (rule.type === "delete-file" || rule.type === "delete-directory") {
316
- const destPath2 = path2.join(userProjectRoot, rule.to);
343
+ const destPath2 = path3.join(userProjectRoot, rule.to);
317
344
  if (rule.type === "delete-file") {
318
345
  deleteFile(destPath2);
319
346
  } else {
@@ -321,12 +348,17 @@ async function syncRule(rule, pluginRoot, userProjectRoot) {
321
348
  }
322
349
  return;
323
350
  }
351
+ if (rule.type === "remove-line") {
352
+ const destPath2 = path3.join(userProjectRoot, rule.to);
353
+ removeLineFromFile(destPath2, rule.pattern);
354
+ return;
355
+ }
324
356
  if (!("from" in rule)) {
325
357
  return;
326
358
  }
327
- const srcPath = path2.join(pluginRoot, rule.from);
328
- const destPath = path2.join(userProjectRoot, rule.to);
329
- if (!fs2.existsSync(srcPath)) {
359
+ const srcPath = path3.join(pluginRoot, rule.from);
360
+ const destPath = path3.join(userProjectRoot, rule.to);
361
+ if (!fs3.existsSync(srcPath)) {
330
362
  console.warn(`[fullstack-cli] Source not found: ${rule.from}`);
331
363
  return;
332
364
  }
@@ -343,64 +375,64 @@ async function syncRule(rule, pluginRoot, userProjectRoot) {
343
375
  }
344
376
  }
345
377
  function syncFile(src, dest, overwrite = true) {
346
- const destDir = path2.dirname(dest);
347
- if (!fs2.existsSync(destDir)) {
348
- fs2.mkdirSync(destDir, { recursive: true });
378
+ const destDir = path3.dirname(dest);
379
+ if (!fs3.existsSync(destDir)) {
380
+ fs3.mkdirSync(destDir, { recursive: true });
349
381
  }
350
- if (fs2.existsSync(dest) && !overwrite) {
351
- console.log(`[fullstack-cli] \u25CB ${path2.basename(dest)} (skipped, already exists)`);
382
+ if (fs3.existsSync(dest) && !overwrite) {
383
+ console.log(`[fullstack-cli] \u25CB ${path3.basename(dest)} (skipped, already exists)`);
352
384
  return;
353
385
  }
354
- fs2.copyFileSync(src, dest);
355
- console.log(`[fullstack-cli] \u2713 ${path2.basename(dest)}`);
386
+ fs3.copyFileSync(src, dest);
387
+ console.log(`[fullstack-cli] \u2713 ${path3.basename(dest)}`);
356
388
  }
357
389
  function syncDirectory(src, dest, overwrite = true) {
358
- if (!fs2.existsSync(dest)) {
359
- fs2.mkdirSync(dest, { recursive: true });
390
+ if (!fs3.existsSync(dest)) {
391
+ fs3.mkdirSync(dest, { recursive: true });
360
392
  }
361
- const files = fs2.readdirSync(src);
393
+ const files = fs3.readdirSync(src);
362
394
  let count = 0;
363
395
  files.forEach((file) => {
364
- const srcFile = path2.join(src, file);
365
- const destFile = path2.join(dest, file);
366
- const stats = fs2.statSync(srcFile);
396
+ const srcFile = path3.join(src, file);
397
+ const destFile = path3.join(dest, file);
398
+ const stats = fs3.statSync(srcFile);
367
399
  if (stats.isDirectory()) {
368
400
  syncDirectory(srcFile, destFile, overwrite);
369
401
  } else {
370
- if (overwrite || !fs2.existsSync(destFile)) {
371
- fs2.copyFileSync(srcFile, destFile);
372
- console.log(`[fullstack-cli] \u2713 ${path2.relative(dest, destFile)}`);
402
+ if (overwrite || !fs3.existsSync(destFile)) {
403
+ fs3.copyFileSync(srcFile, destFile);
404
+ console.log(`[fullstack-cli] \u2713 ${path3.relative(dest, destFile)}`);
373
405
  count++;
374
406
  }
375
407
  }
376
408
  });
377
409
  if (count > 0) {
378
- console.log(`[fullstack-cli] Synced ${count} files to ${path2.basename(dest)}/`);
410
+ console.log(`[fullstack-cli] Synced ${count} files to ${path3.basename(dest)}/`);
379
411
  }
380
412
  }
381
413
  function appendToFile(src, dest) {
382
- const content = fs2.readFileSync(src, "utf-8");
414
+ const content = fs3.readFileSync(src, "utf-8");
383
415
  let existingContent = "";
384
- if (fs2.existsSync(dest)) {
385
- existingContent = fs2.readFileSync(dest, "utf-8");
416
+ if (fs3.existsSync(dest)) {
417
+ existingContent = fs3.readFileSync(dest, "utf-8");
386
418
  }
387
419
  if (existingContent.includes(content.trim())) {
388
- console.log(`[fullstack-cli] \u25CB ${path2.basename(dest)} (already contains content)`);
420
+ console.log(`[fullstack-cli] \u25CB ${path3.basename(dest)} (already contains content)`);
389
421
  return;
390
422
  }
391
- fs2.appendFileSync(dest, content);
392
- console.log(`[fullstack-cli] \u2713 ${path2.basename(dest)} (appended)`);
423
+ fs3.appendFileSync(dest, content);
424
+ console.log(`[fullstack-cli] \u2713 ${path3.basename(dest)} (appended)`);
393
425
  }
394
426
  function setPermissions(permissions, projectRoot) {
395
427
  for (const [pattern, mode] of Object.entries(permissions)) {
396
428
  if (pattern === "**/*.sh") {
397
- const scriptsDir = path2.join(projectRoot, "scripts");
398
- if (fs2.existsSync(scriptsDir)) {
399
- const files = fs2.readdirSync(scriptsDir);
429
+ const scriptsDir = path3.join(projectRoot, "scripts");
430
+ if (fs3.existsSync(scriptsDir)) {
431
+ const files = fs3.readdirSync(scriptsDir);
400
432
  files.forEach((file) => {
401
433
  if (file.endsWith(".sh")) {
402
- const filePath = path2.join(scriptsDir, file);
403
- fs2.chmodSync(filePath, mode);
434
+ const filePath = path3.join(scriptsDir, file);
435
+ fs3.chmodSync(filePath, mode);
404
436
  }
405
437
  });
406
438
  }
@@ -408,19 +440,19 @@ function setPermissions(permissions, projectRoot) {
408
440
  }
409
441
  }
410
442
  function deleteFile(filePath) {
411
- if (fs2.existsSync(filePath)) {
412
- fs2.unlinkSync(filePath);
413
- console.log(`[fullstack-cli] \u2713 ${path2.basename(filePath)} (deleted)`);
443
+ if (fs3.existsSync(filePath)) {
444
+ fs3.unlinkSync(filePath);
445
+ console.log(`[fullstack-cli] \u2713 ${path3.basename(filePath)} (deleted)`);
414
446
  } else {
415
- console.log(`[fullstack-cli] \u25CB ${path2.basename(filePath)} (not found)`);
447
+ console.log(`[fullstack-cli] \u25CB ${path3.basename(filePath)} (not found)`);
416
448
  }
417
449
  }
418
450
  function deleteDirectory(dirPath) {
419
- if (fs2.existsSync(dirPath)) {
420
- fs2.rmSync(dirPath, { recursive: true });
421
- console.log(`[fullstack-cli] \u2713 ${path2.basename(dirPath)} (deleted)`);
451
+ if (fs3.existsSync(dirPath)) {
452
+ fs3.rmSync(dirPath, { recursive: true });
453
+ console.log(`[fullstack-cli] \u2713 ${path3.basename(dirPath)} (deleted)`);
422
454
  } else {
423
- console.log(`[fullstack-cli] \u25CB ${path2.basename(dirPath)} (not found)`);
455
+ console.log(`[fullstack-cli] \u25CB ${path3.basename(dirPath)} (not found)`);
424
456
  }
425
457
  }
426
458
 
@@ -436,8 +468,8 @@ var syncCommand = {
436
468
  };
437
469
 
438
470
  // src/commands/action-plugin/utils.ts
439
- import fs3 from "fs";
440
- import path3 from "path";
471
+ import fs4 from "fs";
472
+ import path4 from "path";
441
473
  import { spawnSync as spawnSync2, execSync } from "child_process";
442
474
  function parsePluginName(input) {
443
475
  const match = input.match(/^(@[^/]+\/[^@]+)(?:@(.+))?$/);
@@ -455,18 +487,18 @@ function getProjectRoot() {
455
487
  return process.cwd();
456
488
  }
457
489
  function getPackageJsonPath() {
458
- return path3.join(getProjectRoot(), "package.json");
490
+ return path4.join(getProjectRoot(), "package.json");
459
491
  }
460
492
  function getPluginPath(pluginName) {
461
- return path3.join(getProjectRoot(), "node_modules", pluginName);
493
+ return path4.join(getProjectRoot(), "node_modules", pluginName);
462
494
  }
463
495
  function readPackageJson() {
464
496
  const pkgPath = getPackageJsonPath();
465
- if (!fs3.existsSync(pkgPath)) {
497
+ if (!fs4.existsSync(pkgPath)) {
466
498
  throw new Error("package.json not found in current directory");
467
499
  }
468
500
  try {
469
- const content = fs3.readFileSync(pkgPath, "utf-8");
501
+ const content = fs4.readFileSync(pkgPath, "utf-8");
470
502
  return JSON.parse(content);
471
503
  } catch {
472
504
  throw new Error("Failed to parse package.json");
@@ -474,7 +506,7 @@ function readPackageJson() {
474
506
  }
475
507
  function writePackageJson(pkg2) {
476
508
  const pkgPath = getPackageJsonPath();
477
- fs3.writeFileSync(pkgPath, JSON.stringify(pkg2, null, 2) + "\n", "utf-8");
509
+ fs4.writeFileSync(pkgPath, JSON.stringify(pkg2, null, 2) + "\n", "utf-8");
478
510
  }
479
511
  function readActionPlugins() {
480
512
  const pkg2 = readPackageJson();
@@ -507,12 +539,12 @@ function npmInstall(tgzPath) {
507
539
  }
508
540
  }
509
541
  function getPackageVersion(pluginName) {
510
- const pkgJsonPath = path3.join(getPluginPath(pluginName), "package.json");
511
- if (!fs3.existsSync(pkgJsonPath)) {
542
+ const pkgJsonPath = path4.join(getPluginPath(pluginName), "package.json");
543
+ if (!fs4.existsSync(pkgJsonPath)) {
512
544
  return null;
513
545
  }
514
546
  try {
515
- const content = fs3.readFileSync(pkgJsonPath, "utf-8");
547
+ const content = fs4.readFileSync(pkgJsonPath, "utf-8");
516
548
  const pkg2 = JSON.parse(content);
517
549
  return pkg2.version || null;
518
550
  } catch {
@@ -520,49 +552,49 @@ function getPackageVersion(pluginName) {
520
552
  }
521
553
  }
522
554
  function readPluginPackageJson(pluginPath) {
523
- const pkgJsonPath = path3.join(pluginPath, "package.json");
524
- if (!fs3.existsSync(pkgJsonPath)) {
555
+ const pkgJsonPath = path4.join(pluginPath, "package.json");
556
+ if (!fs4.existsSync(pkgJsonPath)) {
525
557
  return null;
526
558
  }
527
559
  try {
528
- const content = fs3.readFileSync(pkgJsonPath, "utf-8");
560
+ const content = fs4.readFileSync(pkgJsonPath, "utf-8");
529
561
  return JSON.parse(content);
530
562
  } catch {
531
563
  return null;
532
564
  }
533
565
  }
534
566
  function extractTgzToNodeModules(tgzPath, pluginName) {
535
- const nodeModulesPath = path3.join(getProjectRoot(), "node_modules");
536
- const targetDir = path3.join(nodeModulesPath, pluginName);
537
- const scopeDir = path3.dirname(targetDir);
538
- if (!fs3.existsSync(scopeDir)) {
539
- fs3.mkdirSync(scopeDir, { recursive: true });
567
+ const nodeModulesPath = path4.join(getProjectRoot(), "node_modules");
568
+ const targetDir = path4.join(nodeModulesPath, pluginName);
569
+ const scopeDir = path4.dirname(targetDir);
570
+ if (!fs4.existsSync(scopeDir)) {
571
+ fs4.mkdirSync(scopeDir, { recursive: true });
540
572
  }
541
- if (fs3.existsSync(targetDir)) {
542
- fs3.rmSync(targetDir, { recursive: true });
573
+ if (fs4.existsSync(targetDir)) {
574
+ fs4.rmSync(targetDir, { recursive: true });
543
575
  }
544
- const tempDir = path3.join(nodeModulesPath, ".cache", "fullstack-cli", "extract-temp");
545
- if (fs3.existsSync(tempDir)) {
546
- fs3.rmSync(tempDir, { recursive: true });
576
+ const tempDir = path4.join(nodeModulesPath, ".cache", "fullstack-cli", "extract-temp");
577
+ if (fs4.existsSync(tempDir)) {
578
+ fs4.rmSync(tempDir, { recursive: true });
547
579
  }
548
- fs3.mkdirSync(tempDir, { recursive: true });
580
+ fs4.mkdirSync(tempDir, { recursive: true });
549
581
  try {
550
582
  execSync(`tar -xzf "${tgzPath}" -C "${tempDir}"`, { stdio: "pipe" });
551
- const extractedDir = path3.join(tempDir, "package");
552
- if (fs3.existsSync(extractedDir)) {
553
- fs3.renameSync(extractedDir, targetDir);
583
+ const extractedDir = path4.join(tempDir, "package");
584
+ if (fs4.existsSync(extractedDir)) {
585
+ fs4.renameSync(extractedDir, targetDir);
554
586
  } else {
555
- const files = fs3.readdirSync(tempDir);
587
+ const files = fs4.readdirSync(tempDir);
556
588
  if (files.length === 1) {
557
- fs3.renameSync(path3.join(tempDir, files[0]), targetDir);
589
+ fs4.renameSync(path4.join(tempDir, files[0]), targetDir);
558
590
  } else {
559
591
  throw new Error("Unexpected tgz structure");
560
592
  }
561
593
  }
562
594
  return targetDir;
563
595
  } finally {
564
- if (fs3.existsSync(tempDir)) {
565
- fs3.rmSync(tempDir, { recursive: true });
596
+ if (fs4.existsSync(tempDir)) {
597
+ fs4.rmSync(tempDir, { recursive: true });
566
598
  }
567
599
  }
568
600
  }
@@ -571,10 +603,10 @@ function checkMissingPeerDeps(peerDeps) {
571
603
  return [];
572
604
  }
573
605
  const missing = [];
574
- const nodeModulesPath = path3.join(getProjectRoot(), "node_modules");
606
+ const nodeModulesPath = path4.join(getProjectRoot(), "node_modules");
575
607
  for (const [depName, _version] of Object.entries(peerDeps)) {
576
- const depPath = path3.join(nodeModulesPath, depName);
577
- if (!fs3.existsSync(depPath)) {
608
+ const depPath = path4.join(nodeModulesPath, depName);
609
+ if (!fs4.existsSync(depPath)) {
578
610
  missing.push(depName);
579
611
  }
580
612
  }
@@ -598,16 +630,16 @@ function installMissingDeps(deps) {
598
630
  }
599
631
  function removePluginDirectory(pluginName) {
600
632
  const pluginPath = getPluginPath(pluginName);
601
- if (fs3.existsSync(pluginPath)) {
602
- fs3.rmSync(pluginPath, { recursive: true });
633
+ if (fs4.existsSync(pluginPath)) {
634
+ fs4.rmSync(pluginPath, { recursive: true });
603
635
  console.log(`[action-plugin] Removed ${pluginName}`);
604
636
  }
605
637
  }
606
638
 
607
639
  // src/commands/action-plugin/api-client.ts
608
640
  import { HttpClient as HttpClient2 } from "@lark-apaas/http-client";
609
- import fs4 from "fs";
610
- import path4 from "path";
641
+ import fs5 from "fs";
642
+ import path5 from "path";
611
643
 
612
644
  // src/utils/http-client.ts
613
645
  import { HttpClient } from "@lark-apaas/http-client";
@@ -692,19 +724,19 @@ async function downloadFromPublic(downloadURL) {
692
724
  return Buffer.from(arrayBuffer);
693
725
  }
694
726
  function getPluginCacheDir() {
695
- return path4.join(process.cwd(), PLUGIN_CACHE_DIR);
727
+ return path5.join(process.cwd(), PLUGIN_CACHE_DIR);
696
728
  }
697
729
  function ensureCacheDir() {
698
730
  const cacheDir = getPluginCacheDir();
699
- if (!fs4.existsSync(cacheDir)) {
700
- fs4.mkdirSync(cacheDir, { recursive: true });
731
+ if (!fs5.existsSync(cacheDir)) {
732
+ fs5.mkdirSync(cacheDir, { recursive: true });
701
733
  }
702
734
  }
703
735
  function getTempFilePath(pluginKey, version) {
704
736
  ensureCacheDir();
705
737
  const safeKey = pluginKey.replace(/[/@]/g, "_");
706
738
  const filename = `${safeKey}-${version}.tgz`;
707
- return path4.join(getPluginCacheDir(), filename);
739
+ return path5.join(getPluginCacheDir(), filename);
708
740
  }
709
741
  async function downloadPlugin(pluginKey, requestedVersion) {
710
742
  console.log(`[action-plugin] Fetching plugin info for ${pluginKey}@${requestedVersion}...`);
@@ -720,7 +752,7 @@ async function downloadPlugin(pluginKey, requestedVersion) {
720
752
  tgzBuffer = await downloadFromPublic(pluginInfo.downloadURL);
721
753
  }
722
754
  const tgzPath = getTempFilePath(pluginKey, pluginInfo.version);
723
- fs4.writeFileSync(tgzPath, tgzBuffer);
755
+ fs5.writeFileSync(tgzPath, tgzBuffer);
724
756
  console.log(`[action-plugin] Downloaded to ${tgzPath} (${(tgzBuffer.length / 1024).toFixed(2)} KB)`);
725
757
  return {
726
758
  tgzPath,
@@ -730,8 +762,8 @@ async function downloadPlugin(pluginKey, requestedVersion) {
730
762
  }
731
763
  function cleanupTempFile(tgzPath) {
732
764
  try {
733
- if (fs4.existsSync(tgzPath)) {
734
- fs4.unlinkSync(tgzPath);
765
+ if (fs5.existsSync(tgzPath)) {
766
+ fs5.unlinkSync(tgzPath);
735
767
  }
736
768
  } catch {
737
769
  }
@@ -1056,39 +1088,39 @@ var actionPluginCommandGroup = {
1056
1088
  };
1057
1089
 
1058
1090
  // src/commands/capability/utils.ts
1059
- import fs5 from "fs";
1060
- import path5 from "path";
1091
+ import fs6 from "fs";
1092
+ import path6 from "path";
1061
1093
  var CAPABILITIES_DIR = "server/capabilities";
1062
1094
  function getProjectRoot2() {
1063
1095
  return process.cwd();
1064
1096
  }
1065
1097
  function getCapabilitiesDir() {
1066
- return path5.join(getProjectRoot2(), CAPABILITIES_DIR);
1098
+ return path6.join(getProjectRoot2(), CAPABILITIES_DIR);
1067
1099
  }
1068
1100
  function getCapabilityPath(id) {
1069
- return path5.join(getCapabilitiesDir(), `${id}.json`);
1101
+ return path6.join(getCapabilitiesDir(), `${id}.json`);
1070
1102
  }
1071
1103
  function getPluginManifestPath(pluginKey) {
1072
- return path5.join(getProjectRoot2(), "node_modules", pluginKey, "manifest.json");
1104
+ return path6.join(getProjectRoot2(), "node_modules", pluginKey, "manifest.json");
1073
1105
  }
1074
1106
  function capabilitiesDirExists() {
1075
- return fs5.existsSync(getCapabilitiesDir());
1107
+ return fs6.existsSync(getCapabilitiesDir());
1076
1108
  }
1077
1109
  function listCapabilityIds() {
1078
1110
  const dir = getCapabilitiesDir();
1079
- if (!fs5.existsSync(dir)) {
1111
+ if (!fs6.existsSync(dir)) {
1080
1112
  return [];
1081
1113
  }
1082
- const files = fs5.readdirSync(dir);
1114
+ const files = fs6.readdirSync(dir);
1083
1115
  return files.filter((f) => f.endsWith(".json")).map((f) => f.replace(/\.json$/, ""));
1084
1116
  }
1085
1117
  function readCapability(id) {
1086
1118
  const filePath = getCapabilityPath(id);
1087
- if (!fs5.existsSync(filePath)) {
1119
+ if (!fs6.existsSync(filePath)) {
1088
1120
  throw new Error(`Capability not found: ${id}`);
1089
1121
  }
1090
1122
  try {
1091
- const content = fs5.readFileSync(filePath, "utf-8");
1123
+ const content = fs6.readFileSync(filePath, "utf-8");
1092
1124
  return JSON.parse(content);
1093
1125
  } catch (error) {
1094
1126
  if (error instanceof SyntaxError) {
@@ -1103,11 +1135,11 @@ function readAllCapabilities() {
1103
1135
  }
1104
1136
  function readPluginManifest(pluginKey) {
1105
1137
  const manifestPath = getPluginManifestPath(pluginKey);
1106
- if (!fs5.existsSync(manifestPath)) {
1138
+ if (!fs6.existsSync(manifestPath)) {
1107
1139
  throw new Error(`Plugin not installed: ${pluginKey} (manifest.json not found)`);
1108
1140
  }
1109
1141
  try {
1110
- const content = fs5.readFileSync(manifestPath, "utf-8");
1142
+ const content = fs6.readFileSync(manifestPath, "utf-8");
1111
1143
  return JSON.parse(content);
1112
1144
  } catch (error) {
1113
1145
  if (error instanceof SyntaxError) {
@@ -1138,14 +1170,6 @@ async function loadPlugin(pluginKey) {
1138
1170
  );
1139
1171
  }
1140
1172
  }
1141
- async function zodToJsonSchema(zodSchema) {
1142
- try {
1143
- const { zodToJsonSchema: convert } = await import("zod-to-json-schema");
1144
- return convert(zodSchema);
1145
- } catch {
1146
- throw new Error("Failed to convert Zod schema to JSON Schema. Make sure zod-to-json-schema is installed.");
1147
- }
1148
- }
1149
1173
  async function hydrateCapability(capability) {
1150
1174
  try {
1151
1175
  const manifest = readPluginManifest(capability.pluginKey);
@@ -1170,11 +1194,11 @@ async function hydrateCapability(capability) {
1170
1194
  if (!pluginInstance) {
1171
1195
  throw new Error(`Plugin instance not available for dynamic schema`);
1172
1196
  }
1173
- const zodSchema = pluginInstance.getInputSchema(manifestAction.key);
1174
- if (!zodSchema) {
1197
+ const jsonSchema = pluginInstance.getInputJsonSchema(manifestAction.key);
1198
+ if (!jsonSchema) {
1175
1199
  throw new Error(`Failed to get input schema for action: ${manifestAction.key}`);
1176
1200
  }
1177
- inputSchema = await zodToJsonSchema(zodSchema);
1201
+ inputSchema = jsonSchema;
1178
1202
  } else {
1179
1203
  inputSchema = manifestAction.inputSchema;
1180
1204
  }
@@ -1183,11 +1207,11 @@ async function hydrateCapability(capability) {
1183
1207
  if (!pluginInstance) {
1184
1208
  throw new Error(`Plugin instance not available for dynamic schema`);
1185
1209
  }
1186
- const zodSchema = pluginInstance.getOutputSchema(manifestAction.key, {});
1187
- if (!zodSchema) {
1210
+ const jsonSchema = pluginInstance.getOutputJsonSchema(manifestAction.key, capability.formValue || {});
1211
+ if (!jsonSchema) {
1188
1212
  throw new Error(`Failed to get output schema for action: ${manifestAction.key}`);
1189
1213
  }
1190
- outputSchema = await zodToJsonSchema(zodSchema);
1214
+ outputSchema = jsonSchema;
1191
1215
  } else {
1192
1216
  outputSchema = manifestAction.outputSchema;
1193
1217
  }
@@ -1289,58 +1313,58 @@ var capabilityCommandGroup = {
1289
1313
  };
1290
1314
 
1291
1315
  // src/commands/migration/version-manager.ts
1292
- import fs6 from "fs";
1293
- import path6 from "path";
1316
+ import fs7 from "fs";
1317
+ import path7 from "path";
1294
1318
  var PACKAGE_JSON = "package.json";
1295
1319
  var VERSION_FIELD = "migrationVersion";
1296
1320
  function getPackageJsonPath2() {
1297
- return path6.join(process.cwd(), PACKAGE_JSON);
1321
+ return path7.join(process.cwd(), PACKAGE_JSON);
1298
1322
  }
1299
1323
  function getCurrentVersion() {
1300
1324
  const pkgPath = getPackageJsonPath2();
1301
- if (!fs6.existsSync(pkgPath)) {
1325
+ if (!fs7.existsSync(pkgPath)) {
1302
1326
  throw new Error("package.json not found");
1303
1327
  }
1304
- const pkg2 = JSON.parse(fs6.readFileSync(pkgPath, "utf-8"));
1328
+ const pkg2 = JSON.parse(fs7.readFileSync(pkgPath, "utf-8"));
1305
1329
  return pkg2[VERSION_FIELD] ?? 0;
1306
1330
  }
1307
1331
  function setCurrentVersion(version) {
1308
1332
  const pkgPath = getPackageJsonPath2();
1309
- const pkg2 = JSON.parse(fs6.readFileSync(pkgPath, "utf-8"));
1333
+ const pkg2 = JSON.parse(fs7.readFileSync(pkgPath, "utf-8"));
1310
1334
  pkg2[VERSION_FIELD] = version;
1311
- fs6.writeFileSync(pkgPath, JSON.stringify(pkg2, null, 2) + "\n", "utf-8");
1335
+ fs7.writeFileSync(pkgPath, JSON.stringify(pkg2, null, 2) + "\n", "utf-8");
1312
1336
  }
1313
1337
 
1314
1338
  // src/commands/migration/versions/v001_capability/json-migrator/detector.ts
1315
- import fs8 from "fs";
1316
- import path8 from "path";
1339
+ import fs9 from "fs";
1340
+ import path9 from "path";
1317
1341
 
1318
1342
  // src/commands/migration/versions/v001_capability/utils.ts
1319
- import fs7 from "fs";
1320
- import path7 from "path";
1343
+ import fs8 from "fs";
1344
+ import path8 from "path";
1321
1345
  var CAPABILITIES_DIR2 = "server/capabilities";
1322
1346
  function getProjectRoot3() {
1323
1347
  return process.cwd();
1324
1348
  }
1325
1349
  function getCapabilitiesDir2() {
1326
- return path7.join(getProjectRoot3(), CAPABILITIES_DIR2);
1350
+ return path8.join(getProjectRoot3(), CAPABILITIES_DIR2);
1327
1351
  }
1328
1352
  function getPluginManifestPath2(pluginKey) {
1329
- return path7.join(getProjectRoot3(), "node_modules", pluginKey, "manifest.json");
1353
+ return path8.join(getProjectRoot3(), "node_modules", pluginKey, "manifest.json");
1330
1354
  }
1331
1355
 
1332
1356
  // src/commands/migration/versions/v001_capability/json-migrator/detector.ts
1333
1357
  function detectJsonMigration() {
1334
1358
  const capabilitiesDir = getCapabilitiesDir2();
1335
- const oldFilePath = path8.join(capabilitiesDir, "capabilities.json");
1336
- if (!fs8.existsSync(oldFilePath)) {
1359
+ const oldFilePath = path9.join(capabilitiesDir, "capabilities.json");
1360
+ if (!fs9.existsSync(oldFilePath)) {
1337
1361
  return {
1338
1362
  needsMigration: false,
1339
1363
  reason: "capabilities.json not found"
1340
1364
  };
1341
1365
  }
1342
1366
  try {
1343
- const content = fs8.readFileSync(oldFilePath, "utf-8");
1367
+ const content = fs9.readFileSync(oldFilePath, "utf-8");
1344
1368
  const parsed = JSON.parse(content);
1345
1369
  const capabilities = Array.isArray(parsed) ? parsed : [];
1346
1370
  return {
@@ -1349,10 +1373,12 @@ function detectJsonMigration() {
1349
1373
  oldFilePath
1350
1374
  };
1351
1375
  } catch (error) {
1376
+ const errorMessage = error instanceof Error ? error.message : String(error);
1377
+ console.warn(`[migration] Warning: capabilities.json is not valid JSON, skipping migration`);
1378
+ console.warn(`[migration] Error: ${errorMessage}`);
1352
1379
  return {
1353
- needsMigration: true,
1354
- oldCapabilities: [],
1355
- oldFilePath
1380
+ needsMigration: false,
1381
+ reason: `capabilities.json is not valid JSON: ${errorMessage}`
1356
1382
  };
1357
1383
  }
1358
1384
  }
@@ -1378,8 +1404,8 @@ async function check(options) {
1378
1404
  }
1379
1405
 
1380
1406
  // src/commands/migration/versions/v001_capability/json-migrator/index.ts
1381
- import fs9 from "fs";
1382
- import path9 from "path";
1407
+ import fs10 from "fs";
1408
+ import path10 from "path";
1383
1409
 
1384
1410
  // src/commands/migration/versions/v001_capability/mapping.ts
1385
1411
  var DEFAULT_PLUGIN_VERSION = "1.0.0";
@@ -1494,7 +1520,7 @@ var DEFAULT_TEMPERATURE = 0.7;
1494
1520
  function transformAITextGenerate(input) {
1495
1521
  const actionInput = input;
1496
1522
  return {
1497
- modelID: actionInput.model_id ?? DEFAULT_MODEL_ID,
1523
+ modelID: DEFAULT_MODEL_ID,
1498
1524
  prompt: actionInput.prompt ?? "",
1499
1525
  modelParams: {
1500
1526
  maxTokens: convertToNumber(actionInput.max_tokens, DEFAULT_MAX_TOKENS),
@@ -1512,7 +1538,7 @@ function transformAIImageUnderstanding(input) {
1512
1538
  return {
1513
1539
  prompt: actionInput.prompt ?? "",
1514
1540
  images: actionInput.image_list ?? [],
1515
- modelID: actionInput.model_id ?? DEFAULT_MODEL_ID2,
1541
+ modelID: DEFAULT_MODEL_ID2,
1516
1542
  modelParams: {
1517
1543
  maxTokens: convertToNumber(actionInput.max_tokens, DEFAULT_MAX_TOKENS2),
1518
1544
  temperature: convertToNumber(actionInput.temperature, DEFAULT_TEMPERATURE2)
@@ -1573,18 +1599,18 @@ function transformCapabilities(oldCapabilities) {
1573
1599
  // src/commands/migration/versions/v001_capability/json-migrator/index.ts
1574
1600
  function loadExistingCapabilities() {
1575
1601
  const capabilitiesDir = getCapabilitiesDir2();
1576
- if (!fs9.existsSync(capabilitiesDir)) {
1602
+ if (!fs10.existsSync(capabilitiesDir)) {
1577
1603
  return [];
1578
1604
  }
1579
- const files = fs9.readdirSync(capabilitiesDir);
1605
+ const files = fs10.readdirSync(capabilitiesDir);
1580
1606
  const capabilities = [];
1581
1607
  for (const file of files) {
1582
1608
  if (file === "capabilities.json" || !file.endsWith(".json")) {
1583
1609
  continue;
1584
1610
  }
1585
1611
  try {
1586
- const filePath = path9.join(capabilitiesDir, file);
1587
- const content = fs9.readFileSync(filePath, "utf-8");
1612
+ const filePath = path10.join(capabilitiesDir, file);
1613
+ const content = fs10.readFileSync(filePath, "utf-8");
1588
1614
  const capability = JSON.parse(content);
1589
1615
  if (capability.id && capability.pluginKey) {
1590
1616
  capabilities.push(capability);
@@ -1642,9 +1668,9 @@ async function migrateJsonFiles(options) {
1642
1668
  }
1643
1669
  const capabilitiesDir = getCapabilitiesDir2();
1644
1670
  for (const cap of newCapabilities) {
1645
- const filePath = path9.join(capabilitiesDir, `${cap.id}.json`);
1671
+ const filePath = path10.join(capabilitiesDir, `${cap.id}.json`);
1646
1672
  const content = JSON.stringify(cap, null, 2);
1647
- fs9.writeFileSync(filePath, content, "utf-8");
1673
+ fs10.writeFileSync(filePath, content, "utf-8");
1648
1674
  console.log(` \u2713 Created: ${cap.id}.json`);
1649
1675
  }
1650
1676
  return {
@@ -1656,10 +1682,10 @@ async function migrateJsonFiles(options) {
1656
1682
  }
1657
1683
 
1658
1684
  // src/commands/migration/versions/v001_capability/plugin-installer/detector.ts
1659
- import fs10 from "fs";
1685
+ import fs11 from "fs";
1660
1686
  function isPluginInstalled2(pluginKey) {
1661
1687
  const manifestPath = getPluginManifestPath2(pluginKey);
1662
- return fs10.existsSync(manifestPath);
1688
+ return fs11.existsSync(manifestPath);
1663
1689
  }
1664
1690
  function detectPluginsToInstall(capabilities) {
1665
1691
  const pluginKeys = /* @__PURE__ */ new Set();
@@ -1735,12 +1761,12 @@ async function installPlugins(capabilities, options) {
1735
1761
  }
1736
1762
 
1737
1763
  // src/commands/migration/versions/v001_capability/code-migrator/index.ts
1738
- import path11 from "path";
1764
+ import path12 from "path";
1739
1765
  import { Project } from "ts-morph";
1740
1766
 
1741
1767
  // src/commands/migration/versions/v001_capability/code-migrator/scanner.ts
1742
- import fs11 from "fs";
1743
- import path10 from "path";
1768
+ import fs12 from "fs";
1769
+ import path11 from "path";
1744
1770
  var EXCLUDED_DIRS = [
1745
1771
  "node_modules",
1746
1772
  "dist",
@@ -1755,9 +1781,9 @@ var EXCLUDED_PATTERNS = [
1755
1781
  /\.d\.ts$/
1756
1782
  ];
1757
1783
  function scanDirectory(dir, files = []) {
1758
- const entries = fs11.readdirSync(dir, { withFileTypes: true });
1784
+ const entries = fs12.readdirSync(dir, { withFileTypes: true });
1759
1785
  for (const entry of entries) {
1760
- const fullPath = path10.join(dir, entry.name);
1786
+ const fullPath = path11.join(dir, entry.name);
1761
1787
  if (entry.isDirectory()) {
1762
1788
  if (EXCLUDED_DIRS.includes(entry.name)) {
1763
1789
  continue;
@@ -1773,14 +1799,14 @@ function scanDirectory(dir, files = []) {
1773
1799
  return files;
1774
1800
  }
1775
1801
  function scanServerFiles() {
1776
- const serverDir = path10.join(getProjectRoot3(), "server");
1777
- if (!fs11.existsSync(serverDir)) {
1802
+ const serverDir = path11.join(getProjectRoot3(), "server");
1803
+ if (!fs12.existsSync(serverDir)) {
1778
1804
  return [];
1779
1805
  }
1780
1806
  return scanDirectory(serverDir);
1781
1807
  }
1782
1808
  function hasCapabilityImport(filePath) {
1783
- const content = fs11.readFileSync(filePath, "utf-8");
1809
+ const content = fs12.readFileSync(filePath, "utf-8");
1784
1810
  return /import\s+.*from\s+['"][^'"]*capabilities[^'"]*['"]/.test(content);
1785
1811
  }
1786
1812
  function scanFilesToMigrate() {
@@ -2155,7 +2181,7 @@ function analyzeFile(project, filePath, actionNameMap) {
2155
2181
  const callSites = analyzeCallSites(sourceFile, imports);
2156
2182
  const classInfo = analyzeClass(sourceFile);
2157
2183
  const { canMigrate, reason } = canAutoMigrate(classInfo);
2158
- const relativePath = path11.relative(getProjectRoot3(), filePath);
2184
+ const relativePath = path12.relative(getProjectRoot3(), filePath);
2159
2185
  return {
2160
2186
  filePath: relativePath,
2161
2187
  imports,
@@ -2166,7 +2192,7 @@ function analyzeFile(project, filePath, actionNameMap) {
2166
2192
  };
2167
2193
  }
2168
2194
  function migrateFile(project, analysis, dryRun) {
2169
- const absolutePath = path11.join(getProjectRoot3(), analysis.filePath);
2195
+ const absolutePath = path12.join(getProjectRoot3(), analysis.filePath);
2170
2196
  if (!analysis.canAutoMigrate) {
2171
2197
  return {
2172
2198
  filePath: analysis.filePath,
@@ -2269,17 +2295,17 @@ function getSuggestion(analysis) {
2269
2295
  }
2270
2296
 
2271
2297
  // src/commands/migration/versions/v001_capability/cleanup.ts
2272
- import fs12 from "fs";
2273
- import path12 from "path";
2298
+ import fs13 from "fs";
2299
+ import path13 from "path";
2274
2300
  function cleanupOldFiles(capabilities, dryRun) {
2275
2301
  const deletedFiles = [];
2276
2302
  const errors = [];
2277
2303
  const capabilitiesDir = getCapabilitiesDir2();
2278
- const oldJsonPath = path12.join(capabilitiesDir, "capabilities.json");
2279
- if (fs12.existsSync(oldJsonPath)) {
2304
+ const oldJsonPath = path13.join(capabilitiesDir, "capabilities.json");
2305
+ if (fs13.existsSync(oldJsonPath)) {
2280
2306
  try {
2281
2307
  if (!dryRun) {
2282
- fs12.unlinkSync(oldJsonPath);
2308
+ fs13.unlinkSync(oldJsonPath);
2283
2309
  }
2284
2310
  deletedFiles.push("capabilities.json");
2285
2311
  } catch (error) {
@@ -2287,11 +2313,11 @@ function cleanupOldFiles(capabilities, dryRun) {
2287
2313
  }
2288
2314
  }
2289
2315
  for (const cap of capabilities) {
2290
- const tsFilePath = path12.join(capabilitiesDir, `${cap.id}.ts`);
2291
- if (fs12.existsSync(tsFilePath)) {
2316
+ const tsFilePath = path13.join(capabilitiesDir, `${cap.id}.ts`);
2317
+ if (fs13.existsSync(tsFilePath)) {
2292
2318
  try {
2293
2319
  if (!dryRun) {
2294
- fs12.unlinkSync(tsFilePath);
2320
+ fs13.unlinkSync(tsFilePath);
2295
2321
  }
2296
2322
  deletedFiles.push(`${cap.id}.ts`);
2297
2323
  } catch (error) {
@@ -2307,8 +2333,8 @@ function cleanupOldFiles(capabilities, dryRun) {
2307
2333
  }
2308
2334
 
2309
2335
  // src/commands/migration/versions/v001_capability/report-generator.ts
2310
- import fs13 from "fs";
2311
- import path13 from "path";
2336
+ import fs14 from "fs";
2337
+ import path14 from "path";
2312
2338
  var REPORT_FILE = "capability-migration-report.md";
2313
2339
  function printSummary(result) {
2314
2340
  const { jsonMigration, pluginInstallation, codeMigration, cleanup } = result;
@@ -2470,8 +2496,8 @@ async function generateReport(result) {
2470
2496
  lines.push("- [ ] \u5904\u7406\u624B\u52A8\u8FC1\u79FB\u9879");
2471
2497
  }
2472
2498
  lines.push("");
2473
- const reportPath = path13.join(getProjectRoot3(), REPORT_FILE);
2474
- fs13.writeFileSync(reportPath, lines.join("\n"), "utf-8");
2499
+ const reportPath = path14.join(getProjectRoot3(), REPORT_FILE);
2500
+ fs14.writeFileSync(reportPath, lines.join("\n"), "utf-8");
2475
2501
  console.log(`\u{1F4C4} Report generated: ${REPORT_FILE}`);
2476
2502
  }
2477
2503
 
@@ -2871,6 +2897,10 @@ async function runMigrations(options) {
2871
2897
  printSummary2(summary, !!options.dryRun);
2872
2898
  return summary;
2873
2899
  }
2900
+ function printMigrationResult(result) {
2901
+ console.log("");
2902
+ console.log(`MigrationResult=${JSON.stringify(result)}`);
2903
+ }
2874
2904
  async function checkMigrations(options) {
2875
2905
  const currentVersion = getCurrentVersion();
2876
2906
  const latestVersion = getLatestVersion();
@@ -2878,6 +2908,12 @@ async function checkMigrations(options) {
2878
2908
  log(`Current version: ${currentVersion || "0 (not set)"}`);
2879
2909
  if (currentVersion >= latestVersion) {
2880
2910
  log("All migrations are up to date.");
2911
+ printMigrationResult({
2912
+ needMigration: false,
2913
+ migrationVersion: currentVersion,
2914
+ targetVersion: latestVersion,
2915
+ pendingMigrations: []
2916
+ });
2881
2917
  return {
2882
2918
  needsMigration: false,
2883
2919
  completed: [],
@@ -2896,13 +2932,16 @@ async function checkMigrations(options) {
2896
2932
  };
2897
2933
  let needsCount = 0;
2898
2934
  let noActionCount = 0;
2935
+ const pendingMigrationNames = [];
2899
2936
  for (const migration of pendingMigrations) {
2900
2937
  const { version, name } = migration;
2901
2938
  const versionTag = `v${version}`;
2939
+ const versionName = `v${String(version).padStart(3, "0")}_${name}`;
2902
2940
  try {
2903
2941
  const checkResult = await migration.check(options);
2904
2942
  if (checkResult.needsMigration) {
2905
2943
  needsCount++;
2944
+ pendingMigrationNames.push(versionName);
2906
2945
  console.log(` ${versionTag} (${name}): needs migration`);
2907
2946
  if (checkResult.items && checkResult.items.length > 0) {
2908
2947
  for (const item of checkResult.items) {
@@ -2949,11 +2988,19 @@ async function checkMigrations(options) {
2949
2988
  log("Run 'fullstack-cli migration' to apply.");
2950
2989
  }
2951
2990
  summary.needsMigration = needsCount > 0;
2991
+ let finalVersion = currentVersion;
2952
2992
  if (needsCount === 0 && summary.failed.length === 0) {
2953
2993
  setCurrentVersion(latestVersion);
2994
+ finalVersion = latestVersion;
2954
2995
  console.log("");
2955
2996
  log(`Updated migrationVersion to ${latestVersion}.`);
2956
2997
  }
2998
+ printMigrationResult({
2999
+ needMigration: needsCount > 0,
3000
+ migrationVersion: finalVersion,
3001
+ targetVersion: latestVersion,
3002
+ pendingMigrations: pendingMigrationNames
3003
+ });
2957
3004
  return summary;
2958
3005
  }
2959
3006
 
@@ -2971,30 +3018,865 @@ var migrationCommand = {
2971
3018
  migrationCmd.command("check").description("Check pending migrations without applying them").action(async () => {
2972
3019
  const summary = await checkMigrations({});
2973
3020
  if (summary.failed.length > 0) {
2974
- process.exit(2);
2975
- } else if (summary.needsMigration) {
2976
3021
  process.exit(1);
2977
3022
  }
2978
3023
  });
2979
3024
  }
2980
3025
  };
2981
3026
 
3027
+ // src/commands/read-logs/index.ts
3028
+ import path15 from "path";
3029
+
3030
+ // src/commands/read-logs/std-utils.ts
3031
+ import fs15 from "fs";
3032
+ function formatStdPrefixTime(localTime) {
3033
+ const match = localTime.match(/^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/);
3034
+ if (!match) return localTime;
3035
+ const year = Number(match[1]);
3036
+ const month = Number(match[2]);
3037
+ const day = Number(match[3]);
3038
+ const hour = Number(match[4]);
3039
+ const minute = Number(match[5]);
3040
+ const second = Number(match[6]);
3041
+ const date = new Date(year, month - 1, day, hour, minute, second, 0);
3042
+ if (Number.isNaN(date.getTime())) return localTime;
3043
+ const pad2 = (n) => String(n).padStart(2, "0");
3044
+ const tzOffsetMinutes = -date.getTimezoneOffset();
3045
+ const sign = tzOffsetMinutes >= 0 ? "+" : "-";
3046
+ const abs = Math.abs(tzOffsetMinutes);
3047
+ const offsetHH = pad2(Math.floor(abs / 60));
3048
+ const offsetMM = pad2(abs % 60);
3049
+ return `${localTime.replace(" ", "T")}${sign}${offsetHH}:${offsetMM}`;
3050
+ }
3051
+ function stripPrefixFromStdLine(line) {
3052
+ const match = line.match(/^(\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\] \[(server|client)\] )(.*)$/);
3053
+ if (!match) {
3054
+ return line;
3055
+ }
3056
+ const time = formatStdPrefixTime(match[2] || "");
3057
+ const content = match[4] || "";
3058
+ return `[${time}] ${content}`;
3059
+ }
3060
+ function readStdLinesTailFromLastMarkerPaged(filePath, maxLines, offset, isMarker) {
3061
+ const stat = fs15.statSync(filePath);
3062
+ if (stat.size === 0) {
3063
+ return { lines: [], markerFound: false, totalLinesCount: 0 };
3064
+ }
3065
+ const fd = fs15.openSync(filePath, "r");
3066
+ const chunkSize = 64 * 1024;
3067
+ let position = stat.size;
3068
+ let remainder = "";
3069
+ let markerFound = false;
3070
+ let finished = false;
3071
+ let totalLinesCount = 0;
3072
+ let skipped = 0;
3073
+ const collected = [];
3074
+ try {
3075
+ while (position > 0 && !finished) {
3076
+ const length = Math.min(chunkSize, position);
3077
+ position -= length;
3078
+ const buffer = Buffer.alloc(length);
3079
+ fs15.readSync(fd, buffer, 0, length, position);
3080
+ let chunk = buffer.toString("utf8");
3081
+ if (remainder) {
3082
+ chunk += remainder;
3083
+ remainder = "";
3084
+ }
3085
+ const parts = chunk.split("\n");
3086
+ remainder = parts.shift() ?? "";
3087
+ for (let i = parts.length - 1; i >= 0; i -= 1) {
3088
+ const rawLine = parts[i];
3089
+ const line = stripPrefixFromStdLine(rawLine);
3090
+ if (totalLinesCount === 0 && line === "") {
3091
+ continue;
3092
+ }
3093
+ totalLinesCount += 1;
3094
+ if (skipped < offset) {
3095
+ skipped += 1;
3096
+ } else if (collected.length < maxLines) {
3097
+ collected.push(line);
3098
+ }
3099
+ if (isMarker(line)) {
3100
+ markerFound = true;
3101
+ finished = true;
3102
+ break;
3103
+ }
3104
+ }
3105
+ }
3106
+ if (!finished && remainder) {
3107
+ const line = stripPrefixFromStdLine(remainder);
3108
+ if (!(totalLinesCount === 0 && line === "")) {
3109
+ totalLinesCount += 1;
3110
+ if (skipped < offset) {
3111
+ skipped += 1;
3112
+ } else if (collected.length < maxLines) {
3113
+ collected.push(line);
3114
+ }
3115
+ }
3116
+ if (isMarker(line)) {
3117
+ markerFound = true;
3118
+ }
3119
+ }
3120
+ } finally {
3121
+ fs15.closeSync(fd);
3122
+ }
3123
+ return { lines: collected.reverse(), markerFound, totalLinesCount };
3124
+ }
3125
+
3126
+ // src/commands/read-logs/server-std.ts
3127
+ function readServerStdSegment(filePath, maxLines, offset) {
3128
+ const marker = (line) => {
3129
+ if (!line) return false;
3130
+ if (/\bdev:server\b/.test(line)) return true;
3131
+ if (line.includes("Starting compilation in watch mode")) return true;
3132
+ if (line.includes("File change detected. Starting incremental compilation")) return true;
3133
+ if (line.includes("Starting Nest application")) return true;
3134
+ if (line.includes("Nest application successfully started")) return true;
3135
+ return false;
3136
+ };
3137
+ const segment = readStdLinesTailFromLastMarkerPaged(filePath, maxLines, offset, marker);
3138
+ return { lines: segment.lines, totalLinesCount: segment.totalLinesCount };
3139
+ }
3140
+
3141
+ // src/commands/read-logs/tail.ts
3142
+ import fs16 from "fs";
3143
+ function fileExists(filePath) {
3144
+ try {
3145
+ fs16.accessSync(filePath, fs16.constants.F_OK | fs16.constants.R_OK);
3146
+ return true;
3147
+ } catch {
3148
+ return false;
3149
+ }
3150
+ }
3151
+ function readFileTailLines(filePath, maxLines) {
3152
+ const stat = fs16.statSync(filePath);
3153
+ if (stat.size === 0) {
3154
+ return [];
3155
+ }
3156
+ const fd = fs16.openSync(filePath, "r");
3157
+ const chunkSize = 64 * 1024;
3158
+ const chunks = [];
3159
+ let position = stat.size;
3160
+ let collectedLines = 0;
3161
+ try {
3162
+ while (position > 0 && collectedLines <= maxLines) {
3163
+ const length = Math.min(chunkSize, position);
3164
+ position -= length;
3165
+ const buffer = Buffer.alloc(length);
3166
+ fs16.readSync(fd, buffer, 0, length, position);
3167
+ chunks.unshift(buffer.toString("utf8"));
3168
+ const chunkLines = buffer.toString("utf8").split("\n").length - 1;
3169
+ collectedLines += chunkLines;
3170
+ }
3171
+ } finally {
3172
+ fs16.closeSync(fd);
3173
+ }
3174
+ const content = chunks.join("");
3175
+ const allLines = content.split("\n");
3176
+ if (allLines.length === 0) {
3177
+ return [];
3178
+ }
3179
+ if (allLines[allLines.length - 1] === "") {
3180
+ allLines.pop();
3181
+ }
3182
+ if (allLines.length <= maxLines) {
3183
+ return allLines;
3184
+ }
3185
+ return allLines.slice(allLines.length - maxLines);
3186
+ }
3187
+ function readFileTailNonEmptyLinesWithOffset(filePath, maxLines, offset) {
3188
+ const stat = fs16.statSync(filePath);
3189
+ if (stat.size === 0) {
3190
+ return { lines: [], totalLinesCount: 0 };
3191
+ }
3192
+ const fd = fs16.openSync(filePath, "r");
3193
+ const chunkSize = 64 * 1024;
3194
+ let position = stat.size;
3195
+ let remainder = "";
3196
+ let totalLinesCount = 0;
3197
+ let skipped = 0;
3198
+ const collected = [];
3199
+ try {
3200
+ while (position > 0) {
3201
+ const length = Math.min(chunkSize, position);
3202
+ position -= length;
3203
+ const buffer = Buffer.alloc(length);
3204
+ fs16.readSync(fd, buffer, 0, length, position);
3205
+ let chunk = buffer.toString("utf8");
3206
+ if (remainder) {
3207
+ chunk += remainder;
3208
+ remainder = "";
3209
+ }
3210
+ const parts = chunk.split("\n");
3211
+ remainder = parts.shift() ?? "";
3212
+ for (let i = parts.length - 1; i >= 0; i -= 1) {
3213
+ const line = parts[i].trim();
3214
+ if (!line) continue;
3215
+ totalLinesCount += 1;
3216
+ if (skipped < offset) {
3217
+ skipped += 1;
3218
+ } else if (collected.length < maxLines) {
3219
+ collected.push(line);
3220
+ }
3221
+ }
3222
+ }
3223
+ if (remainder) {
3224
+ const line = remainder.trim();
3225
+ if (line) {
3226
+ totalLinesCount += 1;
3227
+ if (skipped < offset) {
3228
+ skipped += 1;
3229
+ } else if (collected.length < maxLines) {
3230
+ collected.push(line);
3231
+ }
3232
+ }
3233
+ }
3234
+ } finally {
3235
+ fs16.closeSync(fd);
3236
+ }
3237
+ return { lines: collected.reverse(), totalLinesCount };
3238
+ }
3239
+
3240
+ // src/commands/read-logs/client-std.ts
3241
+ function readClientStdSegment(filePath, maxLines, offset) {
3242
+ const lines = readFileTailLines(filePath, Math.max((maxLines + offset) * 5, 2e3));
3243
+ return extractClientStdSegment(lines, maxLines, offset);
3244
+ }
3245
+ function extractClientStdSegment(lines, maxLines, offset) {
3246
+ const bodyLines = lines.map(stripPrefixFromStdLine);
3247
+ const hotStartMarkers = [
3248
+ /file change detected\..*incremental compilation/i,
3249
+ /starting incremental compilation/i,
3250
+ /starting compilation/i,
3251
+ /\bcompiling\b/i,
3252
+ /\brecompil/i
3253
+ ];
3254
+ const hotEndMarkers = [
3255
+ /file change detected\..*incremental compilation/i,
3256
+ /\bwebpack compiled\b/i,
3257
+ /compiled successfully/i,
3258
+ /compiled with warnings/i,
3259
+ /compiled with errors/i,
3260
+ /failed to compile/i,
3261
+ /fast refresh/i,
3262
+ /\bhmr\b/i,
3263
+ /hot update/i,
3264
+ /\bhot reload\b/i,
3265
+ /\bhmr update\b/i
3266
+ ];
3267
+ const compiledMarkers = [
3268
+ /\bwebpack compiled\b/i,
3269
+ /compiled successfully/i,
3270
+ /compiled with warnings/i,
3271
+ /compiled with errors/i,
3272
+ /failed to compile/i
3273
+ ];
3274
+ let startIndex = -1;
3275
+ for (let i = bodyLines.length - 1; i >= 0; i -= 1) {
3276
+ const line = bodyLines[i];
3277
+ if (!line) continue;
3278
+ if (hotStartMarkers.some((re) => re.test(line))) {
3279
+ startIndex = i;
3280
+ break;
3281
+ }
3282
+ }
3283
+ if (startIndex === -1) {
3284
+ let pivotIndex = -1;
3285
+ for (let i = bodyLines.length - 1; i >= 0; i -= 1) {
3286
+ const line = bodyLines[i];
3287
+ if (!line) continue;
3288
+ if (hotEndMarkers.some((re) => re.test(line))) {
3289
+ pivotIndex = i;
3290
+ break;
3291
+ }
3292
+ }
3293
+ if (pivotIndex !== -1) {
3294
+ if (compiledMarkers.some((re) => re.test(bodyLines[pivotIndex] ?? ""))) {
3295
+ startIndex = pivotIndex;
3296
+ } else {
3297
+ const searchLimit = 80;
3298
+ const from = Math.max(0, pivotIndex - searchLimit);
3299
+ for (let i = pivotIndex; i >= from; i -= 1) {
3300
+ const line = bodyLines[i];
3301
+ if (!line) continue;
3302
+ if (compiledMarkers.some((re) => re.test(line))) {
3303
+ startIndex = i;
3304
+ break;
3305
+ }
3306
+ }
3307
+ if (startIndex === -1) {
3308
+ startIndex = pivotIndex;
3309
+ }
3310
+ }
3311
+ }
3312
+ }
3313
+ if (startIndex === -1) {
3314
+ for (let i = bodyLines.length - 1; i >= 0; i -= 1) {
3315
+ const line = bodyLines[i];
3316
+ if (!line) continue;
3317
+ if (/\bdev:client\b/.test(line)) {
3318
+ startIndex = i;
3319
+ break;
3320
+ }
3321
+ }
3322
+ }
3323
+ const segment = startIndex === -1 ? bodyLines : bodyLines.slice(startIndex);
3324
+ if (segment.length === 0) {
3325
+ return { lines: [], totalLinesCount: 0 };
3326
+ }
3327
+ const totalLinesCount = segment.length;
3328
+ const endExclusive = Math.max(0, segment.length - offset);
3329
+ const start = Math.max(0, endExclusive - maxLines);
3330
+ return {
3331
+ lines: segment.slice(start, endExclusive),
3332
+ totalLinesCount
3333
+ };
3334
+ }
3335
+
3336
+ // src/commands/read-logs/json-lines.ts
3337
+ import fs17 from "fs";
3338
+ function normalizePid(value) {
3339
+ if (typeof value === "number") {
3340
+ return String(value);
3341
+ }
3342
+ if (typeof value === "string" && value.length > 0) {
3343
+ return value;
3344
+ }
3345
+ return "unknown";
3346
+ }
3347
+ function normalizeLevelName(value) {
3348
+ if (typeof value === "string") {
3349
+ const trimmed = value.trim().toLowerCase();
3350
+ if (!trimmed) return null;
3351
+ if (trimmed === "warning") return "warn";
3352
+ if (trimmed === "err") return "error";
3353
+ const allowed = ["trace", "debug", "info", "warn", "error", "fatal"];
3354
+ return allowed.includes(trimmed) ? trimmed : null;
3355
+ }
3356
+ if (typeof value === "number" && Number.isFinite(value)) {
3357
+ const num = Math.floor(value);
3358
+ if (num <= 10) return "trace";
3359
+ if (num <= 20) return "debug";
3360
+ if (num <= 30) return "info";
3361
+ if (num <= 40) return "warn";
3362
+ if (num <= 50) return "error";
3363
+ return "fatal";
3364
+ }
3365
+ return null;
3366
+ }
3367
+ function extractLevelName(obj) {
3368
+ if (!obj || typeof obj !== "object") return null;
3369
+ const record = obj;
3370
+ const direct = normalizeLevelName(record["level"]);
3371
+ if (direct) return direct;
3372
+ const meta = record["meta"];
3373
+ if (meta && typeof meta === "object") {
3374
+ return normalizeLevelName(meta["level"]);
3375
+ }
3376
+ return null;
3377
+ }
3378
+ function buildWantedLevelSet(levels) {
3379
+ if (!levels || levels.length === 0) return null;
3380
+ const set = /* @__PURE__ */ new Set();
3381
+ for (const raw of levels) {
3382
+ const norm = normalizeLevelName(raw);
3383
+ if (norm) set.add(norm);
3384
+ }
3385
+ return set.size > 0 ? set : null;
3386
+ }
3387
+ function readJsonLinesLastPid(filePath, maxLines, offset, levels) {
3388
+ const stat = fs17.statSync(filePath);
3389
+ if (stat.size === 0) {
3390
+ return { lines: [], totalLinesCount: 0 };
3391
+ }
3392
+ const fd = fs17.openSync(filePath, "r");
3393
+ const chunkSize = 64 * 1024;
3394
+ let position = stat.size;
3395
+ let remainder = "";
3396
+ let targetPid = null;
3397
+ let finished = false;
3398
+ let totalLinesCount = 0;
3399
+ let skipped = 0;
3400
+ const collected = [];
3401
+ const wantedLevelSet = buildWantedLevelSet(levels);
3402
+ try {
3403
+ while (position > 0 && !finished) {
3404
+ const length = Math.min(chunkSize, position);
3405
+ position -= length;
3406
+ const buffer = Buffer.alloc(length);
3407
+ fs17.readSync(fd, buffer, 0, length, position);
3408
+ let chunk = buffer.toString("utf8");
3409
+ if (remainder) {
3410
+ chunk += remainder;
3411
+ remainder = "";
3412
+ }
3413
+ const parts = chunk.split("\n");
3414
+ remainder = parts.shift() ?? "";
3415
+ for (let i = parts.length - 1; i >= 0; i -= 1) {
3416
+ const line = parts[i].trim();
3417
+ if (!line) continue;
3418
+ let parsed = null;
3419
+ try {
3420
+ parsed = JSON.parse(line);
3421
+ } catch {
3422
+ continue;
3423
+ }
3424
+ const pid = normalizePid(parsed?.pid);
3425
+ if (targetPid === null) {
3426
+ targetPid = pid;
3427
+ }
3428
+ if (pid !== targetPid) {
3429
+ finished = true;
3430
+ break;
3431
+ }
3432
+ const levelName = extractLevelName(parsed);
3433
+ if (!wantedLevelSet || levelName && wantedLevelSet.has(levelName)) {
3434
+ totalLinesCount += 1;
3435
+ if (skipped < offset) {
3436
+ skipped += 1;
3437
+ } else if (collected.length < maxLines) {
3438
+ collected.push(line);
3439
+ }
3440
+ }
3441
+ }
3442
+ }
3443
+ if (!finished && remainder) {
3444
+ const line = remainder.trim();
3445
+ if (line) {
3446
+ try {
3447
+ const parsed = JSON.parse(line);
3448
+ const pid = normalizePid(parsed?.pid);
3449
+ if (targetPid === null) {
3450
+ targetPid = pid;
3451
+ }
3452
+ if (pid === targetPid) {
3453
+ const levelName = extractLevelName(parsed);
3454
+ if (!wantedLevelSet || levelName && wantedLevelSet.has(levelName)) {
3455
+ totalLinesCount += 1;
3456
+ if (skipped < offset) {
3457
+ skipped += 1;
3458
+ } else if (collected.length < maxLines) {
3459
+ collected.push(line);
3460
+ }
3461
+ }
3462
+ }
3463
+ } catch {
3464
+ return { lines: [], totalLinesCount: 0 };
3465
+ }
3466
+ }
3467
+ }
3468
+ } finally {
3469
+ fs17.closeSync(fd);
3470
+ }
3471
+ return { lines: collected.reverse(), totalLinesCount };
3472
+ }
3473
+ function normalizeTraceId(value) {
3474
+ if (typeof value === "string") {
3475
+ const trimmed = value.trim();
3476
+ return trimmed ? trimmed : null;
3477
+ }
3478
+ if (typeof value === "number" && Number.isFinite(value)) {
3479
+ return String(value);
3480
+ }
3481
+ return null;
3482
+ }
3483
+ function extractTraceId(obj) {
3484
+ if (!obj || typeof obj !== "object") return null;
3485
+ const record = obj;
3486
+ const directKeys = ["trace_id", "traceId", "traceID", "traceid"];
3487
+ for (const key of directKeys) {
3488
+ const value = normalizeTraceId(record[key]);
3489
+ if (value) return value;
3490
+ }
3491
+ const meta = record["meta"];
3492
+ if (meta && typeof meta === "object") {
3493
+ const metaRecord = meta;
3494
+ for (const key of directKeys) {
3495
+ const value = normalizeTraceId(metaRecord[key]);
3496
+ if (value) return value;
3497
+ }
3498
+ }
3499
+ const attributes = record["attributes"];
3500
+ if (attributes && typeof attributes === "object") {
3501
+ const attrRecord = attributes;
3502
+ for (const key of ["traceID", "trace_id", "traceId", "traceid"]) {
3503
+ const value = normalizeTraceId(attrRecord[key]);
3504
+ if (value) return value;
3505
+ }
3506
+ }
3507
+ return null;
3508
+ }
3509
+ function readJsonLinesByTraceId(filePath, traceId, maxLines, offset, levels) {
3510
+ const wanted = traceId.trim();
3511
+ if (!wanted) return { lines: [], totalLinesCount: 0 };
3512
+ const stat = fs17.statSync(filePath);
3513
+ if (stat.size === 0) {
3514
+ return { lines: [], totalLinesCount: 0 };
3515
+ }
3516
+ const fd = fs17.openSync(filePath, "r");
3517
+ const chunkSize = 64 * 1024;
3518
+ let position = stat.size;
3519
+ let remainder = "";
3520
+ let totalLinesCount = 0;
3521
+ let skipped = 0;
3522
+ const collected = [];
3523
+ const wantedLevelSet = buildWantedLevelSet(levels);
3524
+ try {
3525
+ while (position > 0) {
3526
+ const length = Math.min(chunkSize, position);
3527
+ position -= length;
3528
+ const buffer = Buffer.alloc(length);
3529
+ fs17.readSync(fd, buffer, 0, length, position);
3530
+ let chunk = buffer.toString("utf8");
3531
+ if (remainder) {
3532
+ chunk += remainder;
3533
+ remainder = "";
3534
+ }
3535
+ const parts = chunk.split("\n");
3536
+ remainder = parts.shift() ?? "";
3537
+ for (let i = parts.length - 1; i >= 0; i -= 1) {
3538
+ const line = parts[i].trim();
3539
+ if (!line) continue;
3540
+ try {
3541
+ const parsed = JSON.parse(line);
3542
+ const lineTraceId = extractTraceId(parsed);
3543
+ if (lineTraceId === wanted) {
3544
+ const levelName = extractLevelName(parsed);
3545
+ if (!wantedLevelSet || levelName && wantedLevelSet.has(levelName)) {
3546
+ totalLinesCount += 1;
3547
+ if (skipped < offset) {
3548
+ skipped += 1;
3549
+ } else if (collected.length < maxLines) {
3550
+ collected.push(line);
3551
+ }
3552
+ }
3553
+ }
3554
+ } catch {
3555
+ continue;
3556
+ }
3557
+ }
3558
+ }
3559
+ if (remainder) {
3560
+ const line = remainder.trim();
3561
+ if (line) {
3562
+ try {
3563
+ const parsed = JSON.parse(line);
3564
+ const lineTraceId = extractTraceId(parsed);
3565
+ if (lineTraceId === wanted) {
3566
+ const levelName = extractLevelName(parsed);
3567
+ if (!wantedLevelSet || levelName && wantedLevelSet.has(levelName)) {
3568
+ totalLinesCount += 1;
3569
+ if (skipped < offset) {
3570
+ skipped += 1;
3571
+ } else if (collected.length < maxLines) {
3572
+ collected.push(line);
3573
+ }
3574
+ }
3575
+ }
3576
+ } catch {
3577
+ return { lines: [], totalLinesCount: 0 };
3578
+ }
3579
+ }
3580
+ }
3581
+ } finally {
3582
+ fs17.closeSync(fd);
3583
+ }
3584
+ return { lines: collected.reverse(), totalLinesCount };
3585
+ }
3586
+ function readJsonLinesTailByLevel(filePath, maxLines, offset, levels) {
3587
+ const wantedLevelSet = buildWantedLevelSet(levels);
3588
+ if (!wantedLevelSet) {
3589
+ return { lines: [], totalLinesCount: 0 };
3590
+ }
3591
+ const stat = fs17.statSync(filePath);
3592
+ if (stat.size === 0) {
3593
+ return { lines: [], totalLinesCount: 0 };
3594
+ }
3595
+ const fd = fs17.openSync(filePath, "r");
3596
+ const chunkSize = 64 * 1024;
3597
+ let position = stat.size;
3598
+ let remainder = "";
3599
+ let totalLinesCount = 0;
3600
+ let skipped = 0;
3601
+ const collected = [];
3602
+ try {
3603
+ while (position > 0) {
3604
+ const length = Math.min(chunkSize, position);
3605
+ position -= length;
3606
+ const buffer = Buffer.alloc(length);
3607
+ fs17.readSync(fd, buffer, 0, length, position);
3608
+ let chunk = buffer.toString("utf8");
3609
+ if (remainder) {
3610
+ chunk += remainder;
3611
+ remainder = "";
3612
+ }
3613
+ const parts = chunk.split("\n");
3614
+ remainder = parts.shift() ?? "";
3615
+ for (let i = parts.length - 1; i >= 0; i -= 1) {
3616
+ const line = parts[i].trim();
3617
+ if (!line) continue;
3618
+ try {
3619
+ const parsed = JSON.parse(line);
3620
+ const levelName = extractLevelName(parsed);
3621
+ if (levelName && wantedLevelSet.has(levelName)) {
3622
+ totalLinesCount += 1;
3623
+ if (skipped < offset) {
3624
+ skipped += 1;
3625
+ } else if (collected.length < maxLines) {
3626
+ collected.push(line);
3627
+ }
3628
+ }
3629
+ } catch {
3630
+ continue;
3631
+ }
3632
+ }
3633
+ }
3634
+ if (remainder) {
3635
+ const line = remainder.trim();
3636
+ if (line) {
3637
+ try {
3638
+ const parsed = JSON.parse(line);
3639
+ const levelName = extractLevelName(parsed);
3640
+ if (levelName && wantedLevelSet.has(levelName)) {
3641
+ totalLinesCount += 1;
3642
+ if (skipped < offset) {
3643
+ skipped += 1;
3644
+ } else if (collected.length < maxLines) {
3645
+ collected.push(line);
3646
+ }
3647
+ }
3648
+ } catch {
3649
+ return { lines: [], totalLinesCount: 0 };
3650
+ }
3651
+ }
3652
+ }
3653
+ } finally {
3654
+ fs17.closeSync(fd);
3655
+ }
3656
+ return { lines: collected.reverse(), totalLinesCount };
3657
+ }
3658
+
3659
+ // src/commands/read-logs/index.ts
3660
+ var LOG_TYPES = ["server", "trace", "server-std", "client-std", "browser"];
3661
+ function sanitizeStructuredLog(value) {
3662
+ if (!value || typeof value !== "object") return value;
3663
+ if (Array.isArray(value)) return value;
3664
+ const obj = value;
3665
+ const sanitized = { ...obj };
3666
+ delete sanitized.tenant_id;
3667
+ delete sanitized.app_id;
3668
+ delete sanitized.pid;
3669
+ return sanitized;
3670
+ }
3671
+ function hasErrorInStdLines(lines) {
3672
+ const combined = lines.join("\n");
3673
+ if (!combined) return false;
3674
+ const strong = [
3675
+ /compiled with errors/i,
3676
+ /failed to compile/i,
3677
+ /error: \w+/i,
3678
+ /uncaught/i,
3679
+ /unhandled/i,
3680
+ /eaddrinuse/i,
3681
+ /cannot find module/i,
3682
+ /module not found/i,
3683
+ /ts\d{3,5}:/i
3684
+ ];
3685
+ if (strong.some((re) => re.test(combined))) return true;
3686
+ const weakLine = /\b(error|fatal|exception)\b/i;
3687
+ const ignorePatterns = [
3688
+ /\b0\s+errors?\b/i,
3689
+ /Server Error \d{3}/i
3690
+ ];
3691
+ return lines.some((line) => {
3692
+ const text = line.trim();
3693
+ if (!text) return false;
3694
+ if (ignorePatterns.some((re) => re.test(text))) return false;
3695
+ return weakLine.test(text);
3696
+ });
3697
+ }
3698
+ function hasErrorInLogObject(value) {
3699
+ if (!value || typeof value !== "object") return false;
3700
+ const obj = value;
3701
+ const rawLevel = obj.level;
3702
+ const level = typeof rawLevel === "string" ? rawLevel.toLowerCase() : "";
3703
+ if (level === "error" || level === "fatal") return true;
3704
+ if (level === "err") return true;
3705
+ if (typeof rawLevel === "number" && Number.isFinite(rawLevel) && rawLevel >= 50) return true;
3706
+ if (level === "warn" && typeof obj.stack === "string" && obj.stack.length > 0) return true;
3707
+ if (typeof obj.stack === "string" && obj.stack.length > 0) return true;
3708
+ const statusCode = obj.statusCode;
3709
+ const status_code = obj.status_code;
3710
+ const meta = obj.meta;
3711
+ const metaObj = meta && typeof meta === "object" ? meta : null;
3712
+ const metaStatusCode = metaObj?.statusCode;
3713
+ const metaStatus_code = metaObj?.status_code;
3714
+ const candidates = [statusCode, status_code, metaStatusCode, metaStatus_code];
3715
+ for (const candidate of candidates) {
3716
+ if (typeof candidate === "number" && Number.isFinite(candidate) && candidate >= 400) {
3717
+ return true;
3718
+ }
3719
+ }
3720
+ const message = typeof obj.message === "string" ? obj.message : "";
3721
+ if (message && hasErrorInStdLines([message])) return true;
3722
+ return false;
3723
+ }
3724
+ async function readLatestLogLinesMeta(options) {
3725
+ const maxLines = options.maxLines ?? 30;
3726
+ const offset = options.offset ?? 0;
3727
+ const filePath = resolveLogFilePath(options.logDir, options.type);
3728
+ const levels = Array.isArray(options.levels) ? options.levels : void 0;
3729
+ if (!fileExists(filePath)) {
3730
+ throw new Error(`Log file not found: ${filePath}`);
3731
+ }
3732
+ if (options.type === "server-std") {
3733
+ return readServerStdSegment(filePath, maxLines, offset);
3734
+ }
3735
+ if (options.type === "client-std") {
3736
+ return readClientStdSegment(filePath, maxLines, offset);
3737
+ }
3738
+ const traceId = typeof options.traceId === "string" ? options.traceId.trim() : "";
3739
+ if (traceId) {
3740
+ return readJsonLinesByTraceId(filePath, traceId, maxLines, offset, levels);
3741
+ }
3742
+ if (options.type === "server" || options.type === "trace") {
3743
+ return readJsonLinesLastPid(filePath, maxLines, offset, levels);
3744
+ }
3745
+ if (options.type === "browser") {
3746
+ if (levels && levels.length > 0) {
3747
+ return readJsonLinesTailByLevel(filePath, maxLines, offset, levels);
3748
+ }
3749
+ return readFileTailNonEmptyLinesWithOffset(filePath, maxLines, offset);
3750
+ }
3751
+ return { lines: [], totalLinesCount: 0 };
3752
+ }
3753
+ async function readLogsJsonResult(options) {
3754
+ const { lines, totalLinesCount } = await readLatestLogLinesMeta(options);
3755
+ if (options.type === "server-std" || options.type === "client-std") {
3756
+ return {
3757
+ hasError: hasErrorInStdLines(lines),
3758
+ totalLinesCount,
3759
+ logs: lines
3760
+ };
3761
+ }
3762
+ const logs = [];
3763
+ let hasError = false;
3764
+ for (const line of lines) {
3765
+ if (!hasError && hasErrorInStdLines([line])) {
3766
+ hasError = true;
3767
+ }
3768
+ try {
3769
+ const parsed = JSON.parse(line);
3770
+ logs.push(sanitizeStructuredLog(parsed));
3771
+ if (!hasError && hasErrorInLogObject(parsed)) {
3772
+ hasError = true;
3773
+ }
3774
+ } catch {
3775
+ continue;
3776
+ }
3777
+ }
3778
+ return {
3779
+ hasError,
3780
+ totalLinesCount,
3781
+ logs
3782
+ };
3783
+ }
3784
+ function resolveLogFilePath(logDir, type) {
3785
+ const base = path15.isAbsolute(logDir) ? logDir : path15.join(process.cwd(), logDir);
3786
+ if (type === "server") {
3787
+ return path15.join(base, "server.log");
3788
+ }
3789
+ if (type === "trace") {
3790
+ return path15.join(base, "trace.log");
3791
+ }
3792
+ if (type === "server-std") {
3793
+ return path15.join(base, "server.std.log");
3794
+ }
3795
+ if (type === "client-std") {
3796
+ return path15.join(base, "client.std.log");
3797
+ }
3798
+ if (type === "browser") {
3799
+ return path15.join(base, "browser.log");
3800
+ }
3801
+ throw new Error(`Unsupported log type: ${type}`);
3802
+ }
3803
+ async function run4(options) {
3804
+ try {
3805
+ const result = await readLogsJsonResult(options);
3806
+ process.stdout.write(JSON.stringify(result) + "\n");
3807
+ } catch (error) {
3808
+ const message = error instanceof Error ? error.message : String(error);
3809
+ const result = { hasError: true, totalLinesCount: 0, logs: [message] };
3810
+ process.stdout.write(JSON.stringify(result) + "\n");
3811
+ process.exitCode = 1;
3812
+ }
3813
+ }
3814
+ function parseLogType(input) {
3815
+ const value = typeof input === "string" ? input.trim() : "";
3816
+ if (LOG_TYPES.includes(value)) {
3817
+ return value;
3818
+ }
3819
+ throw new Error(`Invalid --type: ${String(input)}. Expected one of: ${LOG_TYPES.join(", ")}`);
3820
+ }
3821
+ function parsePositiveInt(input, flagName) {
3822
+ const value = typeof input === "number" ? input : Number.parseInt(String(input), 10);
3823
+ if (!Number.isFinite(value) || value <= 0) {
3824
+ throw new Error(`Invalid ${flagName}: ${String(input)}. Expected a positive integer.`);
3825
+ }
3826
+ return value;
3827
+ }
3828
+ function parseNonNegativeInt(input, flagName) {
3829
+ const value = typeof input === "number" ? input : Number.parseInt(String(input), 10);
3830
+ if (!Number.isFinite(value) || value < 0) {
3831
+ throw new Error(`Invalid ${flagName}: ${String(input)}. Expected a non-negative integer.`);
3832
+ }
3833
+ return value;
3834
+ }
3835
+ function parseCommaSeparatedList(input) {
3836
+ const value = typeof input === "string" ? input : "";
3837
+ const items = value.split(",").map((s) => s.trim()).filter(Boolean);
3838
+ return items.length > 0 ? items : void 0;
3839
+ }
3840
+ var readLogsCommand = {
3841
+ name: "read-logs",
3842
+ description: "Read latest logs from log files",
3843
+ register(program) {
3844
+ program.command(this.name).description(this.description).option("--dir <path>", "Logs directory", "logs").option("--type <type>", `Log type: ${LOG_TYPES.join("|")}`, "server-std").option("--max-lines <lines>", "Max lines to return", "30").option("--offset <lines>", "Skip latest N lines for pagination", "0").option("--trace-id <id>", "Filter structured logs by trace id").option("--level <levels>", "Filter structured logs by level (comma-separated)").action(async (rawOptions) => {
3845
+ try {
3846
+ const logDir = typeof rawOptions.dir === "string" ? rawOptions.dir : "logs";
3847
+ const type = parseLogType(rawOptions.type);
3848
+ const maxLines = parsePositiveInt(rawOptions.maxLines, "--max-lines");
3849
+ const offset = parseNonNegativeInt(rawOptions.offset, "--offset");
3850
+ const traceId = typeof rawOptions.traceId === "string" ? rawOptions.traceId : void 0;
3851
+ const levels = parseCommaSeparatedList(rawOptions.level);
3852
+ await run4({ logDir, type, maxLines, offset, traceId, levels });
3853
+ } catch (error) {
3854
+ const message = error instanceof Error ? error.message : String(error);
3855
+ const result = { hasError: true, totalLinesCount: 0, logs: [message] };
3856
+ process.stdout.write(JSON.stringify(result) + "\n");
3857
+ process.exitCode = 1;
3858
+ }
3859
+ });
3860
+ }
3861
+ };
3862
+
2982
3863
  // src/commands/index.ts
2983
3864
  var commands = [
2984
3865
  genDbSchemaCommand,
2985
3866
  syncCommand,
2986
3867
  actionPluginCommandGroup,
2987
3868
  capabilityCommandGroup,
2988
- migrationCommand
3869
+ migrationCommand,
3870
+ readLogsCommand
2989
3871
  ];
2990
3872
 
2991
3873
  // src/index.ts
2992
- var envPath = path14.join(process.cwd(), ".env");
2993
- if (fs14.existsSync(envPath)) {
3874
+ var envPath = path16.join(process.cwd(), ".env");
3875
+ if (fs18.existsSync(envPath)) {
2994
3876
  dotenvConfig({ path: envPath });
2995
3877
  }
2996
- var __dirname = path14.dirname(fileURLToPath3(import.meta.url));
2997
- var pkg = JSON.parse(fs14.readFileSync(path14.join(__dirname, "../package.json"), "utf-8"));
3878
+ var __dirname = path16.dirname(fileURLToPath3(import.meta.url));
3879
+ var pkg = JSON.parse(fs18.readFileSync(path16.join(__dirname, "../package.json"), "utf-8"));
2998
3880
  var cli = new FullstackCLI(pkg.version);
2999
3881
  cli.useAll(commands);
3000
3882
  cli.run();