@lark-apaas/fullstack-cli 1.1.11 → 1.1.12-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +1366 -228
  2. package/package.json +4 -3
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/index.ts
2
- import fs18 from "fs";
3
- import path16 from "path";
2
+ import fs19 from "fs";
3
+ import path17 from "path";
4
4
  import { fileURLToPath as fileURLToPath3 } from "url";
5
5
  import { config as dotenvConfig } from "dotenv";
6
6
 
@@ -116,17 +116,1157 @@ Command "${ctx.commandName}" completed in ${elapsed}ms`);
116
116
  };
117
117
 
118
118
  // src/commands/db/schema.handler.ts
119
- import path from "path";
120
- import fs from "fs";
119
+ import path2 from "path";
120
+ import fs2 from "fs";
121
121
  import { fileURLToPath } from "url";
122
122
  import { spawnSync } from "child_process";
123
- import { createRequire } from "module";
124
123
  import { config as loadEnv } from "dotenv";
125
- var require2 = createRequire(import.meta.url);
124
+
125
+ // src/internal/postprocess-drizzle-schema.ts
126
+ import fs from "fs";
127
+ import path from "path";
128
+ import { pinyin } from "pinyin-pro";
129
+ var HEADER_COMMENT = "/** auto generated, do not edit */";
130
+ var CUSTOM_TYPE_PATTERN = /\/\/ TODO: failed to parse database type '(?:\w+\.)?(user_profile|file_attachment)(\[\])?'/;
131
+ var TEMPLATE_TYPES_TS = `import { sql } from 'drizzle-orm';
132
+ import { customType } from 'drizzle-orm/pg-core';
133
+
134
+ export const userProfile = customType<{
135
+ data: string;
136
+ driverData: string;
137
+ }>({
138
+ dataType() {
139
+ return 'user_profile';
140
+ },
141
+ toDriver(value: string) {
142
+ return sql\`ROW(\${value})::user_profile\`;
143
+ },
144
+ fromDriver(value: string) {
145
+ const [userId] = value.slice(1, -1).split(',');
146
+ return userId.trim();
147
+ },
148
+ });
149
+
150
+ export type FileAttachment = {
151
+ bucket_id: string;
152
+ file_path: string;
153
+ };
154
+
155
+ export const fileAttachment = customType<{
156
+ data: FileAttachment;
157
+ driverData: string;
158
+ }>({
159
+ dataType() {
160
+ return 'file_attachment';
161
+ },
162
+ toDriver(value: FileAttachment) {
163
+ return sql\`ROW(\${value.bucket_id},\${value.file_path})::file_attachment\`;
164
+ },
165
+ fromDriver(value: string): FileAttachment {
166
+ const [bucketId, filePath] = value.slice(1, -1).split(',');
167
+ return { bucket_id: bucketId.trim(), file_path: filePath.trim() };
168
+ },
169
+ });
170
+
171
+ export const customTimestamptz = customType<{
172
+ data: Date;
173
+ driverData: string;
174
+ config: { precision?: number};
175
+ }>({
176
+ dataType(config) {
177
+ const precision = typeof config?.precision !== 'undefined'
178
+ ? \` (\${config.precision})\`
179
+ : '';
180
+ return \`timestamptz\${precision}\`;
181
+ },
182
+ toDriver(value: Date | string | number){
183
+ if(value == null) return value as any;
184
+ if (typeof value === 'number') {
185
+ return new Date(value).toISOString();
186
+ }
187
+ if(typeof value === 'string') {
188
+ return value;
189
+ }
190
+ if (value instanceof Date) {
191
+ return value.toISOString();
192
+ }
193
+ throw new Error('Invalid timestamp value');
194
+ },
195
+ fromDriver(value: string | Date): Date {
196
+ if(value instanceof Date) return value;
197
+ return new Date(value);
198
+ },
199
+ });
200
+ `;
201
+ function stripLeadingNewlines(value) {
202
+ let current = value;
203
+ while (current.startsWith("\r\n") || current.startsWith("\n")) {
204
+ current = current.startsWith("\r\n") ? current.slice(2) : current.slice(1);
205
+ }
206
+ return current;
207
+ }
208
+ function ensureHeaderComment(source) {
209
+ let text = source.startsWith("\uFEFF") ? source.slice(1) : source;
210
+ while (text.startsWith(HEADER_COMMENT)) {
211
+ text = text.slice(HEADER_COMMENT.length);
212
+ text = stripLeadingNewlines(text);
213
+ }
214
+ const trimmed = stripLeadingNewlines(text);
215
+ if (trimmed.length === 0) {
216
+ return `${HEADER_COMMENT}
217
+ `;
218
+ }
219
+ return `${HEADER_COMMENT}
220
+ ${trimmed}`;
221
+ }
222
+ function collapseExtraBlankLines(text) {
223
+ return text.replace(/\n{3,}/g, "\n\n");
224
+ }
225
+ function patchDrizzleKitDefects(source) {
226
+ let fixed = 0;
227
+ const text = source.replace(/\.default\('\)/g, () => {
228
+ fixed += 1;
229
+ return `.default('')`;
230
+ });
231
+ return { text, fixed };
232
+ }
233
+ function removePgSchemaDeclarations(source) {
234
+ return source.replace(/export const \w+ = pgSchema\([\s\S]*?\);\n*/g, "");
235
+ }
236
+ function convertSchemaTableInvocations(source) {
237
+ let converted = 0;
238
+ let text = source.replace(/([A-Za-z0-9_]+)\.table\(/g, () => {
239
+ converted += 1;
240
+ return "pgTable(";
241
+ });
242
+ text = text.replace(/([A-Za-z0-9_]+)\.view\(/g, () => {
243
+ converted += 1;
244
+ return "pgView(";
245
+ });
246
+ text = text.replace(/([A-Za-z0-9_]+)\.materializedView\(/g, () => {
247
+ converted += 1;
248
+ return "pgMaterializedView(";
249
+ });
250
+ text = text.replace(/([A-Za-z0-9_]+)\.enum\(/g, () => {
251
+ converted += 1;
252
+ return "pgEnum(";
253
+ });
254
+ text = text.replace(/([A-Za-z0-9_]+)\.sequence\(/g, () => {
255
+ converted += 1;
256
+ return "pgSequence(";
257
+ });
258
+ return { text, converted };
259
+ }
260
+ function escapeRegExp(value) {
261
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace(/\//g, "\\/");
262
+ }
263
+ function toCamelCase(str) {
264
+ const words = str.split(/[_\-\s]+/).filter(Boolean);
265
+ if (words.length === 0) {
266
+ return "";
267
+ }
268
+ return words.map((word, index) => {
269
+ if (index === 0) {
270
+ return word.toLowerCase();
271
+ }
272
+ return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
273
+ }).join("");
274
+ }
275
+ function toAsciiName(name) {
276
+ let hasNonAscii = false;
277
+ for (let i = 0; i < name.length; i += 1) {
278
+ if (name.charCodeAt(i) > 127) {
279
+ hasNonAscii = true;
280
+ break;
281
+ }
282
+ }
283
+ if (!hasNonAscii) {
284
+ return name;
285
+ }
286
+ try {
287
+ const transliterated = pinyin(name, { toneType: "none", type: "array" }).join("_");
288
+ return transliterated || name;
289
+ } catch {
290
+ return name;
291
+ }
292
+ }
293
+ function sanitizeIdentifier(name) {
294
+ const asciiName = toAsciiName(name);
295
+ let sanitized = asciiName.replace(/[^A-Za-z0-9_]/g, "_");
296
+ sanitized = sanitized.replace(/_+/g, "_");
297
+ sanitized = sanitized.replace(/^_|_$/g, "");
298
+ sanitized = toCamelCase(sanitized);
299
+ if (!sanitized) {
300
+ sanitized = "table";
301
+ }
302
+ if (!/^[A-Za-z_]/.test(sanitized)) {
303
+ sanitized = `_${sanitized}`;
304
+ }
305
+ return sanitized;
306
+ }
307
+ function renamePgTableConstants(source) {
308
+ const pgTableRegex = /export const\s+([^\s=]+)\s*=\s*(pgTable|pgView|pgMaterializedView)\(\s*["'`]([^"'`]+)["'`]/gu;
309
+ const renames = [];
310
+ const updated = source.replace(pgTableRegex, (match, currentName, factory, tableName) => {
311
+ const sanitized = sanitizeIdentifier(tableName);
312
+ if (sanitized === currentName) {
313
+ return match;
314
+ }
315
+ renames.push({ from: currentName, to: sanitized });
316
+ const equalsIndex = match.indexOf("=");
317
+ const suffix = equalsIndex >= 0 ? match.slice(equalsIndex) : ` = ${factory}("${tableName}"`;
318
+ const normalizedSuffix = suffix.trimStart();
319
+ return `export const ${sanitized} ${normalizedSuffix}`;
320
+ });
321
+ return { text: updated, renames };
322
+ }
323
+ function updateTableReferenceIdentifiers(source, renames) {
324
+ if (renames.length === 0) {
325
+ return source;
326
+ }
327
+ return renames.reduce((acc, rename) => {
328
+ if (!rename.from || rename.from === rename.to) {
329
+ return acc;
330
+ }
331
+ const pattern = new RegExp(`\\b${escapeRegExp(rename.from)}(\\s*\\.)`, "g");
332
+ return acc.replace(pattern, `${rename.to}$1`);
333
+ }, source);
334
+ }
335
+ function replaceFollowingUnknown(nextLine, factory) {
336
+ if (!nextLine || !nextLine.includes("unknown(")) {
337
+ return void 0;
338
+ }
339
+ return nextLine.replace("unknown(", `${factory}(`);
340
+ }
341
+ function replaceUnknownColumns(source) {
342
+ const lines = source.split("\n");
343
+ const result = [];
344
+ let replaced = 0;
345
+ const unmatched = [];
346
+ for (let i = 0; i < lines.length; i += 1) {
347
+ const line = lines[i];
348
+ const match = line.match(CUSTOM_TYPE_PATTERN);
349
+ if (match) {
350
+ const typeName = match[1];
351
+ const factory = typeName === "user_profile" ? "userProfile" : "fileAttachment";
352
+ const replacedLine = replaceFollowingUnknown(lines[i + 1], factory);
353
+ if (replacedLine) {
354
+ result.push(replacedLine);
355
+ replaced += 1;
356
+ i += 1;
357
+ } else {
358
+ unmatched.push(line.trim());
359
+ result.push(line);
360
+ }
361
+ continue;
362
+ }
363
+ if (line.includes("unknown(")) {
364
+ unmatched.push(line.trim());
365
+ }
366
+ result.push(line);
367
+ }
368
+ return { text: result.join("\n"), replaced, unmatched };
369
+ }
370
+ function ensureImportIdentifier(source, packageName, identifier) {
371
+ const escapedPackage = packageName.replace(/\//g, "\\/");
372
+ const importRegex = new RegExp(`import \\{([^}]*)\\} from ["']${escapedPackage}["'];?`);
373
+ const match = source.match(importRegex);
374
+ if (!match) {
375
+ return source;
376
+ }
377
+ const identifiers = match[1].split(",").map((id) => id.trim()).filter(Boolean);
378
+ if (identifiers.includes(identifier)) {
379
+ return source;
380
+ }
381
+ identifiers.push(identifier);
382
+ const unique = Array.from(new Set(identifiers));
383
+ const replacement = `import { ${unique.join(", ")} } from "${packageName}"`;
384
+ return source.replace(importRegex, replacement);
385
+ }
386
+ function tweakImports(source) {
387
+ const importRegex = /import \{([^}]*)\} from "drizzle-orm\/pg-core";?/;
388
+ const match = source.match(importRegex);
389
+ if (!match) {
390
+ return source;
391
+ }
392
+ const identifiers = match[1].split(",").map((id) => id.trim()).filter(Boolean).filter((id) => id !== "pgSchema" && id !== "customType");
393
+ const filteredIdentifiers = identifiers.filter((id) => {
394
+ if (id === "timestamp") {
395
+ const timestampUsageRegex = /timestamp\s*\(/;
396
+ return timestampUsageRegex.test(source);
397
+ }
398
+ return true;
399
+ });
400
+ if (source.includes("pgTable(") && !filteredIdentifiers.includes("pgTable")) {
401
+ filteredIdentifiers.push("pgTable");
402
+ }
403
+ if (source.includes("pgView(") && !filteredIdentifiers.includes("pgView")) {
404
+ filteredIdentifiers.push("pgView");
405
+ }
406
+ if (source.includes("pgMaterializedView(") && !filteredIdentifiers.includes("pgMaterializedView")) {
407
+ filteredIdentifiers.push("pgMaterializedView");
408
+ }
409
+ if (source.includes("pgEnum(") && !filteredIdentifiers.includes("pgEnum")) {
410
+ filteredIdentifiers.push("pgEnum");
411
+ }
412
+ if (source.includes("pgSequence(") && !filteredIdentifiers.includes("pgSequence")) {
413
+ filteredIdentifiers.push("pgSequence");
414
+ }
415
+ const unique = Array.from(new Set(filteredIdentifiers));
416
+ const replacement = `import { ${unique.join(", ")} } from "drizzle-orm/pg-core"`;
417
+ return source.replace(importRegex, replacement);
418
+ }
419
+ function inlineFromTemplate(text, templateContent) {
420
+ const typeDefinitions = templateContent.replace(/^import\s+.*;\r?\n*/gm, "").trim();
421
+ const needsSql = typeDefinitions.includes("sql`") && !text.includes("from 'drizzle-orm'") && !text.includes('from "drizzle-orm"');
422
+ const needsCustomType = typeDefinitions.includes("customType<") && !text.includes("customType");
423
+ if (needsCustomType) {
424
+ text = ensureImportIdentifier(text, "drizzle-orm/pg-core", "customType");
425
+ }
426
+ if (needsSql && !text.includes("from 'drizzle-orm'") && !text.includes('from "drizzle-orm"')) {
427
+ const importMatch = text.match(/^import [\s\S]*?from ["']drizzle-orm\/pg-core["'];?\n/m);
428
+ if (importMatch) {
429
+ const insertPoint = text.indexOf(importMatch[0]) + importMatch[0].length;
430
+ text = text.slice(0, insertPoint) + "import { sql } from 'drizzle-orm';\n" + text.slice(insertPoint);
431
+ }
432
+ }
433
+ const headerPrefix = `${HEADER_COMMENT}
434
+ `;
435
+ let insertionPoint = 0;
436
+ if (text.startsWith(headerPrefix)) {
437
+ insertionPoint = headerPrefix.length;
438
+ }
439
+ const importSectionMatch = text.slice(insertionPoint).match(/^(?:import [^\n]+\n)+/);
440
+ if (importSectionMatch) {
441
+ insertionPoint += importSectionMatch[0].length;
442
+ }
443
+ const typeBlock = `
444
+ ${typeDefinitions}
445
+
446
+ `;
447
+ return text.slice(0, insertionPoint) + typeBlock + text.slice(insertionPoint);
448
+ }
449
+ function inlineCustomTypes(source) {
450
+ const text = source.replace(/import \{[^}]*\} from ["']\.\/types["'];?\n*/g, "");
451
+ return inlineFromTemplate(text, TEMPLATE_TYPES_TS);
452
+ }
453
+ function removeConflictingSystemFields(source) {
454
+ const systemFieldMap = {
455
+ _created_at: "created_at",
456
+ _created_by: "created_by",
457
+ _updated_at: "updated_at",
458
+ _updated_by: "updated_by"
459
+ };
460
+ const lines = source.split("\n");
461
+ const result = [];
462
+ let inTable = false;
463
+ let tableStartLine = -1;
464
+ const tableBusinessFields = /* @__PURE__ */ new Set();
465
+ let bracketDepth = 0;
466
+ for (let i = 0; i < lines.length; i += 1) {
467
+ const line = lines[i];
468
+ if (!inTable && /=\s*(pgTable|pgView|pgMaterializedView)\s*\(/.test(line)) {
469
+ inTable = true;
470
+ tableStartLine = result.length;
471
+ tableBusinessFields.clear();
472
+ bracketDepth = 0;
473
+ }
474
+ if (inTable) {
475
+ for (const char of line) {
476
+ if (char === "{") bracketDepth += 1;
477
+ if (char === "}") bracketDepth -= 1;
478
+ }
479
+ for (const businessField of Object.values(systemFieldMap)) {
480
+ if (line.includes(`"${businessField}"`) || line.includes(`'${businessField}'`)) {
481
+ tableBusinessFields.add(businessField);
482
+ }
483
+ }
484
+ if (bracketDepth === 0 && line.includes(");")) {
485
+ inTable = false;
486
+ const tableEndLine = result.length;
487
+ for (let j = tableStartLine; j <= tableEndLine; j += 1) {
488
+ const tableLine = result[j] || "";
489
+ let shouldRemove = false;
490
+ for (const [systemField, businessField] of Object.entries(systemFieldMap)) {
491
+ if (tableBusinessFields.has(businessField)) {
492
+ if (tableLine.includes(`"${systemField}"`) || tableLine.includes(`'${systemField}'`)) {
493
+ shouldRemove = true;
494
+ if (j > 0 && result[j - 1]?.includes("// System field:")) {
495
+ result[j - 1] = null;
496
+ }
497
+ break;
498
+ }
499
+ }
500
+ }
501
+ if (shouldRemove) {
502
+ result[j] = null;
503
+ }
504
+ }
505
+ }
506
+ }
507
+ result.push(line);
508
+ }
509
+ return result.filter((line) => line !== null).join("\n");
510
+ }
511
+ function addSystemFieldComments(source) {
512
+ const commentMap = {
513
+ _created_at: "Creation time",
514
+ _created_by: "Creator",
515
+ _updated_at: "Update time",
516
+ _updated_by: "Updater"
517
+ };
518
+ const lines = source.split("\n");
519
+ for (let i = 0; i < lines.length; i += 1) {
520
+ const line = lines[i];
521
+ const entry = Object.entries(commentMap).find(([key]) => line.includes(`"${key}"`));
522
+ if (!entry) {
523
+ continue;
524
+ }
525
+ const [, description] = entry;
526
+ const previousLine = lines[i - 1]?.trim() ?? "";
527
+ if (previousLine.startsWith("//") && previousLine.includes("System field")) {
528
+ continue;
529
+ }
530
+ const indentMatch = line.match(/^\s*/);
531
+ const indent = indentMatch ? indentMatch[0] : "";
532
+ const comment = `${indent}// System field: ${description} (auto-filled, do not modify)`;
533
+ lines.splice(i, 0, comment);
534
+ i += 1;
535
+ }
536
+ return lines.join("\n");
537
+ }
538
+ function replaceTimestampWithCustomTypes(source) {
539
+ let replaced = 0;
540
+ const pattern = /timestamp\((['"])(.*?)\1,\s*(\{[^}]*\})\)/g;
541
+ const text = source.replace(pattern, (match, quote, fieldName, options) => {
542
+ const hasWithTimezone = /withTimezone:\s*true/.test(options);
543
+ const hasModeString = /mode:\s*['"]string['"]/.test(options);
544
+ if (hasWithTimezone && hasModeString) {
545
+ replaced += 1;
546
+ return `customTimestamptz(${quote}${fieldName}${quote})`;
547
+ }
548
+ return match;
549
+ });
550
+ return { text, replaced };
551
+ }
552
+ function replaceDefaultNowWithSql(source) {
553
+ let replaced = 0;
554
+ const pattern = /\.defaultNow\(\)/g;
555
+ const text = source.replace(pattern, () => {
556
+ replaced += 1;
557
+ return ".default(sql`CURRENT_TIMESTAMP`)";
558
+ });
559
+ return { text, replaced };
560
+ }
561
+ function appendTableAliases(source) {
562
+ const marker = "// table aliases";
563
+ const markerIndex = source.indexOf(`
564
+ ${marker}`);
565
+ const base = markerIndex === -1 ? source : source.slice(0, markerIndex);
566
+ const exportRegex = /export const\s+([A-Za-z_$][\w$]*)\s*=\s*pgTable\s*\(/g;
567
+ const tableExports = /* @__PURE__ */ new Set();
568
+ for (const match of base.matchAll(exportRegex)) {
569
+ tableExports.add(match[1]);
570
+ }
571
+ if (tableExports.size === 0) {
572
+ return base;
573
+ }
574
+ const aliasLines = Array.from(tableExports).sort().map((name) => `export const ${name}Table = ${name};`).join("\n");
575
+ const prefix = base.trimEnd();
576
+ return `${prefix}
577
+
578
+ ${marker}
579
+ ${aliasLines}
580
+ `;
581
+ }
582
+ function postprocessDrizzleSchema(targetPath) {
583
+ const resolvedPath = path.resolve(targetPath);
584
+ if (!fs.existsSync(resolvedPath)) {
585
+ console.warn(`[postprocess-drizzle-schema] File not found: ${resolvedPath}`);
586
+ return void 0;
587
+ }
588
+ let text = fs.readFileSync(resolvedPath, "utf8");
589
+ text = ensureHeaderComment(text);
590
+ const patchResult = patchDrizzleKitDefects(text);
591
+ text = patchResult.text;
592
+ text = removePgSchemaDeclarations(text);
593
+ const tableConversion = convertSchemaTableInvocations(text);
594
+ text = tableConversion.text;
595
+ const renameResult = renamePgTableConstants(text);
596
+ text = renameResult.text;
597
+ text = updateTableReferenceIdentifiers(text, renameResult.renames);
598
+ const replacement = replaceUnknownColumns(text);
599
+ text = replacement.text;
600
+ const timestampReplacement = replaceTimestampWithCustomTypes(text);
601
+ text = timestampReplacement.text;
602
+ const defaultNowReplacement = replaceDefaultNowWithSql(text);
603
+ text = defaultNowReplacement.text;
604
+ text = removeConflictingSystemFields(text);
605
+ text = addSystemFieldComments(text);
606
+ text = tweakImports(text);
607
+ text = inlineCustomTypes(text);
608
+ text = appendTableAliases(text);
609
+ text = text.replace(/\r?\n/g, "\n");
610
+ text = collapseExtraBlankLines(text);
611
+ fs.writeFileSync(resolvedPath, text, "utf8");
612
+ if (patchResult.fixed > 0) {
613
+ console.info(`[postprocess-drizzle-schema] Patched ${patchResult.fixed} drizzle-kit defects (.default(') -> .default(''))`);
614
+ }
615
+ if (replacement.replaced > 0) {
616
+ console.info(`[postprocess-drizzle-schema] Replaced ${replacement.replaced} unknown columns`);
617
+ }
618
+ if (replacement.unmatched.length > 0) {
619
+ console.warn("[postprocess-drizzle-schema] Unmatched custom types:", replacement.unmatched.length);
620
+ replacement.unmatched.forEach((line) => console.warn(` ${line}`));
621
+ }
622
+ if (tableConversion.converted > 0) {
623
+ console.info(`[postprocess-drizzle-schema] Converted ${tableConversion.converted} schema.table invocations to pgTable`);
624
+ }
625
+ if (timestampReplacement.replaced > 0) {
626
+ console.info(`[postprocess-drizzle-schema] Replaced ${timestampReplacement.replaced} timestamp fields with customTimestamptz`);
627
+ }
628
+ if (defaultNowReplacement.replaced > 0) {
629
+ console.info(`[postprocess-drizzle-schema] Replaced ${defaultNowReplacement.replaced} .defaultNow() with .default(sql\`CURRENT_TIMESTAMP\`)`);
630
+ }
631
+ return {
632
+ replacedUnknown: replacement.replaced,
633
+ unmatchedUnknown: replacement.unmatched,
634
+ patchedDefects: patchResult.fixed,
635
+ replacedTimestamps: timestampReplacement.replaced,
636
+ replacedDefaultNow: defaultNowReplacement.replaced
637
+ };
638
+ }
639
+
640
+ // src/internal/gen-nest-resource.ts
641
+ import { mkdir, rm, writeFile } from "fs/promises";
642
+ import { existsSync } from "fs";
643
+ import { join } from "path";
644
+ import { pluralize } from "inflection";
645
+ import { Project, Node } from "ts-morph";
646
+ var DrizzleSchemaParser = class {
647
+ constructor(projectOptions) {
648
+ this.project = new Project(projectOptions);
649
+ }
650
+ parseSchemaFile(filePath) {
651
+ const sourceFile = this.project.addSourceFileAtPath(filePath);
652
+ const tables = [];
653
+ const variableStatements = sourceFile.getVariableStatements();
654
+ for (const statement of variableStatements) {
655
+ const declarations = statement.getDeclarations();
656
+ for (const declaration of declarations) {
657
+ const initializer = declaration.getInitializer();
658
+ if (!initializer || !Node.isCallExpression(initializer)) {
659
+ continue;
660
+ }
661
+ const expression = initializer.getExpression();
662
+ if (expression.getText() !== "pgTable") {
663
+ continue;
664
+ }
665
+ const tableInfo = this.parsePgTable(declaration.getName(), initializer);
666
+ if (tableInfo) {
667
+ tables.push(tableInfo);
668
+ }
669
+ }
670
+ }
671
+ return tables;
672
+ }
673
+ parsePgTable(variableName, callExpr) {
674
+ const args = callExpr.getArguments();
675
+ if (args.length < 2) {
676
+ return null;
677
+ }
678
+ const tableName = args[0].getText().replace(/['"]/g, "");
679
+ const fieldsArg = args[1];
680
+ if (!Node.isObjectLiteralExpression(fieldsArg)) {
681
+ return null;
682
+ }
683
+ const fields = [];
684
+ const properties = fieldsArg.getProperties();
685
+ for (const prop of properties) {
686
+ if (!Node.isPropertyAssignment(prop)) {
687
+ continue;
688
+ }
689
+ const fieldName = prop.getName();
690
+ const initializer = prop.getInitializer();
691
+ const leadingComments = prop.getLeadingCommentRanges();
692
+ let comment;
693
+ if (leadingComments.length > 0) {
694
+ comment = leadingComments.map((c) => c.getText()).join("\n").replace(/\/\//g, "").trim();
695
+ }
696
+ if (initializer && Node.isCallExpression(initializer)) {
697
+ const fieldInfo = this.parseField(fieldName, initializer, comment);
698
+ fields.push(fieldInfo);
699
+ }
700
+ }
701
+ return { tableName, variableName, fields };
702
+ }
703
+ parseField(fieldName, callExpr, comment) {
704
+ const fieldInfo = {
705
+ name: fieldName,
706
+ columnName: fieldName,
707
+ type: "",
708
+ nullable: true,
709
+ hasDefault: false,
710
+ notNull: false,
711
+ isPrimaryKey: false,
712
+ isUnique: false,
713
+ isArray: false,
714
+ comment
715
+ };
716
+ this.parseBaseType(callExpr, fieldInfo);
717
+ this.parseCallChain(callExpr, fieldInfo);
718
+ return fieldInfo;
719
+ }
720
+ parseBaseType(callExpr, fieldInfo) {
721
+ let current = callExpr;
722
+ let baseCall = null;
723
+ while (Node.isCallExpression(current)) {
724
+ baseCall = current;
725
+ const expression2 = current.getExpression();
726
+ if (Node.isPropertyAccessExpression(expression2)) {
727
+ current = expression2.getExpression();
728
+ } else {
729
+ break;
730
+ }
731
+ }
732
+ if (!baseCall) {
733
+ return;
734
+ }
735
+ const expression = baseCall.getExpression();
736
+ let typeName = "";
737
+ if (Node.isPropertyAccessExpression(expression)) {
738
+ typeName = expression.getName();
739
+ } else {
740
+ typeName = expression.getText();
741
+ }
742
+ fieldInfo.type = typeName;
743
+ const args = baseCall.getArguments();
744
+ if (args.length > 0) {
745
+ const firstArg = args[0];
746
+ if (Node.isStringLiteral(firstArg)) {
747
+ fieldInfo.columnName = firstArg.getLiteralText();
748
+ } else if (Node.isObjectLiteralExpression(firstArg)) {
749
+ this.parseTypeConfig(firstArg, fieldInfo);
750
+ } else if (Node.isArrayLiteralExpression(firstArg)) {
751
+ fieldInfo.enumValues = firstArg.getElements().map((el) => el.getText().replace(/['"]/g, ""));
752
+ }
753
+ }
754
+ if (args.length > 1 && Node.isObjectLiteralExpression(args[1])) {
755
+ this.parseTypeConfig(args[1], fieldInfo);
756
+ }
757
+ }
758
+ parseTypeConfig(objLiteral, fieldInfo) {
759
+ if (!Node.isObjectLiteralExpression(objLiteral)) {
760
+ return;
761
+ }
762
+ const properties = objLiteral.getProperties();
763
+ for (const prop of properties) {
764
+ if (!Node.isPropertyAssignment(prop)) {
765
+ continue;
766
+ }
767
+ const propName = prop.getName();
768
+ const value = prop.getInitializer()?.getText();
769
+ switch (propName) {
770
+ case "length":
771
+ fieldInfo.length = value ? parseInt(value) : void 0;
772
+ break;
773
+ case "precision":
774
+ fieldInfo.precision = value ? parseInt(value) : void 0;
775
+ break;
776
+ case "scale":
777
+ fieldInfo.scale = value ? parseInt(value) : void 0;
778
+ break;
779
+ case "default":
780
+ fieldInfo.hasDefault = true;
781
+ fieldInfo.defaultValue = value;
782
+ break;
783
+ case "withTimezone":
784
+ fieldInfo.withTimezone = value === "true";
785
+ break;
786
+ case "mode":
787
+ fieldInfo.mode = value?.replace(/['"]/g, "");
788
+ break;
789
+ default:
790
+ throw new Error(`Unsupported property: ${propName}`);
791
+ }
792
+ }
793
+ }
794
+ parseCallChain(callExpr, fieldInfo) {
795
+ let current = callExpr;
796
+ while (Node.isCallExpression(current)) {
797
+ const expression = current.getExpression();
798
+ if (!Node.isPropertyAccessExpression(expression)) {
799
+ break;
800
+ }
801
+ const methodName = expression.getName();
802
+ const args = current.getArguments();
803
+ switch (methodName) {
804
+ case "notNull":
805
+ fieldInfo.notNull = true;
806
+ fieldInfo.nullable = false;
807
+ break;
808
+ case "default":
809
+ fieldInfo.hasDefault = true;
810
+ if (args.length > 0) {
811
+ fieldInfo.defaultValue = args[0].getText();
812
+ }
813
+ break;
814
+ case "defaultRandom":
815
+ fieldInfo.hasDefault = true;
816
+ fieldInfo.defaultValue = "random";
817
+ break;
818
+ case "primaryKey":
819
+ fieldInfo.isPrimaryKey = true;
820
+ fieldInfo.notNull = true;
821
+ fieldInfo.nullable = false;
822
+ break;
823
+ case "unique":
824
+ fieldInfo.isUnique = true;
825
+ break;
826
+ case "array":
827
+ fieldInfo.isArray = true;
828
+ break;
829
+ case "references":
830
+ if (args.length > 0) {
831
+ const refArg = args[0].getText();
832
+ const match = refArg.match(/=>\s*(\w+)\.(\w+)/);
833
+ if (match) {
834
+ fieldInfo.references = { table: match[1], column: match[2] };
835
+ }
836
+ }
837
+ break;
838
+ default:
839
+ throw new Error(`Unsupported method: ${methodName}`);
840
+ }
841
+ current = expression.getExpression();
842
+ }
843
+ }
844
+ };
845
+ function mapDrizzleTypeToTS(field) {
846
+ const typeMap = {
847
+ char: "string",
848
+ varchar: "string",
849
+ text: "string",
850
+ smallint: "number",
851
+ integer: "number",
852
+ int: "number",
853
+ bigint: "string",
854
+ serial: "number",
855
+ smallserial: "number",
856
+ bigserial: "string",
857
+ decimal: "string",
858
+ numeric: "string",
859
+ real: "number",
860
+ doublePrecision: "number",
861
+ boolean: "boolean",
862
+ timestamp: "Date",
863
+ timestamptz: "Date",
864
+ date: "Date",
865
+ time: "string",
866
+ timetz: "string",
867
+ interval: "string",
868
+ uuid: "string",
869
+ json: "any",
870
+ jsonb: "any",
871
+ bytea: "Buffer",
872
+ inet: "string",
873
+ cidr: "string",
874
+ macaddr: "string",
875
+ macaddr8: "string",
876
+ point: "{ x: number; y: number }",
877
+ line: "string",
878
+ lseg: "string",
879
+ box: "string",
880
+ path: "string",
881
+ polygon: "string",
882
+ circle: "string",
883
+ array: "any[]",
884
+ customType: "any",
885
+ customTimestamptz: "Date",
886
+ userProfile: "string",
887
+ fileAttachment: "FileAttachment",
888
+ pgEnum: "string"
889
+ };
890
+ let baseType = typeMap[field.type] || "any";
891
+ if (field.isArray) {
892
+ baseType = baseType.endsWith("[]") ? baseType : `${baseType}[]`;
893
+ }
894
+ if (field.enumValues && field.enumValues.length > 0) {
895
+ baseType = field.enumValues.map((v) => `'${v}'`).join(" | ");
896
+ }
897
+ return baseType;
898
+ }
899
+ function toPascalCase(str) {
900
+ return str.replace(/([a-z])([A-Z])/g, "$1 $2").split(/[-_\s]/).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
901
+ }
902
+ function toKebabCase(str) {
903
+ return str.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase().replace(/[_\s]/g, "-");
904
+ }
905
+ function toSnakeCase(str) {
906
+ return str.replace(/([a-z])([A-Z])/g, "$1_$2").toLowerCase().replace(/[-\s]/g, "_");
907
+ }
908
+ function generateValidationDecorators(field, opts = {}) {
909
+ const { isUpdate = false, isResponse = false } = opts;
910
+ let decorators = " // \u8BF7\u6309\u7528\u6237\u9700\u6C42\u4FEE\u6539\u4EE5\u4E0B\u88C5\u9970\u5668\u6CE8\u91CA\n";
911
+ if (field.nullable || !isResponse && field.hasDefault || isUpdate) {
912
+ decorators += ` @ApiPropertyOptional({ description: '${field.comment || field.name}' })
913
+ `;
914
+ if (isResponse) {
915
+ return decorators;
916
+ }
917
+ decorators += " @IsOptional()\n";
918
+ } else {
919
+ decorators += ` @ApiProperty({ description: '${field.comment || field.name}' })
920
+ `;
921
+ if (isResponse) {
922
+ return decorators;
923
+ }
924
+ decorators += " @IsDefined()\n";
925
+ }
926
+ switch (field.type) {
927
+ case "varchar":
928
+ case "char":
929
+ case "text":
930
+ decorators += " @IsString()\n";
931
+ if (field.length) {
932
+ decorators += ` @MaxLength(${field.length})
933
+ `;
934
+ }
935
+ break;
936
+ case "integer":
937
+ case "smallint":
938
+ case "serial":
939
+ case "smallserial":
940
+ decorators += " @IsInt()\n";
941
+ break;
942
+ case "decimal":
943
+ case "numeric":
944
+ case "real":
945
+ case "doublePrecision":
946
+ decorators += " @IsNumber()\n";
947
+ break;
948
+ case "boolean":
949
+ decorators += " @IsBoolean()\n";
950
+ break;
951
+ case "uuid":
952
+ decorators += " @IsUUID()\n";
953
+ break;
954
+ case "timestamp":
955
+ case "timestamptz":
956
+ case "date":
957
+ case "customTimestamptz":
958
+ decorators += " @IsDate()\n";
959
+ break;
960
+ case "json":
961
+ case "jsonb":
962
+ decorators += " @IsObject()\n";
963
+ break;
964
+ }
965
+ if (field.isArray) {
966
+ decorators += " @IsArray()\n";
967
+ }
968
+ return decorators;
969
+ }
970
+ function generateDTO(table) {
971
+ const className = toPascalCase(table.variableName);
972
+ let dto = `// \u8BF7\u4FEE\u6539\u8BE5\u6587\u4EF6\u4EE3\u7801\u4EE5\u6EE1\u8DB3\u9700\u6C42
973
+ import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
974
+ import { IsDefined, IsNumber, IsOptional, IsString, MaxLength, IsInt, IsBoolean, IsUUID, IsDate, IsObject, IsArray } from 'class-validator';
975
+ import { Type } from 'class-transformer';
976
+ import { FileAttachment } from '../../../database/schema';
977
+
978
+ `;
979
+ dto += `export class Create${className}Dto {
980
+ `;
981
+ for (const field of table.fields) {
982
+ if (field.isPrimaryKey || field.name === "id" || field.name.startsWith("_") || field.name.startsWith("created") || field.name.startsWith("updated")) {
983
+ continue;
984
+ }
985
+ const tsType = mapDrizzleTypeToTS(field);
986
+ const optional = field.nullable || field.hasDefault ? "?" : "";
987
+ const decorators = generateValidationDecorators(field);
988
+ if (decorators) {
989
+ dto += decorators;
990
+ }
991
+ dto += ` ${field.name}${optional}: ${tsType};
992
+
993
+ `;
994
+ }
995
+ dto += "}\n\n";
996
+ dto += `export class Update${className}Dto {
997
+ `;
998
+ for (const field of table.fields) {
999
+ if (field.name.startsWith("_") || field.name.startsWith("created") || field.name.startsWith("updated") || field.isPrimaryKey || field.name === "id") {
1000
+ continue;
1001
+ }
1002
+ const tsType = mapDrizzleTypeToTS(field);
1003
+ const decorators = generateValidationDecorators(field, { isUpdate: true });
1004
+ if (decorators) {
1005
+ dto += decorators;
1006
+ }
1007
+ dto += ` ${field.name}?: ${tsType};
1008
+
1009
+ `;
1010
+ }
1011
+ dto += "}\n\n";
1012
+ dto += `export class ${className}ResponseDto {
1013
+ `;
1014
+ for (const field of table.fields) {
1015
+ const tsType = mapDrizzleTypeToTS(field);
1016
+ const optional = field.nullable ? "?" : "";
1017
+ const decorators = generateValidationDecorators(field, { isResponse: true });
1018
+ if (decorators) {
1019
+ dto += decorators;
1020
+ }
1021
+ dto += ` ${field.name}${optional}: ${tsType};
1022
+
1023
+ `;
1024
+ }
1025
+ dto += "}\n";
1026
+ return dto;
1027
+ }
1028
+ function generateController(table) {
1029
+ const className = toPascalCase(table.variableName);
1030
+ const routePath = toKebabCase(pluralize(table.variableName));
1031
+ const filePath = toSnakeCase(table.variableName);
1032
+ const pkField = table.fields.find((f) => f.isPrimaryKey);
1033
+ const pkType = pkField ? mapDrizzleTypeToTS(pkField) : "string";
1034
+ const pkName = pkField ? pkField.name : "id";
1035
+ return `
1036
+ // \u8BF7\u4FEE\u6539\u8BE5\u6587\u4EF6\u4EE3\u7801\u4EE5\u6EE1\u8DB3\u9700\u6C42
1037
+ import {
1038
+ Controller,
1039
+ Get,
1040
+ Post,
1041
+ Put,
1042
+ Delete,
1043
+ Body,
1044
+ Param,
1045
+ Query,
1046
+ } from '@nestjs/common';
1047
+ import {
1048
+ ApiTags,
1049
+ ApiOperation,
1050
+ ApiOkResponse,
1051
+ ApiCreatedResponse,
1052
+ } from '@nestjs/swagger';
1053
+ import {
1054
+ Create${className}Dto,
1055
+ Update${className}Dto,
1056
+ ${className}ResponseDto
1057
+ } from './dtos/${filePath}.dto';
1058
+ import { ${className}Service } from './${filePath}.service';
1059
+
1060
+ @ApiTags('${toPascalCase(table.variableName)}')
1061
+ @Controller('api/${routePath}')
1062
+ export class ${className}Controller {
1063
+ constructor(private readonly ${table.variableName}Service: ${className}Service) {}
1064
+
1065
+ @Post()
1066
+ @ApiOperation({
1067
+ summary: '\u521B\u5EFA\u4E00\u6761\u8BB0\u5F55\uFF08\u6A21\u677F\u5185\u5BB9\uFF0C\u8BF7\u4FEE\u6539\u6211\uFF09',
1068
+ description: '\u521B\u5EFA\u4E00\u6761\u8BB0\u5F55\uFF08\u6A21\u677F\u5185\u5BB9\uFF0C\u8BF7\u4FEE\u6539\u6211\uFF09',
1069
+ })
1070
+ @ApiCreatedResponse({
1071
+ description: '\u6210\u529F\u521B\u5EFA\u4E00\u6761\u8BB0\u5F55',
1072
+ type: ${className}ResponseDto,
1073
+ })
1074
+ async create(
1075
+ @Body() createDto: Create${className}Dto
1076
+ ): Promise<${className}ResponseDto> {
1077
+ return this.${table.variableName}Service.create(createDto);
1078
+ }
1079
+
1080
+ @ApiOperation({
1081
+ summary: '\u6839\u636E\u4E3B\u952E\u67E5\u8BE2\u4E00\u6761\u8BB0\u5F55\uFF08\u6A21\u677F\u5185\u5BB9\uFF0C\u8BF7\u4FEE\u6539\u6211\uFF09',
1082
+ description: '\u6839\u636E\u4E3B\u952E\u67E5\u8BE2\u4E00\u6761\u8BB0\u5F55\uFF08\u6A21\u677F\u5185\u5BB9\uFF0C\u8BF7\u4FEE\u6539\u6211\uFF09',
1083
+ })
1084
+ @ApiOkResponse({
1085
+ description: '\u6210\u529F\u67E5\u8BE2\u4E00\u6761\u8BB0\u5F55',
1086
+ type: ${className}ResponseDto,
1087
+ })
1088
+ @Get(':${pkName}')
1089
+ async findOne(
1090
+ @Param('${pkName}') ${pkName}: ${pkType}
1091
+ ): Promise<${className}ResponseDto> {
1092
+ return this.${table.variableName}Service.findOne(${pkName});
1093
+ }
1094
+
1095
+ @ApiOperation({
1096
+ summary: '\u6839\u636E\u4E3B\u952E\u66F4\u65B0\u4E00\u6761\u8BB0\u5F55\uFF08\u6A21\u677F\u5185\u5BB9\uFF0C\u8BF7\u4FEE\u6539\u6211\uFF09',
1097
+ description: '\u6839\u636E\u4E3B\u952E\u66F4\u65B0\u4E00\u6761\u8BB0\u5F55\uFF08\u6A21\u677F\u5185\u5BB9\uFF0C\u8BF7\u4FEE\u6539\u6211\uFF09',
1098
+ })
1099
+ @ApiOkResponse({
1100
+ description: '\u6210\u529F\u66F4\u65B0\u4E00\u6761\u8BB0\u5F55',
1101
+ type: ${className}ResponseDto,
1102
+ })
1103
+ @Put(':${pkName}')
1104
+ async update(
1105
+ @Param('${pkName}') ${pkName}: ${pkType},
1106
+ @Body() updateDto: Update${className}Dto
1107
+ ): Promise<${className}ResponseDto> {
1108
+ return this.${table.variableName}Service.update(${pkName}, updateDto);
1109
+ }
1110
+
1111
+ @ApiOperation({
1112
+ summary: '\u6839\u636E\u4E3B\u952E\u5220\u9664\u4E00\u6761\u8BB0\u5F55\uFF08\u6A21\u677F\u5185\u5BB9\uFF0C\u8BF7\u4FEE\u6539\u6211\uFF09',
1113
+ description: '\u6839\u636E\u4E3B\u952E\u5220\u9664\u4E00\u6761\u8BB0\u5F55\uFF08\u6A21\u677F\u5185\u5BB9\uFF0C\u8BF7\u4FEE\u6539\u6211\uFF09',
1114
+ })
1115
+ @ApiOkResponse({
1116
+ description: '\u6210\u529F\u5220\u9664\u4E00\u6761\u8BB0\u5F55',
1117
+ })
1118
+ @Delete(':${pkName}')
1119
+ async remove(
1120
+ @Param('${pkName}') ${pkName}: ${pkType}
1121
+ ): Promise<void> {
1122
+ return this.${table.variableName}Service.remove(${pkName});
1123
+ }
1124
+ }
1125
+ `;
1126
+ }
1127
+ function generateService(table) {
1128
+ const className = toPascalCase(table.variableName);
1129
+ const filePath = toSnakeCase(table.variableName);
1130
+ const pkField = table.fields.find((f) => f.isPrimaryKey);
1131
+ const pkType = pkField ? mapDrizzleTypeToTS(pkField) : "string";
1132
+ const pkName = pkField ? pkField.name : "id";
1133
+ return `
1134
+ // \u8BF7\u4FEE\u6539\u8BE5\u6587\u4EF6\u4EE3\u7801\u4EE5\u6EE1\u8DB3\u9700\u6C42
1135
+ import { Injectable, Inject, Logger, NotFoundException } from '@nestjs/common';
1136
+ import { eq } from 'drizzle-orm';
1137
+ import { DRIZZLE_DATABASE, type PostgresJsDatabase } from '@lark-apaas/fullstack-nestjs-core';
1138
+ import { ${table.variableName} } from '../../database/schema';
1139
+ import {
1140
+ Create${className}Dto,
1141
+ Update${className}Dto,
1142
+ ${className}ResponseDto
1143
+ } from './dtos/${filePath}.dto';
1144
+
1145
+ @Injectable()
1146
+ export class ${className}Service {
1147
+ private readonly logger = new Logger(${className}Service.name);
1148
+
1149
+ constructor(@Inject(DRIZZLE_DATABASE) private readonly db: PostgresJsDatabase) {}
1150
+
1151
+ async create(createDto: Create${className}Dto): Promise<${className}ResponseDto> {
1152
+ const [result] = await this.db
1153
+ .insert(${table.variableName})
1154
+ .values(createDto)
1155
+ .returning();
1156
+
1157
+ this.logger.log(\`Created ${className} with ${pkName} \${result.${pkName}}\`);
1158
+
1159
+ return result;
1160
+ }
1161
+
1162
+ async findAll(options?: { page?: number; limit?: number }): Promise<${className}ResponseDto[]> {
1163
+ const { page = 1, limit = 10 } = options || {};
1164
+ const offset = (page - 1) * limit;
1165
+
1166
+ return this.db
1167
+ .select()
1168
+ .from(${table.variableName})
1169
+ .limit(limit)
1170
+ .offset(offset);
1171
+ }
1172
+
1173
+ async findOne(${pkName}: ${pkType}): Promise<${className}ResponseDto> {
1174
+ const [result] = await this.db
1175
+ .select()
1176
+ .from(${table.variableName})
1177
+ .where(eq(${table.variableName}.${pkName}, ${pkName}))
1178
+ .limit(1);
1179
+
1180
+ if (!result) {
1181
+ throw new NotFoundException(\`${className} with ${pkName} \${${pkName}} not found\`);
1182
+ }
1183
+
1184
+ return result;
1185
+ }
1186
+
1187
+ async update(${pkName}: ${pkType}, updateDto: Update${className}Dto): Promise<${className}ResponseDto> {
1188
+ const [result] = await this.db
1189
+ .update(${table.variableName})
1190
+ .set(updateDto)
1191
+ .where(eq(${table.variableName}.${pkName}, ${pkName}))
1192
+ .returning();
1193
+
1194
+ if (!result) {
1195
+ throw new NotFoundException(\`${className} with ${pkName} \${${pkName}} not found\`);
1196
+ }
1197
+
1198
+ return result;
1199
+ }
1200
+
1201
+ async remove(${pkName}: ${pkType}): Promise<void> {
1202
+ const result = await this.db
1203
+ .delete(${table.variableName})
1204
+ .where(eq(${table.variableName}.${pkName}, ${pkName}))
1205
+ .returning();
1206
+
1207
+ if (result.length === 0) {
1208
+ throw new NotFoundException(\`${className} with ${pkName} \${${pkName}} not found\`);
1209
+ }
1210
+
1211
+ this.logger.log(\`Deleted ${className} with ${pkName} \${${pkName}}\`);
1212
+ }
1213
+ }
1214
+ `;
1215
+ }
1216
+ function generateModule(table) {
1217
+ const className = toPascalCase(table.variableName);
1218
+ const filePath = toSnakeCase(table.variableName);
1219
+ return `
1220
+ import { Module } from '@nestjs/common';
1221
+ import { ${className}Controller } from './${filePath}.controller';
1222
+ import { ${className}Service } from './${filePath}.service';
1223
+
1224
+ @Module({
1225
+ controllers: [${className}Controller],
1226
+ providers: [${className}Service],
1227
+ })
1228
+ export class ${className}Module {}
1229
+ `;
1230
+ }
1231
+ async function parseAndGenerateNestResourceTemplate(options) {
1232
+ const parser = new DrizzleSchemaParser({ tsConfigFilePath: options.tsConfigFilePath });
1233
+ const tables = parser.parseSchemaFile(options.schemaFilePath);
1234
+ if (tables.length === 0) {
1235
+ console.warn("\u672A\u89E3\u6790\u5230\u4EFB\u4F55\u6570\u636E\u5E93\u8868\uFF0C\u65E0\u9700\u751F\u6210 Nest.js \u6A21\u5757\u6A21\u677F");
1236
+ return;
1237
+ }
1238
+ tables.sort((a, b) => b.variableName.length - a.variableName.length);
1239
+ const table = tables[0];
1240
+ console.info(`\u751F\u6210 Nest.js ${table.variableName} \u6A21\u5757`);
1241
+ const filePath = toSnakeCase(table.variableName);
1242
+ const moduleDir = join(options.moduleOutputDir, filePath);
1243
+ if (existsSync(moduleDir)) {
1244
+ console.info(`Nest.js \u6A21\u5757 ${filePath} \u5DF2\u5B58\u5728\uFF0C\u8DF3\u8FC7\u751F\u6210\u4EE3\u7801`);
1245
+ return;
1246
+ }
1247
+ const dto = generateDTO(table);
1248
+ const controller = generateController(table);
1249
+ const service = generateService(table);
1250
+ const moduleContent = generateModule(table);
1251
+ const moduleFilePath = join(moduleDir, `${filePath}.module.ts`);
1252
+ try {
1253
+ await mkdir(moduleDir, { recursive: true });
1254
+ await mkdir(join(moduleDir, "dtos"), { recursive: true });
1255
+ await writeFile(join(moduleDir, "dtos", `${filePath}.dto.ts`), dto);
1256
+ await writeFile(join(moduleDir, `${filePath}.controller.ts`), controller);
1257
+ await writeFile(join(moduleDir, `${filePath}.service.ts`), service);
1258
+ await writeFile(moduleFilePath, moduleContent);
1259
+ } catch (err) {
1260
+ console.error(`\u751F\u6210 Nest.js ${filePath} \u6A21\u5757\u5931\u8D25: ${err.message}`);
1261
+ await rm(moduleDir, { recursive: true });
1262
+ }
1263
+ }
1264
+
1265
+ // src/commands/db/schema.handler.ts
126
1266
  async function run(options = {}) {
127
1267
  let exitCode = 0;
128
- const envPath2 = path.resolve(process.cwd(), ".env");
129
- if (fs.existsSync(envPath2)) {
1268
+ const envPath2 = path2.resolve(process.cwd(), ".env");
1269
+ if (fs2.existsSync(envPath2)) {
130
1270
  loadEnv({ path: envPath2 });
131
1271
  console.log("[gen-db-schema] \u2713 Loaded .env file");
132
1272
  }
@@ -136,13 +1276,13 @@ async function run(options = {}) {
136
1276
  process.exit(1);
137
1277
  }
138
1278
  const outputPath = options.output || process.env.DB_SCHEMA_OUTPUT || "server/database/schema.ts";
139
- const OUT_DIR = path.resolve(process.cwd(), "server/database/.introspect");
140
- const SCHEMA_FILE = path.resolve(process.cwd(), outputPath);
1279
+ const OUT_DIR = path2.resolve(process.cwd(), "server/database/.introspect");
1280
+ const SCHEMA_FILE = path2.resolve(process.cwd(), outputPath);
141
1281
  console.log("[gen-db-schema] Starting...");
142
1282
  const __filename = fileURLToPath(import.meta.url);
143
- const __dirname2 = path.dirname(__filename);
144
- const configPath = path.join(__dirname2, "config", "drizzle.config.js");
145
- if (!fs.existsSync(configPath)) {
1283
+ const __dirname2 = path2.dirname(__filename);
1284
+ const configPath = path2.join(__dirname2, "config", "drizzle.config.js");
1285
+ if (!fs2.existsSync(configPath)) {
146
1286
  console.error("[gen-db-schema] Error: drizzle config not found in CLI package");
147
1287
  process.exit(1);
148
1288
  }
@@ -162,29 +1302,27 @@ async function run(options = {}) {
162
1302
  if ((result.status ?? 0) !== 0) {
163
1303
  throw new Error(`drizzle-kit introspect failed with status ${result.status}`);
164
1304
  }
165
- const generatedSchema = path.join(OUT_DIR, "schema.ts");
166
- if (!fs.existsSync(generatedSchema)) {
1305
+ const generatedSchema = path2.join(OUT_DIR, "schema.ts");
1306
+ if (!fs2.existsSync(generatedSchema)) {
167
1307
  console.error("[gen-db-schema] schema.ts not generated");
168
1308
  throw new Error("drizzle-kit introspect failed to generate schema.ts");
169
1309
  }
170
- const { postprocessDrizzleSchema } = require2("@lark-apaas/devtool-kits");
171
1310
  const stats = postprocessDrizzleSchema(generatedSchema);
172
1311
  if (stats?.unmatchedUnknown?.length) {
173
1312
  console.warn("[gen-db-schema] Unmatched custom types detected:", stats.unmatchedUnknown);
174
1313
  }
175
1314
  console.log("[gen-db-schema] \u2713 Postprocessed schema");
176
- fs.mkdirSync(path.dirname(SCHEMA_FILE), { recursive: true });
177
- fs.copyFileSync(generatedSchema, SCHEMA_FILE);
1315
+ fs2.mkdirSync(path2.dirname(SCHEMA_FILE), { recursive: true });
1316
+ fs2.copyFileSync(generatedSchema, SCHEMA_FILE);
178
1317
  console.log(`[gen-db-schema] \u2713 Copied to ${outputPath}`);
179
1318
  try {
180
1319
  if (options.enableNestModuleGenerate) {
181
- const { parseAndGenerateNestResourceTemplate } = require2("@lark-apaas/devtool-kits");
182
- const tsConfigFilePath = path.resolve(process.cwd(), "tsconfig.json");
1320
+ const tsConfigFilePath = path2.resolve(process.cwd(), "tsconfig.json");
183
1321
  const schemaFilePath = SCHEMA_FILE;
184
1322
  await parseAndGenerateNestResourceTemplate({
185
1323
  tsConfigFilePath,
186
1324
  schemaFilePath,
187
- moduleOutputDir: path.resolve(process.cwd(), "server/modules")
1325
+ moduleOutputDir: path2.resolve(process.cwd(), "server/modules")
188
1326
  });
189
1327
  console.log("[gen-db-schema] \u2713 Generate NestJS Module Boilerplate Successfully");
190
1328
  }
@@ -196,8 +1334,8 @@ async function run(options = {}) {
196
1334
  console.error("[gen-db-schema] Failed:", err instanceof Error ? err.message : String(err));
197
1335
  exitCode = 1;
198
1336
  } finally {
199
- if (fs.existsSync(OUT_DIR)) {
200
- fs.rmSync(OUT_DIR, { recursive: true, force: true });
1337
+ if (fs2.existsSync(OUT_DIR)) {
1338
+ fs2.rmSync(OUT_DIR, { recursive: true, force: true });
201
1339
  }
202
1340
  process.exit(exitCode);
203
1341
  }
@@ -215,8 +1353,8 @@ var genDbSchemaCommand = {
215
1353
  };
216
1354
 
217
1355
  // src/commands/sync/run.handler.ts
218
- import path3 from "path";
219
- import fs3 from "fs";
1356
+ import path4 from "path";
1357
+ import fs4 from "fs";
220
1358
  import { fileURLToPath as fileURLToPath2 } from "url";
221
1359
 
222
1360
  // src/config/sync.ts
@@ -280,23 +1418,23 @@ function genSyncConfig(perms = {}) {
280
1418
  }
281
1419
 
282
1420
  // src/utils/file-ops.ts
283
- import fs2 from "fs";
284
- import path2 from "path";
1421
+ import fs3 from "fs";
1422
+ import path3 from "path";
285
1423
  function removeLineFromFile(filePath, pattern) {
286
- if (!fs2.existsSync(filePath)) {
287
- console.log(`[fullstack-cli] \u25CB ${path2.basename(filePath)} (not found)`);
1424
+ if (!fs3.existsSync(filePath)) {
1425
+ console.log(`[fullstack-cli] \u25CB ${path3.basename(filePath)} (not found)`);
288
1426
  return false;
289
1427
  }
290
- const content = fs2.readFileSync(filePath, "utf-8");
1428
+ const content = fs3.readFileSync(filePath, "utf-8");
291
1429
  const lines = content.split("\n");
292
1430
  const trimmedPattern = pattern.trim();
293
1431
  const filteredLines = lines.filter((line) => line.trim() !== trimmedPattern);
294
1432
  if (filteredLines.length === lines.length) {
295
- console.log(`[fullstack-cli] \u25CB ${path2.basename(filePath)} (pattern not found: ${pattern})`);
1433
+ console.log(`[fullstack-cli] \u25CB ${path3.basename(filePath)} (pattern not found: ${pattern})`);
296
1434
  return false;
297
1435
  }
298
- fs2.writeFileSync(filePath, filteredLines.join("\n"));
299
- console.log(`[fullstack-cli] \u2713 ${path2.basename(filePath)} (removed: ${pattern})`);
1436
+ fs3.writeFileSync(filePath, filteredLines.join("\n"));
1437
+ console.log(`[fullstack-cli] \u2713 ${path3.basename(filePath)} (removed: ${pattern})`);
300
1438
  return true;
301
1439
  }
302
1440
 
@@ -304,14 +1442,14 @@ function removeLineFromFile(filePath, pattern) {
304
1442
  async function run2(options) {
305
1443
  const userProjectRoot = process.env.INIT_CWD || process.cwd();
306
1444
  const __filename = fileURLToPath2(import.meta.url);
307
- const __dirname2 = path3.dirname(__filename);
308
- const pluginRoot = path3.resolve(__dirname2, "..");
1445
+ const __dirname2 = path4.dirname(__filename);
1446
+ const pluginRoot = path4.resolve(__dirname2, "..");
309
1447
  if (userProjectRoot === pluginRoot) {
310
1448
  console.log("[fullstack-cli] Skip syncing (installing plugin itself)");
311
1449
  process.exit(0);
312
1450
  }
313
- const userPackageJson = path3.join(userProjectRoot, "package.json");
314
- if (!fs3.existsSync(userPackageJson)) {
1451
+ const userPackageJson = path4.join(userProjectRoot, "package.json");
1452
+ if (!fs4.existsSync(userPackageJson)) {
315
1453
  console.log("[fullstack-cli] Skip syncing (not a valid npm project)");
316
1454
  process.exit(0);
317
1455
  }
@@ -339,7 +1477,7 @@ async function run2(options) {
339
1477
  }
340
1478
  async function syncRule(rule, pluginRoot, userProjectRoot) {
341
1479
  if (rule.type === "delete-file" || rule.type === "delete-directory") {
342
- const destPath2 = path3.join(userProjectRoot, rule.to);
1480
+ const destPath2 = path4.join(userProjectRoot, rule.to);
343
1481
  if (rule.type === "delete-file") {
344
1482
  deleteFile(destPath2);
345
1483
  } else {
@@ -348,16 +1486,16 @@ async function syncRule(rule, pluginRoot, userProjectRoot) {
348
1486
  return;
349
1487
  }
350
1488
  if (rule.type === "remove-line") {
351
- const destPath2 = path3.join(userProjectRoot, rule.to);
1489
+ const destPath2 = path4.join(userProjectRoot, rule.to);
352
1490
  removeLineFromFile(destPath2, rule.pattern);
353
1491
  return;
354
1492
  }
355
1493
  if (!("from" in rule)) {
356
1494
  return;
357
1495
  }
358
- const srcPath = path3.join(pluginRoot, rule.from);
359
- const destPath = path3.join(userProjectRoot, rule.to);
360
- if (!fs3.existsSync(srcPath)) {
1496
+ const srcPath = path4.join(pluginRoot, rule.from);
1497
+ const destPath = path4.join(userProjectRoot, rule.to);
1498
+ if (!fs4.existsSync(srcPath)) {
361
1499
  console.warn(`[fullstack-cli] Source not found: ${rule.from}`);
362
1500
  return;
363
1501
  }
@@ -374,64 +1512,64 @@ async function syncRule(rule, pluginRoot, userProjectRoot) {
374
1512
  }
375
1513
  }
376
1514
  function syncFile(src, dest, overwrite = true) {
377
- const destDir = path3.dirname(dest);
378
- if (!fs3.existsSync(destDir)) {
379
- fs3.mkdirSync(destDir, { recursive: true });
1515
+ const destDir = path4.dirname(dest);
1516
+ if (!fs4.existsSync(destDir)) {
1517
+ fs4.mkdirSync(destDir, { recursive: true });
380
1518
  }
381
- if (fs3.existsSync(dest) && !overwrite) {
382
- console.log(`[fullstack-cli] \u25CB ${path3.basename(dest)} (skipped, already exists)`);
1519
+ if (fs4.existsSync(dest) && !overwrite) {
1520
+ console.log(`[fullstack-cli] \u25CB ${path4.basename(dest)} (skipped, already exists)`);
383
1521
  return;
384
1522
  }
385
- fs3.copyFileSync(src, dest);
386
- console.log(`[fullstack-cli] \u2713 ${path3.basename(dest)}`);
1523
+ fs4.copyFileSync(src, dest);
1524
+ console.log(`[fullstack-cli] \u2713 ${path4.basename(dest)}`);
387
1525
  }
388
1526
  function syncDirectory(src, dest, overwrite = true) {
389
- if (!fs3.existsSync(dest)) {
390
- fs3.mkdirSync(dest, { recursive: true });
1527
+ if (!fs4.existsSync(dest)) {
1528
+ fs4.mkdirSync(dest, { recursive: true });
391
1529
  }
392
- const files = fs3.readdirSync(src);
1530
+ const files = fs4.readdirSync(src);
393
1531
  let count = 0;
394
1532
  files.forEach((file) => {
395
- const srcFile = path3.join(src, file);
396
- const destFile = path3.join(dest, file);
397
- const stats = fs3.statSync(srcFile);
1533
+ const srcFile = path4.join(src, file);
1534
+ const destFile = path4.join(dest, file);
1535
+ const stats = fs4.statSync(srcFile);
398
1536
  if (stats.isDirectory()) {
399
1537
  syncDirectory(srcFile, destFile, overwrite);
400
1538
  } else {
401
- if (overwrite || !fs3.existsSync(destFile)) {
402
- fs3.copyFileSync(srcFile, destFile);
403
- console.log(`[fullstack-cli] \u2713 ${path3.relative(dest, destFile)}`);
1539
+ if (overwrite || !fs4.existsSync(destFile)) {
1540
+ fs4.copyFileSync(srcFile, destFile);
1541
+ console.log(`[fullstack-cli] \u2713 ${path4.relative(dest, destFile)}`);
404
1542
  count++;
405
1543
  }
406
1544
  }
407
1545
  });
408
1546
  if (count > 0) {
409
- console.log(`[fullstack-cli] Synced ${count} files to ${path3.basename(dest)}/`);
1547
+ console.log(`[fullstack-cli] Synced ${count} files to ${path4.basename(dest)}/`);
410
1548
  }
411
1549
  }
412
1550
  function appendToFile(src, dest) {
413
- const content = fs3.readFileSync(src, "utf-8");
1551
+ const content = fs4.readFileSync(src, "utf-8");
414
1552
  let existingContent = "";
415
- if (fs3.existsSync(dest)) {
416
- existingContent = fs3.readFileSync(dest, "utf-8");
1553
+ if (fs4.existsSync(dest)) {
1554
+ existingContent = fs4.readFileSync(dest, "utf-8");
417
1555
  }
418
1556
  if (existingContent.includes(content.trim())) {
419
- console.log(`[fullstack-cli] \u25CB ${path3.basename(dest)} (already contains content)`);
1557
+ console.log(`[fullstack-cli] \u25CB ${path4.basename(dest)} (already contains content)`);
420
1558
  return;
421
1559
  }
422
- fs3.appendFileSync(dest, content);
423
- console.log(`[fullstack-cli] \u2713 ${path3.basename(dest)} (appended)`);
1560
+ fs4.appendFileSync(dest, content);
1561
+ console.log(`[fullstack-cli] \u2713 ${path4.basename(dest)} (appended)`);
424
1562
  }
425
1563
  function setPermissions(permissions, projectRoot) {
426
1564
  for (const [pattern, mode] of Object.entries(permissions)) {
427
1565
  if (pattern === "**/*.sh") {
428
- const scriptsDir = path3.join(projectRoot, "scripts");
429
- if (fs3.existsSync(scriptsDir)) {
430
- const files = fs3.readdirSync(scriptsDir);
1566
+ const scriptsDir = path4.join(projectRoot, "scripts");
1567
+ if (fs4.existsSync(scriptsDir)) {
1568
+ const files = fs4.readdirSync(scriptsDir);
431
1569
  files.forEach((file) => {
432
1570
  if (file.endsWith(".sh")) {
433
- const filePath = path3.join(scriptsDir, file);
434
- fs3.chmodSync(filePath, mode);
1571
+ const filePath = path4.join(scriptsDir, file);
1572
+ fs4.chmodSync(filePath, mode);
435
1573
  }
436
1574
  });
437
1575
  }
@@ -439,19 +1577,19 @@ function setPermissions(permissions, projectRoot) {
439
1577
  }
440
1578
  }
441
1579
  function deleteFile(filePath) {
442
- if (fs3.existsSync(filePath)) {
443
- fs3.unlinkSync(filePath);
444
- console.log(`[fullstack-cli] \u2713 ${path3.basename(filePath)} (deleted)`);
1580
+ if (fs4.existsSync(filePath)) {
1581
+ fs4.unlinkSync(filePath);
1582
+ console.log(`[fullstack-cli] \u2713 ${path4.basename(filePath)} (deleted)`);
445
1583
  } else {
446
- console.log(`[fullstack-cli] \u25CB ${path3.basename(filePath)} (not found)`);
1584
+ console.log(`[fullstack-cli] \u25CB ${path4.basename(filePath)} (not found)`);
447
1585
  }
448
1586
  }
449
1587
  function deleteDirectory(dirPath) {
450
- if (fs3.existsSync(dirPath)) {
451
- fs3.rmSync(dirPath, { recursive: true });
452
- console.log(`[fullstack-cli] \u2713 ${path3.basename(dirPath)} (deleted)`);
1588
+ if (fs4.existsSync(dirPath)) {
1589
+ fs4.rmSync(dirPath, { recursive: true });
1590
+ console.log(`[fullstack-cli] \u2713 ${path4.basename(dirPath)} (deleted)`);
453
1591
  } else {
454
- console.log(`[fullstack-cli] \u25CB ${path3.basename(dirPath)} (not found)`);
1592
+ console.log(`[fullstack-cli] \u25CB ${path4.basename(dirPath)} (not found)`);
455
1593
  }
456
1594
  }
457
1595
 
@@ -467,8 +1605,8 @@ var syncCommand = {
467
1605
  };
468
1606
 
469
1607
  // src/commands/action-plugin/utils.ts
470
- import fs4 from "fs";
471
- import path4 from "path";
1608
+ import fs5 from "fs";
1609
+ import path5 from "path";
472
1610
  import { spawnSync as spawnSync2, execSync } from "child_process";
473
1611
  function parsePluginName(input) {
474
1612
  const match = input.match(/^(@[^/]+\/[^@]+)(?:@(.+))?$/);
@@ -486,18 +1624,18 @@ function getProjectRoot() {
486
1624
  return process.cwd();
487
1625
  }
488
1626
  function getPackageJsonPath() {
489
- return path4.join(getProjectRoot(), "package.json");
1627
+ return path5.join(getProjectRoot(), "package.json");
490
1628
  }
491
1629
  function getPluginPath(pluginName) {
492
- return path4.join(getProjectRoot(), "node_modules", pluginName);
1630
+ return path5.join(getProjectRoot(), "node_modules", pluginName);
493
1631
  }
494
1632
  function readPackageJson() {
495
1633
  const pkgPath = getPackageJsonPath();
496
- if (!fs4.existsSync(pkgPath)) {
1634
+ if (!fs5.existsSync(pkgPath)) {
497
1635
  throw new Error("package.json not found in current directory");
498
1636
  }
499
1637
  try {
500
- const content = fs4.readFileSync(pkgPath, "utf-8");
1638
+ const content = fs5.readFileSync(pkgPath, "utf-8");
501
1639
  return JSON.parse(content);
502
1640
  } catch {
503
1641
  throw new Error("Failed to parse package.json");
@@ -505,7 +1643,7 @@ function readPackageJson() {
505
1643
  }
506
1644
  function writePackageJson(pkg2) {
507
1645
  const pkgPath = getPackageJsonPath();
508
- fs4.writeFileSync(pkgPath, JSON.stringify(pkg2, null, 2) + "\n", "utf-8");
1646
+ fs5.writeFileSync(pkgPath, JSON.stringify(pkg2, null, 2) + "\n", "utf-8");
509
1647
  }
510
1648
  function readActionPlugins() {
511
1649
  const pkg2 = readPackageJson();
@@ -538,12 +1676,12 @@ function npmInstall(tgzPath) {
538
1676
  }
539
1677
  }
540
1678
  function getPackageVersion(pluginName) {
541
- const pkgJsonPath = path4.join(getPluginPath(pluginName), "package.json");
542
- if (!fs4.existsSync(pkgJsonPath)) {
1679
+ const pkgJsonPath = path5.join(getPluginPath(pluginName), "package.json");
1680
+ if (!fs5.existsSync(pkgJsonPath)) {
543
1681
  return null;
544
1682
  }
545
1683
  try {
546
- const content = fs4.readFileSync(pkgJsonPath, "utf-8");
1684
+ const content = fs5.readFileSync(pkgJsonPath, "utf-8");
547
1685
  const pkg2 = JSON.parse(content);
548
1686
  return pkg2.version || null;
549
1687
  } catch {
@@ -551,49 +1689,49 @@ function getPackageVersion(pluginName) {
551
1689
  }
552
1690
  }
553
1691
  function readPluginPackageJson(pluginPath) {
554
- const pkgJsonPath = path4.join(pluginPath, "package.json");
555
- if (!fs4.existsSync(pkgJsonPath)) {
1692
+ const pkgJsonPath = path5.join(pluginPath, "package.json");
1693
+ if (!fs5.existsSync(pkgJsonPath)) {
556
1694
  return null;
557
1695
  }
558
1696
  try {
559
- const content = fs4.readFileSync(pkgJsonPath, "utf-8");
1697
+ const content = fs5.readFileSync(pkgJsonPath, "utf-8");
560
1698
  return JSON.parse(content);
561
1699
  } catch {
562
1700
  return null;
563
1701
  }
564
1702
  }
565
1703
  function extractTgzToNodeModules(tgzPath, pluginName) {
566
- const nodeModulesPath = path4.join(getProjectRoot(), "node_modules");
567
- const targetDir = path4.join(nodeModulesPath, pluginName);
568
- const scopeDir = path4.dirname(targetDir);
569
- if (!fs4.existsSync(scopeDir)) {
570
- fs4.mkdirSync(scopeDir, { recursive: true });
1704
+ const nodeModulesPath = path5.join(getProjectRoot(), "node_modules");
1705
+ const targetDir = path5.join(nodeModulesPath, pluginName);
1706
+ const scopeDir = path5.dirname(targetDir);
1707
+ if (!fs5.existsSync(scopeDir)) {
1708
+ fs5.mkdirSync(scopeDir, { recursive: true });
571
1709
  }
572
- if (fs4.existsSync(targetDir)) {
573
- fs4.rmSync(targetDir, { recursive: true });
1710
+ if (fs5.existsSync(targetDir)) {
1711
+ fs5.rmSync(targetDir, { recursive: true });
574
1712
  }
575
- const tempDir = path4.join(nodeModulesPath, ".cache", "fullstack-cli", "extract-temp");
576
- if (fs4.existsSync(tempDir)) {
577
- fs4.rmSync(tempDir, { recursive: true });
1713
+ const tempDir = path5.join(nodeModulesPath, ".cache", "fullstack-cli", "extract-temp");
1714
+ if (fs5.existsSync(tempDir)) {
1715
+ fs5.rmSync(tempDir, { recursive: true });
578
1716
  }
579
- fs4.mkdirSync(tempDir, { recursive: true });
1717
+ fs5.mkdirSync(tempDir, { recursive: true });
580
1718
  try {
581
1719
  execSync(`tar -xzf "${tgzPath}" -C "${tempDir}"`, { stdio: "pipe" });
582
- const extractedDir = path4.join(tempDir, "package");
583
- if (fs4.existsSync(extractedDir)) {
584
- fs4.renameSync(extractedDir, targetDir);
1720
+ const extractedDir = path5.join(tempDir, "package");
1721
+ if (fs5.existsSync(extractedDir)) {
1722
+ fs5.renameSync(extractedDir, targetDir);
585
1723
  } else {
586
- const files = fs4.readdirSync(tempDir);
1724
+ const files = fs5.readdirSync(tempDir);
587
1725
  if (files.length === 1) {
588
- fs4.renameSync(path4.join(tempDir, files[0]), targetDir);
1726
+ fs5.renameSync(path5.join(tempDir, files[0]), targetDir);
589
1727
  } else {
590
1728
  throw new Error("Unexpected tgz structure");
591
1729
  }
592
1730
  }
593
1731
  return targetDir;
594
1732
  } finally {
595
- if (fs4.existsSync(tempDir)) {
596
- fs4.rmSync(tempDir, { recursive: true });
1733
+ if (fs5.existsSync(tempDir)) {
1734
+ fs5.rmSync(tempDir, { recursive: true });
597
1735
  }
598
1736
  }
599
1737
  }
@@ -602,10 +1740,10 @@ function checkMissingPeerDeps(peerDeps) {
602
1740
  return [];
603
1741
  }
604
1742
  const missing = [];
605
- const nodeModulesPath = path4.join(getProjectRoot(), "node_modules");
1743
+ const nodeModulesPath = path5.join(getProjectRoot(), "node_modules");
606
1744
  for (const [depName, _version] of Object.entries(peerDeps)) {
607
- const depPath = path4.join(nodeModulesPath, depName);
608
- if (!fs4.existsSync(depPath)) {
1745
+ const depPath = path5.join(nodeModulesPath, depName);
1746
+ if (!fs5.existsSync(depPath)) {
609
1747
  missing.push(depName);
610
1748
  }
611
1749
  }
@@ -629,16 +1767,16 @@ function installMissingDeps(deps) {
629
1767
  }
630
1768
  function removePluginDirectory(pluginName) {
631
1769
  const pluginPath = getPluginPath(pluginName);
632
- if (fs4.existsSync(pluginPath)) {
633
- fs4.rmSync(pluginPath, { recursive: true });
1770
+ if (fs5.existsSync(pluginPath)) {
1771
+ fs5.rmSync(pluginPath, { recursive: true });
634
1772
  console.log(`[action-plugin] Removed ${pluginName}`);
635
1773
  }
636
1774
  }
637
1775
 
638
1776
  // src/commands/action-plugin/api-client.ts
639
1777
  import { HttpClient as HttpClient2 } from "@lark-apaas/http-client";
640
- import fs5 from "fs";
641
- import path5 from "path";
1778
+ import fs6 from "fs";
1779
+ import path6 from "path";
642
1780
 
643
1781
  // src/utils/http-client.ts
644
1782
  import { HttpClient } from "@lark-apaas/http-client";
@@ -723,19 +1861,19 @@ async function downloadFromPublic(downloadURL) {
723
1861
  return Buffer.from(arrayBuffer);
724
1862
  }
725
1863
  function getPluginCacheDir() {
726
- return path5.join(process.cwd(), PLUGIN_CACHE_DIR);
1864
+ return path6.join(process.cwd(), PLUGIN_CACHE_DIR);
727
1865
  }
728
1866
  function ensureCacheDir() {
729
1867
  const cacheDir = getPluginCacheDir();
730
- if (!fs5.existsSync(cacheDir)) {
731
- fs5.mkdirSync(cacheDir, { recursive: true });
1868
+ if (!fs6.existsSync(cacheDir)) {
1869
+ fs6.mkdirSync(cacheDir, { recursive: true });
732
1870
  }
733
1871
  }
734
1872
  function getTempFilePath(pluginKey, version) {
735
1873
  ensureCacheDir();
736
1874
  const safeKey = pluginKey.replace(/[/@]/g, "_");
737
1875
  const filename = `${safeKey}-${version}.tgz`;
738
- return path5.join(getPluginCacheDir(), filename);
1876
+ return path6.join(getPluginCacheDir(), filename);
739
1877
  }
740
1878
  async function downloadPlugin(pluginKey, requestedVersion) {
741
1879
  console.log(`[action-plugin] Fetching plugin info for ${pluginKey}@${requestedVersion}...`);
@@ -751,7 +1889,7 @@ async function downloadPlugin(pluginKey, requestedVersion) {
751
1889
  tgzBuffer = await downloadFromPublic(pluginInfo.downloadURL);
752
1890
  }
753
1891
  const tgzPath = getTempFilePath(pluginKey, pluginInfo.version);
754
- fs5.writeFileSync(tgzPath, tgzBuffer);
1892
+ fs6.writeFileSync(tgzPath, tgzBuffer);
755
1893
  console.log(`[action-plugin] Downloaded to ${tgzPath} (${(tgzBuffer.length / 1024).toFixed(2)} KB)`);
756
1894
  return {
757
1895
  tgzPath,
@@ -761,8 +1899,8 @@ async function downloadPlugin(pluginKey, requestedVersion) {
761
1899
  }
762
1900
  function cleanupTempFile(tgzPath) {
763
1901
  try {
764
- if (fs5.existsSync(tgzPath)) {
765
- fs5.unlinkSync(tgzPath);
1902
+ if (fs6.existsSync(tgzPath)) {
1903
+ fs6.unlinkSync(tgzPath);
766
1904
  }
767
1905
  } catch {
768
1906
  }
@@ -1087,39 +2225,39 @@ var actionPluginCommandGroup = {
1087
2225
  };
1088
2226
 
1089
2227
  // src/commands/capability/utils.ts
1090
- import fs6 from "fs";
1091
- import path6 from "path";
2228
+ import fs7 from "fs";
2229
+ import path7 from "path";
1092
2230
  var CAPABILITIES_DIR = "server/capabilities";
1093
2231
  function getProjectRoot2() {
1094
2232
  return process.cwd();
1095
2233
  }
1096
2234
  function getCapabilitiesDir() {
1097
- return path6.join(getProjectRoot2(), CAPABILITIES_DIR);
2235
+ return path7.join(getProjectRoot2(), CAPABILITIES_DIR);
1098
2236
  }
1099
2237
  function getCapabilityPath(id) {
1100
- return path6.join(getCapabilitiesDir(), `${id}.json`);
2238
+ return path7.join(getCapabilitiesDir(), `${id}.json`);
1101
2239
  }
1102
2240
  function getPluginManifestPath(pluginKey) {
1103
- return path6.join(getProjectRoot2(), "node_modules", pluginKey, "manifest.json");
2241
+ return path7.join(getProjectRoot2(), "node_modules", pluginKey, "manifest.json");
1104
2242
  }
1105
2243
  function capabilitiesDirExists() {
1106
- return fs6.existsSync(getCapabilitiesDir());
2244
+ return fs7.existsSync(getCapabilitiesDir());
1107
2245
  }
1108
2246
  function listCapabilityIds() {
1109
2247
  const dir = getCapabilitiesDir();
1110
- if (!fs6.existsSync(dir)) {
2248
+ if (!fs7.existsSync(dir)) {
1111
2249
  return [];
1112
2250
  }
1113
- const files = fs6.readdirSync(dir);
2251
+ const files = fs7.readdirSync(dir);
1114
2252
  return files.filter((f) => f.endsWith(".json")).map((f) => f.replace(/\.json$/, ""));
1115
2253
  }
1116
2254
  function readCapability(id) {
1117
2255
  const filePath = getCapabilityPath(id);
1118
- if (!fs6.existsSync(filePath)) {
2256
+ if (!fs7.existsSync(filePath)) {
1119
2257
  throw new Error(`Capability not found: ${id}`);
1120
2258
  }
1121
2259
  try {
1122
- const content = fs6.readFileSync(filePath, "utf-8");
2260
+ const content = fs7.readFileSync(filePath, "utf-8");
1123
2261
  return JSON.parse(content);
1124
2262
  } catch (error) {
1125
2263
  if (error instanceof SyntaxError) {
@@ -1134,11 +2272,11 @@ function readAllCapabilities() {
1134
2272
  }
1135
2273
  function readPluginManifest(pluginKey) {
1136
2274
  const manifestPath = getPluginManifestPath(pluginKey);
1137
- if (!fs6.existsSync(manifestPath)) {
2275
+ if (!fs7.existsSync(manifestPath)) {
1138
2276
  throw new Error(`Plugin not installed: ${pluginKey} (manifest.json not found)`);
1139
2277
  }
1140
2278
  try {
1141
- const content = fs6.readFileSync(manifestPath, "utf-8");
2279
+ const content = fs7.readFileSync(manifestPath, "utf-8");
1142
2280
  return JSON.parse(content);
1143
2281
  } catch (error) {
1144
2282
  if (error instanceof SyntaxError) {
@@ -1312,58 +2450,58 @@ var capabilityCommandGroup = {
1312
2450
  };
1313
2451
 
1314
2452
  // src/commands/migration/version-manager.ts
1315
- import fs7 from "fs";
1316
- import path7 from "path";
2453
+ import fs8 from "fs";
2454
+ import path8 from "path";
1317
2455
  var PACKAGE_JSON = "package.json";
1318
2456
  var VERSION_FIELD = "migrationVersion";
1319
2457
  function getPackageJsonPath2() {
1320
- return path7.join(process.cwd(), PACKAGE_JSON);
2458
+ return path8.join(process.cwd(), PACKAGE_JSON);
1321
2459
  }
1322
2460
  function getCurrentVersion() {
1323
2461
  const pkgPath = getPackageJsonPath2();
1324
- if (!fs7.existsSync(pkgPath)) {
2462
+ if (!fs8.existsSync(pkgPath)) {
1325
2463
  throw new Error("package.json not found");
1326
2464
  }
1327
- const pkg2 = JSON.parse(fs7.readFileSync(pkgPath, "utf-8"));
2465
+ const pkg2 = JSON.parse(fs8.readFileSync(pkgPath, "utf-8"));
1328
2466
  return pkg2[VERSION_FIELD] ?? 0;
1329
2467
  }
1330
2468
  function setCurrentVersion(version) {
1331
2469
  const pkgPath = getPackageJsonPath2();
1332
- const pkg2 = JSON.parse(fs7.readFileSync(pkgPath, "utf-8"));
2470
+ const pkg2 = JSON.parse(fs8.readFileSync(pkgPath, "utf-8"));
1333
2471
  pkg2[VERSION_FIELD] = version;
1334
- fs7.writeFileSync(pkgPath, JSON.stringify(pkg2, null, 2) + "\n", "utf-8");
2472
+ fs8.writeFileSync(pkgPath, JSON.stringify(pkg2, null, 2) + "\n", "utf-8");
1335
2473
  }
1336
2474
 
1337
2475
  // src/commands/migration/versions/v001_capability/json-migrator/detector.ts
1338
- import fs9 from "fs";
1339
- import path9 from "path";
2476
+ import fs10 from "fs";
2477
+ import path10 from "path";
1340
2478
 
1341
2479
  // src/commands/migration/versions/v001_capability/utils.ts
1342
- import fs8 from "fs";
1343
- import path8 from "path";
2480
+ import fs9 from "fs";
2481
+ import path9 from "path";
1344
2482
  var CAPABILITIES_DIR2 = "server/capabilities";
1345
2483
  function getProjectRoot3() {
1346
2484
  return process.cwd();
1347
2485
  }
1348
2486
  function getCapabilitiesDir2() {
1349
- return path8.join(getProjectRoot3(), CAPABILITIES_DIR2);
2487
+ return path9.join(getProjectRoot3(), CAPABILITIES_DIR2);
1350
2488
  }
1351
2489
  function getPluginManifestPath2(pluginKey) {
1352
- return path8.join(getProjectRoot3(), "node_modules", pluginKey, "manifest.json");
2490
+ return path9.join(getProjectRoot3(), "node_modules", pluginKey, "manifest.json");
1353
2491
  }
1354
2492
 
1355
2493
  // src/commands/migration/versions/v001_capability/json-migrator/detector.ts
1356
2494
  function detectJsonMigration() {
1357
2495
  const capabilitiesDir = getCapabilitiesDir2();
1358
- const oldFilePath = path9.join(capabilitiesDir, "capabilities.json");
1359
- if (!fs9.existsSync(oldFilePath)) {
2496
+ const oldFilePath = path10.join(capabilitiesDir, "capabilities.json");
2497
+ if (!fs10.existsSync(oldFilePath)) {
1360
2498
  return {
1361
2499
  needsMigration: false,
1362
2500
  reason: "capabilities.json not found"
1363
2501
  };
1364
2502
  }
1365
2503
  try {
1366
- const content = fs9.readFileSync(oldFilePath, "utf-8");
2504
+ const content = fs10.readFileSync(oldFilePath, "utf-8");
1367
2505
  const parsed = JSON.parse(content);
1368
2506
  const capabilities = Array.isArray(parsed) ? parsed : [];
1369
2507
  return {
@@ -1403,8 +2541,8 @@ async function check(options) {
1403
2541
  }
1404
2542
 
1405
2543
  // src/commands/migration/versions/v001_capability/json-migrator/index.ts
1406
- import fs10 from "fs";
1407
- import path10 from "path";
2544
+ import fs11 from "fs";
2545
+ import path11 from "path";
1408
2546
 
1409
2547
  // src/commands/migration/versions/v001_capability/mapping.ts
1410
2548
  var DEFAULT_PLUGIN_VERSION = "1.0.0";
@@ -1634,18 +2772,18 @@ function transformCapabilities(oldCapabilities) {
1634
2772
  // src/commands/migration/versions/v001_capability/json-migrator/index.ts
1635
2773
  function loadExistingCapabilities() {
1636
2774
  const capabilitiesDir = getCapabilitiesDir2();
1637
- if (!fs10.existsSync(capabilitiesDir)) {
2775
+ if (!fs11.existsSync(capabilitiesDir)) {
1638
2776
  return [];
1639
2777
  }
1640
- const files = fs10.readdirSync(capabilitiesDir);
2778
+ const files = fs11.readdirSync(capabilitiesDir);
1641
2779
  const capabilities = [];
1642
2780
  for (const file of files) {
1643
2781
  if (file === "capabilities.json" || !file.endsWith(".json")) {
1644
2782
  continue;
1645
2783
  }
1646
2784
  try {
1647
- const filePath = path10.join(capabilitiesDir, file);
1648
- const content = fs10.readFileSync(filePath, "utf-8");
2785
+ const filePath = path11.join(capabilitiesDir, file);
2786
+ const content = fs11.readFileSync(filePath, "utf-8");
1649
2787
  const capability = JSON.parse(content);
1650
2788
  if (capability.id && capability.pluginKey) {
1651
2789
  capabilities.push(capability);
@@ -1703,9 +2841,9 @@ async function migrateJsonFiles(options) {
1703
2841
  }
1704
2842
  const capabilitiesDir = getCapabilitiesDir2();
1705
2843
  for (const cap of newCapabilities) {
1706
- const filePath = path10.join(capabilitiesDir, `${cap.id}.json`);
2844
+ const filePath = path11.join(capabilitiesDir, `${cap.id}.json`);
1707
2845
  const content = JSON.stringify(cap, null, 2);
1708
- fs10.writeFileSync(filePath, content, "utf-8");
2846
+ fs11.writeFileSync(filePath, content, "utf-8");
1709
2847
  console.log(` \u2713 Created: ${cap.id}.json`);
1710
2848
  }
1711
2849
  return {
@@ -1717,10 +2855,10 @@ async function migrateJsonFiles(options) {
1717
2855
  }
1718
2856
 
1719
2857
  // src/commands/migration/versions/v001_capability/plugin-installer/detector.ts
1720
- import fs11 from "fs";
2858
+ import fs12 from "fs";
1721
2859
  function isPluginInstalled2(pluginKey) {
1722
2860
  const manifestPath = getPluginManifestPath2(pluginKey);
1723
- return fs11.existsSync(manifestPath);
2861
+ return fs12.existsSync(manifestPath);
1724
2862
  }
1725
2863
  function detectPluginsToInstall(capabilities) {
1726
2864
  const pluginKeys = /* @__PURE__ */ new Set();
@@ -1796,12 +2934,12 @@ async function installPlugins(capabilities, options) {
1796
2934
  }
1797
2935
 
1798
2936
  // src/commands/migration/versions/v001_capability/code-migrator/index.ts
1799
- import path12 from "path";
1800
- import { Project } from "ts-morph";
2937
+ import path13 from "path";
2938
+ import { Project as Project2 } from "ts-morph";
1801
2939
 
1802
2940
  // src/commands/migration/versions/v001_capability/code-migrator/scanner.ts
1803
- import fs12 from "fs";
1804
- import path11 from "path";
2941
+ import fs13 from "fs";
2942
+ import path12 from "path";
1805
2943
  var EXCLUDED_DIRS = [
1806
2944
  "node_modules",
1807
2945
  "dist",
@@ -1816,9 +2954,9 @@ var EXCLUDED_PATTERNS = [
1816
2954
  /\.d\.ts$/
1817
2955
  ];
1818
2956
  function scanDirectory(dir, files = []) {
1819
- const entries = fs12.readdirSync(dir, { withFileTypes: true });
2957
+ const entries = fs13.readdirSync(dir, { withFileTypes: true });
1820
2958
  for (const entry of entries) {
1821
- const fullPath = path11.join(dir, entry.name);
2959
+ const fullPath = path12.join(dir, entry.name);
1822
2960
  if (entry.isDirectory()) {
1823
2961
  if (EXCLUDED_DIRS.includes(entry.name)) {
1824
2962
  continue;
@@ -1834,14 +2972,14 @@ function scanDirectory(dir, files = []) {
1834
2972
  return files;
1835
2973
  }
1836
2974
  function scanServerFiles() {
1837
- const serverDir = path11.join(getProjectRoot3(), "server");
1838
- if (!fs12.existsSync(serverDir)) {
2975
+ const serverDir = path12.join(getProjectRoot3(), "server");
2976
+ if (!fs13.existsSync(serverDir)) {
1839
2977
  return [];
1840
2978
  }
1841
2979
  return scanDirectory(serverDir);
1842
2980
  }
1843
2981
  function hasCapabilityImport(filePath) {
1844
- const content = fs12.readFileSync(filePath, "utf-8");
2982
+ const content = fs13.readFileSync(filePath, "utf-8");
1845
2983
  return /import\s+.*from\s+['"][^'"]*capabilities[^'"]*['"]/.test(content);
1846
2984
  }
1847
2985
  function scanFilesToMigrate() {
@@ -2216,7 +3354,7 @@ function analyzeFile(project, filePath, actionNameMap) {
2216
3354
  const callSites = analyzeCallSites(sourceFile, imports);
2217
3355
  const classInfo = analyzeClass(sourceFile);
2218
3356
  const { canMigrate, reason } = canAutoMigrate(classInfo);
2219
- const relativePath = path12.relative(getProjectRoot3(), filePath);
3357
+ const relativePath = path13.relative(getProjectRoot3(), filePath);
2220
3358
  return {
2221
3359
  filePath: relativePath,
2222
3360
  imports,
@@ -2227,7 +3365,7 @@ function analyzeFile(project, filePath, actionNameMap) {
2227
3365
  };
2228
3366
  }
2229
3367
  function migrateFile(project, analysis, dryRun) {
2230
- const absolutePath = path12.join(getProjectRoot3(), analysis.filePath);
3368
+ const absolutePath = path13.join(getProjectRoot3(), analysis.filePath);
2231
3369
  if (!analysis.canAutoMigrate) {
2232
3370
  return {
2233
3371
  filePath: analysis.filePath,
@@ -2287,7 +3425,7 @@ async function migrateCode(options, capabilities) {
2287
3425
  console.log(" No files need code migration.\n");
2288
3426
  return result;
2289
3427
  }
2290
- const project = new Project({
3428
+ const project = new Project2({
2291
3429
  skipAddingFilesFromTsConfig: true,
2292
3430
  compilerOptions: {
2293
3431
  allowJs: true
@@ -2330,17 +3468,17 @@ function getSuggestion(analysis) {
2330
3468
  }
2331
3469
 
2332
3470
  // src/commands/migration/versions/v001_capability/cleanup.ts
2333
- import fs13 from "fs";
2334
- import path13 from "path";
3471
+ import fs14 from "fs";
3472
+ import path14 from "path";
2335
3473
  function cleanupOldFiles(capabilities, dryRun) {
2336
3474
  const deletedFiles = [];
2337
3475
  const errors = [];
2338
3476
  const capabilitiesDir = getCapabilitiesDir2();
2339
- const oldJsonPath = path13.join(capabilitiesDir, "capabilities.json");
2340
- if (fs13.existsSync(oldJsonPath)) {
3477
+ const oldJsonPath = path14.join(capabilitiesDir, "capabilities.json");
3478
+ if (fs14.existsSync(oldJsonPath)) {
2341
3479
  try {
2342
3480
  if (!dryRun) {
2343
- fs13.unlinkSync(oldJsonPath);
3481
+ fs14.unlinkSync(oldJsonPath);
2344
3482
  }
2345
3483
  deletedFiles.push("capabilities.json");
2346
3484
  } catch (error) {
@@ -2348,11 +3486,11 @@ function cleanupOldFiles(capabilities, dryRun) {
2348
3486
  }
2349
3487
  }
2350
3488
  for (const cap of capabilities) {
2351
- const tsFilePath = path13.join(capabilitiesDir, `${cap.id}.ts`);
2352
- if (fs13.existsSync(tsFilePath)) {
3489
+ const tsFilePath = path14.join(capabilitiesDir, `${cap.id}.ts`);
3490
+ if (fs14.existsSync(tsFilePath)) {
2353
3491
  try {
2354
3492
  if (!dryRun) {
2355
- fs13.unlinkSync(tsFilePath);
3493
+ fs14.unlinkSync(tsFilePath);
2356
3494
  }
2357
3495
  deletedFiles.push(`${cap.id}.ts`);
2358
3496
  } catch (error) {
@@ -2368,8 +3506,8 @@ function cleanupOldFiles(capabilities, dryRun) {
2368
3506
  }
2369
3507
 
2370
3508
  // src/commands/migration/versions/v001_capability/report-generator.ts
2371
- import fs14 from "fs";
2372
- import path14 from "path";
3509
+ import fs15 from "fs";
3510
+ import path15 from "path";
2373
3511
  var REPORT_FILE = "capability-migration-report.md";
2374
3512
  function printSummary(result) {
2375
3513
  const { jsonMigration, pluginInstallation, codeMigration, cleanup } = result;
@@ -2532,15 +3670,15 @@ async function generateReport(result) {
2532
3670
  }
2533
3671
  lines.push("");
2534
3672
  const logDir = process.env.LOG_DIR || "logs";
2535
- if (!fs14.existsSync(logDir)) {
3673
+ if (!fs15.existsSync(logDir)) {
2536
3674
  return;
2537
3675
  }
2538
- const reportDir = path14.join(logDir, "migration");
2539
- if (!fs14.existsSync(reportDir)) {
2540
- fs14.mkdirSync(reportDir, { recursive: true });
3676
+ const reportDir = path15.join(logDir, "migration");
3677
+ if (!fs15.existsSync(reportDir)) {
3678
+ fs15.mkdirSync(reportDir, { recursive: true });
2541
3679
  }
2542
- const reportPath = path14.join(reportDir, REPORT_FILE);
2543
- fs14.writeFileSync(reportPath, lines.join("\n"), "utf-8");
3680
+ const reportPath = path15.join(reportDir, REPORT_FILE);
3681
+ fs15.writeFileSync(reportPath, lines.join("\n"), "utf-8");
2544
3682
  console.log(`\u{1F4C4} Report generated: ${reportPath}`);
2545
3683
  }
2546
3684
 
@@ -3072,10 +4210,10 @@ var migrationCommand = {
3072
4210
  };
3073
4211
 
3074
4212
  // src/commands/read-logs/index.ts
3075
- import path15 from "path";
4213
+ import path16 from "path";
3076
4214
 
3077
4215
  // src/commands/read-logs/std-utils.ts
3078
- import fs15 from "fs";
4216
+ import fs16 from "fs";
3079
4217
  function formatStdPrefixTime(localTime) {
3080
4218
  const match = localTime.match(/^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/);
3081
4219
  if (!match) return localTime;
@@ -3105,11 +4243,11 @@ function stripPrefixFromStdLine(line) {
3105
4243
  return `[${time}] ${content}`;
3106
4244
  }
3107
4245
  function readStdLinesTailFromLastMarkerPaged(filePath, maxLines, offset, isMarker) {
3108
- const stat = fs15.statSync(filePath);
4246
+ const stat = fs16.statSync(filePath);
3109
4247
  if (stat.size === 0) {
3110
4248
  return { lines: [], markerFound: false, totalLinesCount: 0 };
3111
4249
  }
3112
- const fd = fs15.openSync(filePath, "r");
4250
+ const fd = fs16.openSync(filePath, "r");
3113
4251
  const chunkSize = 64 * 1024;
3114
4252
  let position = stat.size;
3115
4253
  let remainder = "";
@@ -3123,7 +4261,7 @@ function readStdLinesTailFromLastMarkerPaged(filePath, maxLines, offset, isMarke
3123
4261
  const length = Math.min(chunkSize, position);
3124
4262
  position -= length;
3125
4263
  const buffer = Buffer.alloc(length);
3126
- fs15.readSync(fd, buffer, 0, length, position);
4264
+ fs16.readSync(fd, buffer, 0, length, position);
3127
4265
  let chunk = buffer.toString("utf8");
3128
4266
  if (remainder) {
3129
4267
  chunk += remainder;
@@ -3165,7 +4303,7 @@ function readStdLinesTailFromLastMarkerPaged(filePath, maxLines, offset, isMarke
3165
4303
  }
3166
4304
  }
3167
4305
  } finally {
3168
- fs15.closeSync(fd);
4306
+ fs16.closeSync(fd);
3169
4307
  }
3170
4308
  return { lines: collected.reverse(), markerFound, totalLinesCount };
3171
4309
  }
@@ -3186,21 +4324,21 @@ function readServerStdSegment(filePath, maxLines, offset) {
3186
4324
  }
3187
4325
 
3188
4326
  // src/commands/read-logs/tail.ts
3189
- import fs16 from "fs";
4327
+ import fs17 from "fs";
3190
4328
  function fileExists(filePath) {
3191
4329
  try {
3192
- fs16.accessSync(filePath, fs16.constants.F_OK | fs16.constants.R_OK);
4330
+ fs17.accessSync(filePath, fs17.constants.F_OK | fs17.constants.R_OK);
3193
4331
  return true;
3194
4332
  } catch {
3195
4333
  return false;
3196
4334
  }
3197
4335
  }
3198
4336
  function readFileTailLines(filePath, maxLines) {
3199
- const stat = fs16.statSync(filePath);
4337
+ const stat = fs17.statSync(filePath);
3200
4338
  if (stat.size === 0) {
3201
4339
  return [];
3202
4340
  }
3203
- const fd = fs16.openSync(filePath, "r");
4341
+ const fd = fs17.openSync(filePath, "r");
3204
4342
  const chunkSize = 64 * 1024;
3205
4343
  const chunks = [];
3206
4344
  let position = stat.size;
@@ -3210,13 +4348,13 @@ function readFileTailLines(filePath, maxLines) {
3210
4348
  const length = Math.min(chunkSize, position);
3211
4349
  position -= length;
3212
4350
  const buffer = Buffer.alloc(length);
3213
- fs16.readSync(fd, buffer, 0, length, position);
4351
+ fs17.readSync(fd, buffer, 0, length, position);
3214
4352
  chunks.unshift(buffer.toString("utf8"));
3215
4353
  const chunkLines = buffer.toString("utf8").split("\n").length - 1;
3216
4354
  collectedLines += chunkLines;
3217
4355
  }
3218
4356
  } finally {
3219
- fs16.closeSync(fd);
4357
+ fs17.closeSync(fd);
3220
4358
  }
3221
4359
  const content = chunks.join("");
3222
4360
  const allLines = content.split("\n");
@@ -3232,11 +4370,11 @@ function readFileTailLines(filePath, maxLines) {
3232
4370
  return allLines.slice(allLines.length - maxLines);
3233
4371
  }
3234
4372
  function readFileTailNonEmptyLinesWithOffset(filePath, maxLines, offset) {
3235
- const stat = fs16.statSync(filePath);
4373
+ const stat = fs17.statSync(filePath);
3236
4374
  if (stat.size === 0) {
3237
4375
  return { lines: [], totalLinesCount: 0 };
3238
4376
  }
3239
- const fd = fs16.openSync(filePath, "r");
4377
+ const fd = fs17.openSync(filePath, "r");
3240
4378
  const chunkSize = 64 * 1024;
3241
4379
  let position = stat.size;
3242
4380
  let remainder = "";
@@ -3248,7 +4386,7 @@ function readFileTailNonEmptyLinesWithOffset(filePath, maxLines, offset) {
3248
4386
  const length = Math.min(chunkSize, position);
3249
4387
  position -= length;
3250
4388
  const buffer = Buffer.alloc(length);
3251
- fs16.readSync(fd, buffer, 0, length, position);
4389
+ fs17.readSync(fd, buffer, 0, length, position);
3252
4390
  let chunk = buffer.toString("utf8");
3253
4391
  if (remainder) {
3254
4392
  chunk += remainder;
@@ -3279,7 +4417,7 @@ function readFileTailNonEmptyLinesWithOffset(filePath, maxLines, offset) {
3279
4417
  }
3280
4418
  }
3281
4419
  } finally {
3282
- fs16.closeSync(fd);
4420
+ fs17.closeSync(fd);
3283
4421
  }
3284
4422
  return { lines: collected.reverse(), totalLinesCount };
3285
4423
  }
@@ -3381,7 +4519,7 @@ function extractClientStdSegment(lines, maxLines, offset) {
3381
4519
  }
3382
4520
 
3383
4521
  // src/commands/read-logs/json-lines.ts
3384
- import fs17 from "fs";
4522
+ import fs18 from "fs";
3385
4523
  function normalizePid(value) {
3386
4524
  if (typeof value === "number") {
3387
4525
  return String(value);
@@ -3432,11 +4570,11 @@ function buildWantedLevelSet(levels) {
3432
4570
  return set.size > 0 ? set : null;
3433
4571
  }
3434
4572
  function readJsonLinesLastPid(filePath, maxLines, offset, levels) {
3435
- const stat = fs17.statSync(filePath);
4573
+ const stat = fs18.statSync(filePath);
3436
4574
  if (stat.size === 0) {
3437
4575
  return { lines: [], totalLinesCount: 0 };
3438
4576
  }
3439
- const fd = fs17.openSync(filePath, "r");
4577
+ const fd = fs18.openSync(filePath, "r");
3440
4578
  const chunkSize = 64 * 1024;
3441
4579
  let position = stat.size;
3442
4580
  let remainder = "";
@@ -3451,7 +4589,7 @@ function readJsonLinesLastPid(filePath, maxLines, offset, levels) {
3451
4589
  const length = Math.min(chunkSize, position);
3452
4590
  position -= length;
3453
4591
  const buffer = Buffer.alloc(length);
3454
- fs17.readSync(fd, buffer, 0, length, position);
4592
+ fs18.readSync(fd, buffer, 0, length, position);
3455
4593
  let chunk = buffer.toString("utf8");
3456
4594
  if (remainder) {
3457
4595
  chunk += remainder;
@@ -3513,7 +4651,7 @@ function readJsonLinesLastPid(filePath, maxLines, offset, levels) {
3513
4651
  }
3514
4652
  }
3515
4653
  } finally {
3516
- fs17.closeSync(fd);
4654
+ fs18.closeSync(fd);
3517
4655
  }
3518
4656
  return { lines: collected.reverse(), totalLinesCount };
3519
4657
  }
@@ -3556,11 +4694,11 @@ function extractTraceId(obj) {
3556
4694
  function readJsonLinesByTraceId(filePath, traceId, maxLines, offset, levels) {
3557
4695
  const wanted = traceId.trim();
3558
4696
  if (!wanted) return { lines: [], totalLinesCount: 0 };
3559
- const stat = fs17.statSync(filePath);
4697
+ const stat = fs18.statSync(filePath);
3560
4698
  if (stat.size === 0) {
3561
4699
  return { lines: [], totalLinesCount: 0 };
3562
4700
  }
3563
- const fd = fs17.openSync(filePath, "r");
4701
+ const fd = fs18.openSync(filePath, "r");
3564
4702
  const chunkSize = 64 * 1024;
3565
4703
  let position = stat.size;
3566
4704
  let remainder = "";
@@ -3573,7 +4711,7 @@ function readJsonLinesByTraceId(filePath, traceId, maxLines, offset, levels) {
3573
4711
  const length = Math.min(chunkSize, position);
3574
4712
  position -= length;
3575
4713
  const buffer = Buffer.alloc(length);
3576
- fs17.readSync(fd, buffer, 0, length, position);
4714
+ fs18.readSync(fd, buffer, 0, length, position);
3577
4715
  let chunk = buffer.toString("utf8");
3578
4716
  if (remainder) {
3579
4717
  chunk += remainder;
@@ -3626,7 +4764,7 @@ function readJsonLinesByTraceId(filePath, traceId, maxLines, offset, levels) {
3626
4764
  }
3627
4765
  }
3628
4766
  } finally {
3629
- fs17.closeSync(fd);
4767
+ fs18.closeSync(fd);
3630
4768
  }
3631
4769
  return { lines: collected.reverse(), totalLinesCount };
3632
4770
  }
@@ -3635,11 +4773,11 @@ function readJsonLinesTailByLevel(filePath, maxLines, offset, levels) {
3635
4773
  if (!wantedLevelSet) {
3636
4774
  return { lines: [], totalLinesCount: 0 };
3637
4775
  }
3638
- const stat = fs17.statSync(filePath);
4776
+ const stat = fs18.statSync(filePath);
3639
4777
  if (stat.size === 0) {
3640
4778
  return { lines: [], totalLinesCount: 0 };
3641
4779
  }
3642
- const fd = fs17.openSync(filePath, "r");
4780
+ const fd = fs18.openSync(filePath, "r");
3643
4781
  const chunkSize = 64 * 1024;
3644
4782
  let position = stat.size;
3645
4783
  let remainder = "";
@@ -3651,7 +4789,7 @@ function readJsonLinesTailByLevel(filePath, maxLines, offset, levels) {
3651
4789
  const length = Math.min(chunkSize, position);
3652
4790
  position -= length;
3653
4791
  const buffer = Buffer.alloc(length);
3654
- fs17.readSync(fd, buffer, 0, length, position);
4792
+ fs18.readSync(fd, buffer, 0, length, position);
3655
4793
  let chunk = buffer.toString("utf8");
3656
4794
  if (remainder) {
3657
4795
  chunk += remainder;
@@ -3698,7 +4836,7 @@ function readJsonLinesTailByLevel(filePath, maxLines, offset, levels) {
3698
4836
  }
3699
4837
  }
3700
4838
  } finally {
3701
- fs17.closeSync(fd);
4839
+ fs18.closeSync(fd);
3702
4840
  }
3703
4841
  return { lines: collected.reverse(), totalLinesCount };
3704
4842
  }
@@ -3829,21 +4967,21 @@ async function readLogsJsonResult(options) {
3829
4967
  };
3830
4968
  }
3831
4969
  function resolveLogFilePath(logDir, type) {
3832
- const base = path15.isAbsolute(logDir) ? logDir : path15.join(process.cwd(), logDir);
4970
+ const base = path16.isAbsolute(logDir) ? logDir : path16.join(process.cwd(), logDir);
3833
4971
  if (type === "server") {
3834
- return path15.join(base, "server.log");
4972
+ return path16.join(base, "server.log");
3835
4973
  }
3836
4974
  if (type === "trace") {
3837
- return path15.join(base, "trace.log");
4975
+ return path16.join(base, "trace.log");
3838
4976
  }
3839
4977
  if (type === "server-std") {
3840
- return path15.join(base, "server.std.log");
4978
+ return path16.join(base, "server.std.log");
3841
4979
  }
3842
4980
  if (type === "client-std") {
3843
- return path15.join(base, "client.std.log");
4981
+ return path16.join(base, "client.std.log");
3844
4982
  }
3845
4983
  if (type === "browser") {
3846
- return path15.join(base, "browser.log");
4984
+ return path16.join(base, "browser.log");
3847
4985
  }
3848
4986
  throw new Error(`Unsupported log type: ${type}`);
3849
4987
  }
@@ -3918,12 +5056,12 @@ var commands = [
3918
5056
  ];
3919
5057
 
3920
5058
  // src/index.ts
3921
- var envPath = path16.join(process.cwd(), ".env");
3922
- if (fs18.existsSync(envPath)) {
5059
+ var envPath = path17.join(process.cwd(), ".env");
5060
+ if (fs19.existsSync(envPath)) {
3923
5061
  dotenvConfig({ path: envPath });
3924
5062
  }
3925
- var __dirname = path16.dirname(fileURLToPath3(import.meta.url));
3926
- var pkg = JSON.parse(fs18.readFileSync(path16.join(__dirname, "../package.json"), "utf-8"));
5063
+ var __dirname = path17.dirname(fileURLToPath3(import.meta.url));
5064
+ var pkg = JSON.parse(fs19.readFileSync(path17.join(__dirname, "../package.json"), "utf-8"));
3927
5065
  var cli = new FullstackCLI(pkg.version);
3928
5066
  cli.useAll(commands);
3929
5067
  cli.run();