@lark-apaas/fullstack-cli 1.1.13-alpha.1 → 1.1.13-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // src/index.ts
2
- import fs18 from "fs";
3
- import path16 from "path";
4
- import { fileURLToPath as fileURLToPath3 } from "url";
2
+ import fs20 from "fs";
3
+ import path17 from "path";
4
+ import { fileURLToPath as fileURLToPath4 } from "url";
5
5
  import { config as dotenvConfig } from "dotenv";
6
6
 
7
7
  // src/cli.ts
@@ -116,17 +116,1169 @@ 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";
121
- import { fileURLToPath } from "url";
119
+ import path2 from "path";
120
+ import fs3 from "fs";
121
+ import { fileURLToPath as fileURLToPath2 } from "url";
122
122
  import { spawnSync } from "child_process";
123
123
  import { createRequire } from "module";
124
124
  import { config as loadEnv } from "dotenv";
125
+
126
+ // src/commands/db/gen-dbschema/postprocess.ts
127
+ import fs2 from "fs";
128
+ import path from "path";
129
+
130
+ // src/commands/db/gen-dbschema/helper/header-format.ts
131
+ var HEADER_COMMENT = "/** auto generated, do not edit */";
132
+ function ensureHeaderComment(source) {
133
+ let text = source.startsWith("\uFEFF") ? source.slice(1) : source;
134
+ while (text.startsWith(HEADER_COMMENT)) {
135
+ text = text.slice(HEADER_COMMENT.length);
136
+ text = stripLeadingNewlines(text);
137
+ }
138
+ const trimmed = stripLeadingNewlines(text);
139
+ if (trimmed.length === 0) {
140
+ return `${HEADER_COMMENT}
141
+ `;
142
+ }
143
+ return `${HEADER_COMMENT}
144
+ ${trimmed}`;
145
+ }
146
+ function stripLeadingNewlines(value) {
147
+ let current = value;
148
+ while (current.startsWith("\r\n") || current.startsWith("\n")) {
149
+ current = current.startsWith("\r\n") ? current.slice(2) : current.slice(1);
150
+ }
151
+ return current;
152
+ }
153
+ function collapseExtraBlankLines(text) {
154
+ return text.replace(/\n{3,}/g, "\n\n");
155
+ }
156
+
157
+ // src/commands/db/gen-dbschema/helper/schema-conversion.ts
158
+ function removePgSchemaDeclarations(source) {
159
+ return source.replace(/export const \w+ = pgSchema\([\s\S]*?\);\n*/g, "");
160
+ }
161
+ function convertSchemaTableInvocations(source) {
162
+ let converted = 0;
163
+ let text = source.replace(/([A-Za-z0-9_]+)\.table\(/g, () => {
164
+ converted += 1;
165
+ return "pgTable(";
166
+ });
167
+ text = text.replace(/([A-Za-z0-9_]+)\.view\(/g, () => {
168
+ converted += 1;
169
+ return "pgView(";
170
+ });
171
+ text = text.replace(/([A-Za-z0-9_]+)\.materializedView\(/g, () => {
172
+ converted += 1;
173
+ return "pgMaterializedView(";
174
+ });
175
+ text = text.replace(/([A-Za-z0-9_]+)\.enum\(/g, () => {
176
+ converted += 1;
177
+ return "pgEnum(";
178
+ });
179
+ text = text.replace(/([A-Za-z0-9_]+)\.sequence\(/g, () => {
180
+ converted += 1;
181
+ return "pgSequence(";
182
+ });
183
+ return { text, converted };
184
+ }
185
+
186
+ // src/commands/db/gen-dbschema/helper/table-rename.ts
187
+ import { pinyin } from "pinyin-pro";
188
+ function renamePgTableConstants(source) {
189
+ const pgTableRegex = /export const\s+([^\s=]+)\s*=\s*(pgTable|pgView|pgMaterializedView)\(\s*["'`]([^"'`]+)["'`]/gu;
190
+ const renames = [];
191
+ const updated = source.replace(pgTableRegex, (match, currentName, factory, tableName) => {
192
+ const sanitized = sanitizeIdentifier(tableName);
193
+ if (sanitized === currentName) {
194
+ return match;
195
+ }
196
+ renames.push({ from: currentName, to: sanitized });
197
+ const equalsIndex = match.indexOf("=");
198
+ const suffix = equalsIndex >= 0 ? match.slice(equalsIndex) : ` = ${factory}("${tableName}"`;
199
+ const normalizedSuffix = suffix.trimStart();
200
+ return `export const ${sanitized} ${normalizedSuffix}`;
201
+ });
202
+ return { text: updated, renames };
203
+ }
204
+ function updateTableReferenceIdentifiers(source, renames) {
205
+ if (renames.length === 0) {
206
+ return source;
207
+ }
208
+ return renames.reduce((acc, rename) => {
209
+ if (!rename.from || rename.from === rename.to) {
210
+ return acc;
211
+ }
212
+ const pattern = new RegExp(`\\b${escapeRegExp(rename.from)}(\\s*\\.)`, "g");
213
+ return acc.replace(pattern, `${rename.to}$1`);
214
+ }, source);
215
+ }
216
+ function escapeRegExp(value) {
217
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace(/\//g, "\\/");
218
+ }
219
+ function toCamelCase(str) {
220
+ const words = str.split(/[_\-\s]+/).filter(Boolean);
221
+ if (words.length === 0) {
222
+ return "";
223
+ }
224
+ return words.map((word, index) => {
225
+ if (index === 0) {
226
+ return word.toLowerCase();
227
+ }
228
+ return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
229
+ }).join("");
230
+ }
231
+ function sanitizeIdentifier(name) {
232
+ const asciiName = toAsciiName(name);
233
+ let sanitized = asciiName.replace(/[^A-Za-z0-9_]/g, "_");
234
+ sanitized = sanitized.replace(/_+/g, "_");
235
+ sanitized = sanitized.replace(/^_|_$/g, "");
236
+ sanitized = toCamelCase(sanitized);
237
+ if (!sanitized) {
238
+ sanitized = "table";
239
+ }
240
+ if (!/^[A-Za-z_]/.test(sanitized)) {
241
+ sanitized = `_${sanitized}`;
242
+ }
243
+ return sanitized;
244
+ }
245
+ function toAsciiName(name) {
246
+ if (!/[^\x00-\x7F]/.test(name)) {
247
+ return name;
248
+ }
249
+ try {
250
+ const transliterated = pinyin(name, { toneType: "none", type: "array" }).join("_");
251
+ return transliterated || name;
252
+ } catch (error) {
253
+ return name;
254
+ }
255
+ }
256
+
257
+ // src/commands/db/gen-dbschema/helper/custom-types.ts
258
+ var CUSTOM_TYPE_PATTERN = /\/\/ TODO: failed to parse database type '(?:\w+\.)?(user_profile|file_attachment)(\[\])?'/;
259
+ function replaceUnknownColumns(source) {
260
+ const lines = source.split("\n");
261
+ const result = [];
262
+ let replaced = 0;
263
+ const unmatched = [];
264
+ for (let i = 0; i < lines.length; i += 1) {
265
+ const line = lines[i];
266
+ const match = line.match(CUSTOM_TYPE_PATTERN);
267
+ if (match) {
268
+ const typeName = match[1];
269
+ const factory = typeName === "user_profile" ? "userProfile" : "fileAttachment";
270
+ const replacedLine = replaceFollowingUnknown(lines[i + 1], factory);
271
+ if (replacedLine) {
272
+ result.push(replacedLine);
273
+ replaced += 1;
274
+ i += 1;
275
+ } else {
276
+ unmatched.push(line.trim());
277
+ result.push(line);
278
+ }
279
+ continue;
280
+ }
281
+ if (line.includes("unknown(")) {
282
+ unmatched.push(line.trim());
283
+ }
284
+ result.push(line);
285
+ }
286
+ return {
287
+ text: result.join("\n"),
288
+ replaced,
289
+ unmatched
290
+ };
291
+ }
292
+ function replaceFollowingUnknown(nextLine, factory) {
293
+ if (!nextLine || !nextLine.includes("unknown(")) {
294
+ return void 0;
295
+ }
296
+ return nextLine.replace("unknown(", `${factory}(`);
297
+ }
298
+
299
+ // src/commands/db/gen-dbschema/helper/imports.ts
300
+ import fs from "fs";
301
+ import { fileURLToPath } from "url";
302
+ function tweakImports(source) {
303
+ const importRegex = /import \{([^}]*)\} from "drizzle-orm\/pg-core";?/;
304
+ const match = source.match(importRegex);
305
+ if (!match) {
306
+ return source;
307
+ }
308
+ const identifiers = match[1].split(",").map((id) => id.trim()).filter(Boolean).filter((id) => id !== "pgSchema" && id !== "customType");
309
+ const filteredIdentifiers = identifiers.filter((id) => {
310
+ if (id === "timestamp") {
311
+ const timestampUsageRegex = /timestamp\s*\(/;
312
+ return timestampUsageRegex.test(source);
313
+ }
314
+ return true;
315
+ });
316
+ if (source.includes("pgTable(") && !filteredIdentifiers.includes("pgTable")) {
317
+ filteredIdentifiers.push("pgTable");
318
+ }
319
+ if (source.includes("pgView(") && !filteredIdentifiers.includes("pgView")) {
320
+ filteredIdentifiers.push("pgView");
321
+ }
322
+ if (source.includes("pgMaterializedView(") && !filteredIdentifiers.includes("pgMaterializedView")) {
323
+ filteredIdentifiers.push("pgMaterializedView");
324
+ }
325
+ if (source.includes("pgEnum(") && !filteredIdentifiers.includes("pgEnum")) {
326
+ filteredIdentifiers.push("pgEnum");
327
+ }
328
+ if (source.includes("pgSequence(") && !filteredIdentifiers.includes("pgSequence")) {
329
+ filteredIdentifiers.push("pgSequence");
330
+ }
331
+ const unique = Array.from(new Set(filteredIdentifiers));
332
+ const replacement = `import { ${unique.join(", ")} } from "drizzle-orm/pg-core"`;
333
+ return source.replace(importRegex, replacement);
334
+ }
335
+ function inlineCustomTypes(source) {
336
+ const text = source.replace(/import \{[^}]*\} from ["']\.\/types["'];?\n*/g, "");
337
+ const templatePath = resolveTemplateTypesPath();
338
+ if (!templatePath) {
339
+ console.warn("[postprocess-drizzle-schema] Template types file not found.");
340
+ return text;
341
+ }
342
+ return inlineFromTemplateContent(text, fs.readFileSync(templatePath, "utf8"));
343
+ }
344
+ function inlineFromTemplateContent(text, templateContent) {
345
+ const typeDefinitions = templateContent.replace(/^import\s+.*;\r?\n*/gm, "").trim();
346
+ const needsSql = typeDefinitions.includes("sql`") && !text.includes("from 'drizzle-orm'") && !text.includes('from "drizzle-orm"');
347
+ const needsCustomType = typeDefinitions.includes("customType<") && !text.includes("customType");
348
+ if (needsCustomType) {
349
+ text = ensureImportIdentifier(text, "drizzle-orm/pg-core", "customType");
350
+ }
351
+ if (needsSql && !text.includes("from 'drizzle-orm'") && !text.includes('from "drizzle-orm"')) {
352
+ const importMatch = text.match(/^import [\s\S]*?from ["']drizzle-orm\/pg-core["'];?\n/m);
353
+ if (importMatch) {
354
+ const insertPoint = text.indexOf(importMatch[0]) + importMatch[0].length;
355
+ text = text.slice(0, insertPoint) + "import { sql } from 'drizzle-orm';\n" + text.slice(insertPoint);
356
+ }
357
+ }
358
+ const headerPrefix = `${HEADER_COMMENT}
359
+ `;
360
+ let insertionPoint = 0;
361
+ if (text.startsWith(headerPrefix)) {
362
+ insertionPoint = headerPrefix.length;
363
+ }
364
+ const importSectionMatch = text.slice(insertionPoint).match(/^(?:import [^\n]+\n)+/);
365
+ if (importSectionMatch) {
366
+ insertionPoint += importSectionMatch[0].length;
367
+ }
368
+ const typeBlock = `
369
+ ${typeDefinitions}
370
+
371
+ `;
372
+ return text.slice(0, insertionPoint) + typeBlock + text.slice(insertionPoint);
373
+ }
374
+ function ensureImportIdentifier(source, packageName, identifier) {
375
+ const escapedPackage = packageName.replace(/\//g, "\\/");
376
+ const importRegex = new RegExp(`import \\{([^}]*)\\} from ["']${escapedPackage}["'];?`);
377
+ const match = source.match(importRegex);
378
+ if (!match) {
379
+ return source;
380
+ }
381
+ const identifiers = match[1].split(",").map((id) => id.trim()).filter(Boolean);
382
+ if (identifiers.includes(identifier)) {
383
+ return source;
384
+ }
385
+ identifiers.push(identifier);
386
+ const unique = Array.from(new Set(identifiers));
387
+ const replacement = `import { ${unique.join(", ")} } from "${packageName}"`;
388
+ return source.replace(importRegex, replacement);
389
+ }
390
+ function resolveTemplateTypesPath() {
391
+ const candidates = [
392
+ new URL("../template/types.ts", import.meta.url),
393
+ new URL("./gen-dbschema-template/types.ts", import.meta.url)
394
+ ];
395
+ for (const url of candidates) {
396
+ const p = fileURLToPath(url);
397
+ if (fs.existsSync(p)) {
398
+ return p;
399
+ }
400
+ }
401
+ return void 0;
402
+ }
403
+
404
+ // src/commands/db/gen-dbschema/helper/system-fields.ts
405
+ function addSystemFieldComments(source) {
406
+ const commentMap = {
407
+ "_created_at": "Creation time",
408
+ "_created_by": "Creator",
409
+ "_updated_at": "Update time",
410
+ "_updated_by": "Updater"
411
+ };
412
+ const lines = source.split("\n");
413
+ for (let i = 0; i < lines.length; i += 1) {
414
+ const line = lines[i];
415
+ const entry = Object.entries(commentMap).find(([key]) => line.includes(`"${key}"`));
416
+ if (!entry) {
417
+ continue;
418
+ }
419
+ const [, description] = entry;
420
+ const previousLine = lines[i - 1]?.trim() ?? "";
421
+ if (previousLine.startsWith("//") && previousLine.includes("System field")) {
422
+ continue;
423
+ }
424
+ const indentMatch = line.match(/^\s*/);
425
+ const indent = indentMatch ? indentMatch[0] : "";
426
+ const comment = `${indent}// System field: ${description} (auto-filled, do not modify)`;
427
+ lines.splice(i, 0, comment);
428
+ i += 1;
429
+ }
430
+ return lines.join("\n");
431
+ }
432
+ function removeConflictingSystemFields(source) {
433
+ const systemFieldMap = {
434
+ "_created_at": "created_at",
435
+ "_created_by": "created_by",
436
+ "_updated_at": "updated_at",
437
+ "_updated_by": "updated_by"
438
+ };
439
+ const lines = source.split("\n");
440
+ const result = [];
441
+ let inTable = false;
442
+ let tableStartLine = -1;
443
+ const tableBusinessFields = /* @__PURE__ */ new Set();
444
+ let bracketDepth = 0;
445
+ for (let i = 0; i < lines.length; i += 1) {
446
+ const line = lines[i];
447
+ if (!inTable && /=\s*(pgTable|pgView|pgMaterializedView)\s*\(/.test(line)) {
448
+ inTable = true;
449
+ tableStartLine = result.length;
450
+ tableBusinessFields.clear();
451
+ bracketDepth = 0;
452
+ }
453
+ if (inTable) {
454
+ for (const char of line) {
455
+ if (char === "{") bracketDepth++;
456
+ if (char === "}") bracketDepth--;
457
+ }
458
+ for (const businessField of Object.values(systemFieldMap)) {
459
+ if (line.includes(`"${businessField}"`) || line.includes(`'${businessField}'`)) {
460
+ tableBusinessFields.add(businessField);
461
+ }
462
+ }
463
+ if (bracketDepth === 0 && line.includes(");")) {
464
+ inTable = false;
465
+ const tableEndLine = result.length;
466
+ for (let j = tableStartLine; j <= tableEndLine; j++) {
467
+ const tableLine = result[j] || "";
468
+ let shouldRemove = false;
469
+ for (const [systemField, businessField] of Object.entries(systemFieldMap)) {
470
+ if (tableBusinessFields.has(businessField)) {
471
+ if (tableLine.includes(`"${systemField}"`) || tableLine.includes(`'${systemField}'`)) {
472
+ shouldRemove = true;
473
+ if (j > 0 && result[j - 1]?.includes("// System field:")) {
474
+ result[j - 1] = null;
475
+ }
476
+ break;
477
+ }
478
+ }
479
+ }
480
+ if (shouldRemove) {
481
+ result[j] = null;
482
+ }
483
+ }
484
+ }
485
+ }
486
+ result.push(line);
487
+ }
488
+ return result.filter((line) => line !== null).join("\n");
489
+ }
490
+
491
+ // src/commands/db/gen-dbschema/helper/patch-helper.ts
492
+ function patchDrizzleKitDefects(source) {
493
+ let fixed = 0;
494
+ const text = source.replace(/\.default\('\)/g, () => {
495
+ fixed += 1;
496
+ return `.default('')`;
497
+ });
498
+ return { text, fixed };
499
+ }
500
+
501
+ // src/commands/db/gen-dbschema/helper/timestamp-replacement.ts
502
+ function replaceTimestampWithCustomTypes(source) {
503
+ let replaced = 0;
504
+ const pattern = /timestamp\((['"])(.*?)\1,\s*(\{[^}]*\})\)/g;
505
+ const text = source.replace(pattern, (match, quote, fieldName, options) => {
506
+ const hasWithTimezone = /withTimezone:\s*true/.test(options);
507
+ const hasModeString = /mode:\s*['"]string['"]/.test(options);
508
+ if (hasWithTimezone && hasModeString) {
509
+ replaced += 1;
510
+ return `customTimestamptz(${quote}${fieldName}${quote})`;
511
+ }
512
+ return match;
513
+ });
514
+ return { text, replaced };
515
+ }
516
+ function replaceDefaultNowWithSql(source) {
517
+ let replaced = 0;
518
+ const pattern = /\.defaultNow\(\)/g;
519
+ const text = source.replace(pattern, () => {
520
+ replaced += 1;
521
+ return ".default(sql`CURRENT_TIMESTAMP`)";
522
+ });
523
+ return { text, replaced };
524
+ }
525
+
526
+ // src/commands/db/gen-dbschema/helper/appendTableAliases.ts
527
+ var TABLE_ALIAS_MARKER = "// table aliases";
528
+ function appendTableAliases(source) {
529
+ const markerIndex = source.indexOf(`
530
+ ${TABLE_ALIAS_MARKER}`);
531
+ const base = markerIndex === -1 ? source : source.slice(0, markerIndex);
532
+ const exportRegex = /export const\s+([A-Za-z_$][\w$]*)\s*=\s*pgTable\s*\(/g;
533
+ const tableExports = /* @__PURE__ */ new Set();
534
+ for (const match of base.matchAll(exportRegex)) {
535
+ const name = match[1];
536
+ tableExports.add(name);
537
+ }
538
+ if (tableExports.size === 0) {
539
+ return base;
540
+ }
541
+ const aliasLines = Array.from(tableExports).sort().map((name) => `export const ${name}Table = ${name};`).join("\n");
542
+ const prefix = base.trimEnd();
543
+ return `${prefix}
544
+
545
+ ${TABLE_ALIAS_MARKER}
546
+ ${aliasLines}
547
+ `;
548
+ }
549
+
550
+ // src/commands/db/gen-dbschema/postprocess.ts
551
+ function postprocessDrizzleSchema(targetPath) {
552
+ const resolvedPath = path.resolve(targetPath);
553
+ if (!fs2.existsSync(resolvedPath)) {
554
+ console.warn(`[postprocess-drizzle-schema] File not found: ${resolvedPath}`);
555
+ return void 0;
556
+ }
557
+ let text = fs2.readFileSync(resolvedPath, "utf8");
558
+ text = ensureHeaderComment(text);
559
+ const patchResult = patchDrizzleKitDefects(text);
560
+ text = patchResult.text;
561
+ text = removePgSchemaDeclarations(text);
562
+ const tableConversion = convertSchemaTableInvocations(text);
563
+ text = tableConversion.text;
564
+ const renameResult = renamePgTableConstants(text);
565
+ text = renameResult.text;
566
+ text = updateTableReferenceIdentifiers(text, renameResult.renames);
567
+ const replacement = replaceUnknownColumns(text);
568
+ text = replacement.text;
569
+ const timestampReplacement = replaceTimestampWithCustomTypes(text);
570
+ text = timestampReplacement.text;
571
+ const defaultNowReplacement = replaceDefaultNowWithSql(text);
572
+ text = defaultNowReplacement.text;
573
+ text = removeConflictingSystemFields(text);
574
+ text = addSystemFieldComments(text);
575
+ text = tweakImports(text);
576
+ text = inlineCustomTypes(text);
577
+ text = appendTableAliases(text);
578
+ text = text.replace(/\r?\n/g, "\n");
579
+ text = collapseExtraBlankLines(text);
580
+ fs2.writeFileSync(resolvedPath, text, "utf8");
581
+ if (patchResult.fixed > 0) {
582
+ console.info(`[postprocess-drizzle-schema] Patched ${patchResult.fixed} drizzle-kit defects (.default(') -> .default(''))`);
583
+ }
584
+ if (replacement.replaced > 0) {
585
+ console.info(`[postprocess-drizzle-schema] Replaced ${replacement.replaced} unknown columns`);
586
+ }
587
+ if (replacement.unmatched.length > 0) {
588
+ console.warn("[postprocess-drizzle-schema] Unmatched custom types:", replacement.unmatched.length);
589
+ replacement.unmatched.forEach((line) => console.warn(` ${line}`));
590
+ }
591
+ if (tableConversion.converted > 0) {
592
+ console.info(`[postprocess-drizzle-schema] Converted ${tableConversion.converted} schema.table invocations to pgTable`);
593
+ }
594
+ if (timestampReplacement.replaced > 0) {
595
+ console.info(`[postprocess-drizzle-schema] Replaced ${timestampReplacement.replaced} timestamp fields with customTimestamptz`);
596
+ }
597
+ if (defaultNowReplacement.replaced > 0) {
598
+ console.info(`[postprocess-drizzle-schema] Replaced ${defaultNowReplacement.replaced} .defaultNow() with .default(sql\`CURRENT_TIMESTAMP\`)`);
599
+ }
600
+ return {
601
+ replacedUnknown: replacement.replaced,
602
+ unmatchedUnknown: replacement.unmatched,
603
+ patchedDefects: patchResult.fixed,
604
+ replacedTimestamps: timestampReplacement.replaced,
605
+ replacedDefaultNow: defaultNowReplacement.replaced
606
+ };
607
+ }
608
+
609
+ // src/commands/db/gen-nest-resource/generator.ts
610
+ import { pluralize } from "inflection";
611
+
612
+ // src/commands/db/gen-nest-resource/utils.ts
613
+ function mapDrizzleTypeToTS(field) {
614
+ const typeMap = {
615
+ // String types
616
+ char: "string",
617
+ varchar: "string",
618
+ text: "string",
619
+ // Numeric types
620
+ smallint: "number",
621
+ integer: "number",
622
+ int: "number",
623
+ bigint: "string",
624
+ // bigint 在 JS 中通常作为 string 处理
625
+ serial: "number",
626
+ smallserial: "number",
627
+ bigserial: "string",
628
+ // Decimal types
629
+ decimal: "string",
630
+ // 精确数值通常用 string
631
+ numeric: "string",
632
+ real: "number",
633
+ doublePrecision: "number",
634
+ // Boolean
635
+ boolean: "boolean",
636
+ // Date/Time types
637
+ timestamp: "Date",
638
+ timestamptz: "Date",
639
+ date: "Date",
640
+ time: "string",
641
+ timetz: "string",
642
+ interval: "string",
643
+ // UUID
644
+ uuid: "string",
645
+ // JSON types
646
+ json: "any",
647
+ jsonb: "any",
648
+ // Binary
649
+ bytea: "Buffer",
650
+ // Network types
651
+ inet: "string",
652
+ cidr: "string",
653
+ macaddr: "string",
654
+ macaddr8: "string",
655
+ // Geometric types
656
+ point: "{ x: number; y: number }",
657
+ line: "string",
658
+ lseg: "string",
659
+ box: "string",
660
+ path: "string",
661
+ polygon: "string",
662
+ circle: "string",
663
+ // Array types (handled by isArray flag)
664
+ array: "any[]",
665
+ // Custom types
666
+ customType: "any",
667
+ customTimestamptz: "Date",
668
+ userProfile: "string",
669
+ fileAttachment: "FileAttachment",
670
+ // Enum (handled separately)
671
+ pgEnum: "string"
672
+ };
673
+ let baseType = typeMap[field.type] || "any";
674
+ if (field.isArray) {
675
+ baseType = baseType.endsWith("[]") ? baseType : `${baseType}[]`;
676
+ }
677
+ if (field.enumValues && field.enumValues.length > 0) {
678
+ baseType = field.enumValues.map((v) => `'${v}'`).join(" | ");
679
+ }
680
+ return baseType;
681
+ }
682
+ function toPascalCase(str) {
683
+ return str.replace(/([a-z])([A-Z])/g, "$1 $2").split(/[-_\s]/).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
684
+ }
685
+ function toKebabCase(str) {
686
+ return str.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase().replace(/[_\s]/g, "-");
687
+ }
688
+ function toSnakeCase(str) {
689
+ return str.replace(/([a-z])([A-Z])/g, "$1_$2").toLowerCase().replace(/[-\s]/g, "_");
690
+ }
691
+
692
+ // src/commands/db/gen-nest-resource/generator.ts
693
+ function generateDTO(table) {
694
+ const className = toPascalCase(table.variableName);
695
+ let dto = `// \u8BF7\u4FEE\u6539\u8BE5\u6587\u4EF6\u4EE3\u7801\u4EE5\u6EE1\u8DB3\u9700\u6C42
696
+ import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
697
+ import { IsDefined, IsNumber, IsOptional, IsString, MaxLength, IsInt, IsBoolean, IsUUID, IsDate, IsObject, IsArray } from 'class-validator';
698
+ import { Type } from 'class-transformer';
699
+ import { FileAttachment } from '../../../database/schema';
700
+
701
+ `;
702
+ dto += `export class Create${className}Dto {
703
+ `;
704
+ for (const field of table.fields) {
705
+ if (field.isPrimaryKey || field.name === "id" || field.name.startsWith("_") || field.name.startsWith("created") || field.name.startsWith("updated")) {
706
+ continue;
707
+ }
708
+ const tsType = mapDrizzleTypeToTS(field);
709
+ const optional = field.nullable || field.hasDefault ? "?" : "";
710
+ const decorators = generateValidationDecorators(field);
711
+ if (decorators) {
712
+ dto += decorators;
713
+ }
714
+ dto += ` ${field.name}${optional}: ${tsType};
715
+
716
+ `;
717
+ }
718
+ dto += "}\n\n";
719
+ dto += `export class Update${className}Dto {
720
+ `;
721
+ for (const field of table.fields) {
722
+ if (field.name.startsWith("_") || field.name.startsWith("created") || field.name.startsWith("updated") || field.isPrimaryKey || field.name === "id") {
723
+ continue;
724
+ }
725
+ const tsType = mapDrizzleTypeToTS(field);
726
+ const decorators = generateValidationDecorators(field, {
727
+ isUpdate: true
728
+ });
729
+ if (decorators) {
730
+ dto += decorators;
731
+ }
732
+ dto += ` ${field.name}?: ${tsType};
733
+
734
+ `;
735
+ }
736
+ dto += "}\n\n";
737
+ dto += `export class ${className}ResponseDto {
738
+ `;
739
+ for (const field of table.fields) {
740
+ const tsType = mapDrizzleTypeToTS(field);
741
+ const optional = field.nullable ? "?" : "";
742
+ const decorators = generateValidationDecorators(field, {
743
+ isResponse: true
744
+ });
745
+ if (decorators) {
746
+ dto += decorators;
747
+ }
748
+ dto += ` ${field.name}${optional}: ${tsType};
749
+
750
+ `;
751
+ }
752
+ dto += "}\n";
753
+ return dto;
754
+ }
755
+ function generateValidationDecorators(field, {
756
+ isUpdate = false,
757
+ isResponse = false
758
+ } = {}) {
759
+ let decorators = " // \u8BF7\u6309\u7528\u6237\u9700\u6C42\u4FEE\u6539\u4EE5\u4E0B\u88C5\u9970\u5668\u6CE8\u91CA\n";
760
+ if (field.nullable || !isResponse && field.hasDefault || isUpdate) {
761
+ decorators += ` @ApiPropertyOptional({ description: '${field.comment || field.name}' })
762
+ `;
763
+ if (isResponse) {
764
+ return decorators;
765
+ }
766
+ decorators += " @IsOptional()\n";
767
+ } else {
768
+ decorators += ` @ApiProperty({ description: '${field.comment || field.name}' })
769
+ `;
770
+ if (isResponse) {
771
+ return decorators;
772
+ }
773
+ decorators += " @IsDefined()\n";
774
+ }
775
+ switch (field.type) {
776
+ case "varchar":
777
+ case "char":
778
+ case "text":
779
+ decorators += " @IsString()\n";
780
+ if (field.length) {
781
+ decorators += ` @MaxLength(${field.length})
782
+ `;
783
+ }
784
+ break;
785
+ case "integer":
786
+ case "smallint":
787
+ case "serial":
788
+ case "smallserial":
789
+ decorators += " @IsInt()\n";
790
+ break;
791
+ case "decimal":
792
+ case "numeric":
793
+ case "real":
794
+ case "doublePrecision":
795
+ decorators += " @IsNumber()\n";
796
+ break;
797
+ case "boolean":
798
+ decorators += " @IsBoolean()\n";
799
+ break;
800
+ case "uuid":
801
+ decorators += " @IsUUID()\n";
802
+ break;
803
+ case "timestamp":
804
+ case "timestamptz":
805
+ case "date":
806
+ case "customTimestamptz":
807
+ decorators += " @IsDate()\n";
808
+ break;
809
+ case "json":
810
+ case "jsonb":
811
+ decorators += " @IsObject()\n";
812
+ break;
813
+ }
814
+ if (field.isArray) {
815
+ decorators += " @IsArray()\n";
816
+ }
817
+ return decorators;
818
+ }
819
+ function generateController(table) {
820
+ const className = toPascalCase(table.variableName);
821
+ const routePath = toKebabCase(pluralize(table.variableName));
822
+ const filePath = toSnakeCase(table.variableName);
823
+ const pkField = table.fields.find((f) => f.isPrimaryKey);
824
+ const pkType = pkField ? mapDrizzleTypeToTS(pkField) : "string";
825
+ const pkName = pkField ? pkField.name : "id";
826
+ const controller = `
827
+ // \u8BF7\u4FEE\u6539\u8BE5\u6587\u4EF6\u4EE3\u7801\u4EE5\u6EE1\u8DB3\u9700\u6C42
828
+ import {
829
+ Controller,
830
+ Get,
831
+ Post,
832
+ Put,
833
+ Delete,
834
+ Body,
835
+ Param,
836
+ Query,
837
+ } from '@nestjs/common';
838
+ import {
839
+ ApiTags,
840
+ ApiOperation,
841
+ ApiOkResponse,
842
+ ApiCreatedResponse,
843
+ } from '@nestjs/swagger';
844
+ import {
845
+ Create${className}Dto,
846
+ Update${className}Dto,
847
+ ${className}ResponseDto
848
+ } from './dtos/${filePath}.dto';
849
+ import { ${className}Service } from './${filePath}.service';
850
+
851
+ @ApiTags('${toPascalCase(table.variableName)}')
852
+ @Controller('api/${routePath}')
853
+ export class ${className}Controller {
854
+ constructor(private readonly ${table.variableName}Service: ${className}Service) {}
855
+
856
+ @Post()
857
+ @ApiOperation({
858
+ summary: '\u521B\u5EFA\u4E00\u6761\u8BB0\u5F55\uFF08\u6A21\u677F\u5185\u5BB9\uFF0C\u8BF7\u4FEE\u6539\u6211\uFF09',
859
+ description: '\u521B\u5EFA\u4E00\u6761\u8BB0\u5F55\uFF08\u6A21\u677F\u5185\u5BB9\uFF0C\u8BF7\u4FEE\u6539\u6211\uFF09',
860
+ })
861
+ @ApiCreatedResponse({
862
+ description: '\u6210\u529F\u521B\u5EFA\u4E00\u6761\u8BB0\u5F55',
863
+ type: ${className}ResponseDto,
864
+ })
865
+ async create(
866
+ @Body() createDto: Create${className}Dto
867
+ ): Promise<${className}ResponseDto> {
868
+ return this.${table.variableName}Service.create(createDto);
869
+ }
870
+
871
+ @ApiOperation({
872
+ summary: '\u6839\u636E\u4E3B\u952E\u67E5\u8BE2\u4E00\u6761\u8BB0\u5F55\uFF08\u6A21\u677F\u5185\u5BB9\uFF0C\u8BF7\u4FEE\u6539\u6211\uFF09',
873
+ description: '\u6839\u636E\u4E3B\u952E\u67E5\u8BE2\u4E00\u6761\u8BB0\u5F55\uFF08\u6A21\u677F\u5185\u5BB9\uFF0C\u8BF7\u4FEE\u6539\u6211\uFF09',
874
+ })
875
+ @ApiOkResponse({
876
+ description: '\u6210\u529F\u67E5\u8BE2\u4E00\u6761\u8BB0\u5F55',
877
+ type: ${className}ResponseDto,
878
+ })
879
+ @Get(':${pkName}')
880
+ async findOne(
881
+ @Param('${pkName}') ${pkName}: ${pkType}
882
+ ): Promise<${className}ResponseDto> {
883
+ return this.${table.variableName}Service.findOne(${pkName});
884
+ }
885
+
886
+ @ApiOperation({
887
+ summary: '\u6839\u636E\u4E3B\u952E\u66F4\u65B0\u4E00\u6761\u8BB0\u5F55\uFF08\u6A21\u677F\u5185\u5BB9\uFF0C\u8BF7\u4FEE\u6539\u6211\uFF09',
888
+ description: '\u6839\u636E\u4E3B\u952E\u66F4\u65B0\u4E00\u6761\u8BB0\u5F55\uFF08\u6A21\u677F\u5185\u5BB9\uFF0C\u8BF7\u4FEE\u6539\u6211\uFF09',
889
+ })
890
+ @ApiOkResponse({
891
+ description: '\u6210\u529F\u66F4\u65B0\u4E00\u6761\u8BB0\u5F55',
892
+ type: ${className}ResponseDto,
893
+ })
894
+ @Put(':${pkName}')
895
+ async update(
896
+ @Param('${pkName}') ${pkName}: ${pkType},
897
+ @Body() updateDto: Update${className}Dto
898
+ ): Promise<${className}ResponseDto> {
899
+ return this.${table.variableName}Service.update(${pkName}, updateDto);
900
+ }
901
+
902
+ @ApiOperation({
903
+ summary: '\u6839\u636E\u4E3B\u952E\u5220\u9664\u4E00\u6761\u8BB0\u5F55\uFF08\u6A21\u677F\u5185\u5BB9\uFF0C\u8BF7\u4FEE\u6539\u6211\uFF09',
904
+ description: '\u6839\u636E\u4E3B\u952E\u5220\u9664\u4E00\u6761\u8BB0\u5F55\uFF08\u6A21\u677F\u5185\u5BB9\uFF0C\u8BF7\u4FEE\u6539\u6211\uFF09',
905
+ })
906
+ @ApiOkResponse({
907
+ description: '\u6210\u529F\u5220\u9664\u4E00\u6761\u8BB0\u5F55',
908
+ })
909
+ @Delete(':${pkName}')
910
+ async remove(
911
+ @Param('${pkName}') ${pkName}: ${pkType}
912
+ ): Promise<void> {
913
+ return this.${table.variableName}Service.remove(${pkName});
914
+ }
915
+ }
916
+ `;
917
+ return controller;
918
+ }
919
+ function generateService(table) {
920
+ const className = toPascalCase(table.variableName);
921
+ const filePath = toSnakeCase(table.variableName);
922
+ const pkField = table.fields.find((f) => f.isPrimaryKey);
923
+ const pkType = pkField ? mapDrizzleTypeToTS(pkField) : "string";
924
+ const pkName = pkField ? pkField.name : "id";
925
+ const service = `
926
+ // \u8BF7\u4FEE\u6539\u8BE5\u6587\u4EF6\u4EE3\u7801\u4EE5\u6EE1\u8DB3\u9700\u6C42
927
+ import { Injectable, Inject, Logger, NotFoundException } from '@nestjs/common';
928
+ import { eq } from 'drizzle-orm';
929
+ import { DRIZZLE_DATABASE, type PostgresJsDatabase } from '@lark-apaas/fullstack-nestjs-core';
930
+ import { ${table.variableName} } from '../../database/schema';
931
+ import {
932
+ Create${className}Dto,
933
+ Update${className}Dto,
934
+ ${className}ResponseDto
935
+ } from './dtos/${filePath}.dto';
936
+
937
+ @Injectable()
938
+ export class ${className}Service {
939
+ private readonly logger = new Logger(${className}Service.name);
940
+
941
+ constructor(@Inject(DRIZZLE_DATABASE) private readonly db: PostgresJsDatabase) {}
942
+
943
+ async create(createDto: Create${className}Dto): Promise<${className}ResponseDto> {
944
+ const [result] = await this.db
945
+ .insert(${table.variableName})
946
+ .values(createDto)
947
+ .returning();
948
+
949
+ this.logger.log(\`Created ${className} with ${pkName} \${result.${pkName}}\`);
950
+
951
+ return result;
952
+ }
953
+
954
+ async findAll(options?: { page?: number; limit?: number }): Promise<${className}ResponseDto[]> {
955
+ const { page = 1, limit = 10 } = options || {};
956
+ const offset = (page - 1) * limit;
957
+
958
+ return this.db
959
+ .select()
960
+ .from(${table.variableName})
961
+ .limit(limit)
962
+ .offset(offset);
963
+ }
964
+
965
+ async findOne(${pkName}: ${pkType}): Promise<${className}ResponseDto> {
966
+ const [result] = await this.db
967
+ .select()
968
+ .from(${table.variableName})
969
+ .where(eq(${table.variableName}.${pkName}, ${pkName}))
970
+ .limit(1);
971
+
972
+ if (!result) {
973
+ throw new NotFoundException(\`${className} with ${pkName} \${${pkName}} not found\`);
974
+ }
975
+
976
+ return result;
977
+ }
978
+
979
+ async update(${pkName}: ${pkType}, updateDto: Update${className}Dto): Promise<${className}ResponseDto> {
980
+ const [result] = await this.db
981
+ .update(${table.variableName})
982
+ .set(updateDto)
983
+ .where(eq(${table.variableName}.${pkName}, ${pkName}))
984
+ .returning();
985
+
986
+ if (!result) {
987
+ throw new NotFoundException(\`${className} with ${pkName} \${${pkName}} not found\`);
988
+ }
989
+
990
+ return result;
991
+ }
992
+
993
+ async remove(${pkName}: ${pkType}): Promise<void> {
994
+ const result = await this.db
995
+ .delete(${table.variableName})
996
+ .where(eq(${table.variableName}.${pkName}, ${pkName}))
997
+ .returning();
998
+
999
+ if (result.length === 0) {
1000
+ throw new NotFoundException(\`${className} with ${pkName} \${${pkName}} not found\`);
1001
+ }
1002
+
1003
+ this.logger.log(\`Deleted ${className} with ${pkName} \${${pkName}}\`);
1004
+ }
1005
+ }
1006
+ `;
1007
+ return service;
1008
+ }
1009
+ function generateModule(table) {
1010
+ const className = toPascalCase(table.variableName);
1011
+ const filePath = toSnakeCase(table.variableName);
1012
+ const module = `
1013
+ import { Module } from '@nestjs/common';
1014
+ import { ${className}Controller } from './${filePath}.controller';
1015
+ import { ${className}Service } from './${filePath}.service';
1016
+
1017
+ @Module({
1018
+ controllers: [${className}Controller],
1019
+ providers: [${className}Service],
1020
+ })
1021
+ export class ${className}Module {}
1022
+ `;
1023
+ return module;
1024
+ }
1025
+
1026
+ // src/commands/db/gen-nest-resource/schema-parser.ts
1027
+ import { Project, Node } from "ts-morph";
1028
+ var DrizzleSchemaParser = class {
1029
+ constructor(projectOptions) {
1030
+ this.project = new Project(projectOptions);
1031
+ }
1032
+ parseSchemaFile(filePath) {
1033
+ const sourceFile = this.project.addSourceFileAtPath(filePath);
1034
+ const tables = [];
1035
+ const variableStatements = sourceFile.getVariableStatements();
1036
+ for (const statement of variableStatements) {
1037
+ const declarations = statement.getDeclarations();
1038
+ for (const declaration of declarations) {
1039
+ const initializer = declaration.getInitializer();
1040
+ if (initializer && Node.isCallExpression(initializer)) {
1041
+ const expression = initializer.getExpression();
1042
+ if (expression.getText() === "pgTable") {
1043
+ const tableInfo = this.parsePgTable(
1044
+ declaration.getName(),
1045
+ initializer
1046
+ );
1047
+ if (tableInfo) {
1048
+ tables.push(tableInfo);
1049
+ }
1050
+ }
1051
+ }
1052
+ }
1053
+ }
1054
+ return tables;
1055
+ }
1056
+ parsePgTable(variableName, callExpr) {
1057
+ const args = callExpr.getArguments();
1058
+ if (args.length < 2) {
1059
+ return null;
1060
+ }
1061
+ const tableName = args[0].getText().replace(/['"]/g, "");
1062
+ const fieldsArg = args[1];
1063
+ if (!Node.isObjectLiteralExpression(fieldsArg)) {
1064
+ return null;
1065
+ }
1066
+ const fields = [];
1067
+ const properties = fieldsArg.getProperties();
1068
+ for (const prop of properties) {
1069
+ if (Node.isPropertyAssignment(prop)) {
1070
+ const fieldName = prop.getName();
1071
+ const initializer = prop.getInitializer();
1072
+ const leadingComments = prop.getLeadingCommentRanges();
1073
+ let comment;
1074
+ if (leadingComments.length > 0) {
1075
+ comment = leadingComments.map((c) => c.getText()).join("\n").replace(/\/\//g, "").trim();
1076
+ }
1077
+ if (initializer && Node.isCallExpression(initializer)) {
1078
+ const fieldInfo = this.parseField(fieldName, initializer, comment);
1079
+ fields.push(fieldInfo);
1080
+ }
1081
+ }
1082
+ }
1083
+ return {
1084
+ tableName,
1085
+ variableName,
1086
+ fields
1087
+ };
1088
+ }
1089
+ parseField(fieldName, callExpr, comment) {
1090
+ const fieldInfo = {
1091
+ name: fieldName,
1092
+ columnName: fieldName,
1093
+ type: "",
1094
+ nullable: true,
1095
+ hasDefault: false,
1096
+ notNull: false,
1097
+ isPrimaryKey: false,
1098
+ isUnique: false,
1099
+ isArray: false,
1100
+ comment
1101
+ };
1102
+ this.parseBaseType(callExpr, fieldInfo);
1103
+ this.parseCallChain(callExpr, fieldInfo);
1104
+ return fieldInfo;
1105
+ }
1106
+ parseBaseType(callExpr, fieldInfo) {
1107
+ let current = callExpr;
1108
+ let baseCall = null;
1109
+ while (Node.isCallExpression(current)) {
1110
+ baseCall = current;
1111
+ const expression2 = current.getExpression();
1112
+ if (Node.isPropertyAccessExpression(expression2)) {
1113
+ current = expression2.getExpression();
1114
+ } else {
1115
+ break;
1116
+ }
1117
+ }
1118
+ if (!baseCall) {
1119
+ return;
1120
+ }
1121
+ const expression = baseCall.getExpression();
1122
+ let typeName = "";
1123
+ if (Node.isPropertyAccessExpression(expression)) {
1124
+ typeName = expression.getName();
1125
+ } else {
1126
+ typeName = expression.getText();
1127
+ }
1128
+ fieldInfo.type = typeName;
1129
+ const args = baseCall.getArguments();
1130
+ if (args.length > 0) {
1131
+ const firstArg = args[0];
1132
+ if (Node.isStringLiteral(firstArg)) {
1133
+ fieldInfo.columnName = firstArg.getLiteralText();
1134
+ } else if (Node.isObjectLiteralExpression(firstArg)) {
1135
+ this.parseTypeConfig(firstArg, fieldInfo);
1136
+ } else if (Node.isArrayLiteralExpression(firstArg)) {
1137
+ fieldInfo.enumValues = firstArg.getElements().map((el) => el.getText().replace(/['"]/g, ""));
1138
+ }
1139
+ }
1140
+ if (args.length > 1 && Node.isObjectLiteralExpression(args[1])) {
1141
+ this.parseTypeConfig(args[1], fieldInfo);
1142
+ }
1143
+ }
1144
+ parseTypeConfig(objLiteral, fieldInfo) {
1145
+ if (!Node.isObjectLiteralExpression(objLiteral)) {
1146
+ return;
1147
+ }
1148
+ const properties = objLiteral.getProperties();
1149
+ for (const prop of properties) {
1150
+ if (Node.isPropertyAssignment(prop)) {
1151
+ const propName = prop.getName();
1152
+ const value = prop.getInitializer()?.getText();
1153
+ switch (propName) {
1154
+ case "length":
1155
+ fieldInfo.length = value ? parseInt(value) : void 0;
1156
+ break;
1157
+ case "precision":
1158
+ fieldInfo.precision = value ? parseInt(value) : void 0;
1159
+ break;
1160
+ case "scale":
1161
+ fieldInfo.scale = value ? parseInt(value) : void 0;
1162
+ break;
1163
+ case "default":
1164
+ fieldInfo.hasDefault = true;
1165
+ fieldInfo.defaultValue = value;
1166
+ break;
1167
+ // 时间精度(用于 timestamp, time 等)
1168
+ case "withTimezone":
1169
+ fieldInfo.withTimezone = value === "true";
1170
+ break;
1171
+ case "mode":
1172
+ fieldInfo.mode = value?.replace(/['"]/g, "");
1173
+ break;
1174
+ default:
1175
+ throw new Error(`Unsupported property: ${propName}`);
1176
+ }
1177
+ }
1178
+ }
1179
+ }
1180
+ parseCallChain(callExpr, fieldInfo) {
1181
+ let current = callExpr;
1182
+ while (Node.isCallExpression(current)) {
1183
+ const expression = current.getExpression();
1184
+ if (Node.isPropertyAccessExpression(expression)) {
1185
+ const methodName = expression.getName();
1186
+ const args = current.getArguments();
1187
+ switch (methodName) {
1188
+ case "notNull":
1189
+ fieldInfo.notNull = true;
1190
+ fieldInfo.nullable = false;
1191
+ break;
1192
+ case "default":
1193
+ fieldInfo.hasDefault = true;
1194
+ if (args.length > 0) {
1195
+ fieldInfo.defaultValue = args[0].getText();
1196
+ }
1197
+ break;
1198
+ case "defaultRandom":
1199
+ fieldInfo.hasDefault = true;
1200
+ fieldInfo.defaultValue = "random";
1201
+ break;
1202
+ case "primaryKey":
1203
+ fieldInfo.isPrimaryKey = true;
1204
+ fieldInfo.notNull = true;
1205
+ fieldInfo.nullable = false;
1206
+ break;
1207
+ case "unique":
1208
+ fieldInfo.isUnique = true;
1209
+ break;
1210
+ case "array":
1211
+ fieldInfo.isArray = true;
1212
+ break;
1213
+ case "references":
1214
+ if (args.length > 0) {
1215
+ const refArg = args[0].getText();
1216
+ const match = refArg.match(/=>\s*(\w+)\.(\w+)/);
1217
+ if (match) {
1218
+ fieldInfo.references = {
1219
+ table: match[1],
1220
+ column: match[2]
1221
+ };
1222
+ }
1223
+ }
1224
+ break;
1225
+ default:
1226
+ throw new Error(`Unsupported method: ${methodName}`);
1227
+ }
1228
+ current = expression.getExpression();
1229
+ } else {
1230
+ break;
1231
+ }
1232
+ }
1233
+ }
1234
+ };
1235
+
1236
+ // src/commands/db/gen-nest-resource/index.ts
1237
+ import { join } from "path";
1238
+ import { mkdir, rm, writeFile } from "fs/promises";
1239
+ import { existsSync } from "fs";
1240
+ async function parseAndGenerateNestResourceTemplate(options) {
1241
+ const parser = new DrizzleSchemaParser({
1242
+ tsConfigFilePath: options.tsConfigFilePath
1243
+ });
1244
+ const tables = parser.parseSchemaFile(options.schemaFilePath);
1245
+ if (tables.length === 0) {
1246
+ console.warn("\u672A\u89E3\u6790\u5230\u4EFB\u4F55\u6570\u636E\u5E93\u8868\uFF0C\u65E0\u9700\u751F\u6210 Nest.js \u6A21\u5757\u6A21\u677F");
1247
+ return;
1248
+ }
1249
+ tables.sort((a, b) => b.variableName.length - a.variableName.length);
1250
+ const table = tables[0];
1251
+ console.info(`\u751F\u6210 Nest.js ${table.variableName} \u6A21\u5757`);
1252
+ const filePath = toSnakeCase(table.variableName);
1253
+ const moduleDir = join(options.moduleOutputDir, filePath);
1254
+ if (existsSync(moduleDir)) {
1255
+ console.info(`Nest.js \u6A21\u5757 ${filePath} \u5DF2\u5B58\u5728\uFF0C\u8DF3\u8FC7\u751F\u6210\u4EE3\u7801`);
1256
+ return;
1257
+ }
1258
+ const dto = generateDTO(table);
1259
+ const controller = generateController(table);
1260
+ const service = generateService(table);
1261
+ const moduleFilePath = join(moduleDir, `${filePath}.module.ts`);
1262
+ const module = generateModule(table);
1263
+ try {
1264
+ await mkdir(moduleDir, { recursive: true });
1265
+ await mkdir(join(moduleDir, "dtos"), { recursive: true });
1266
+ await writeFile(join(moduleDir, "dtos", `${filePath}.dto.ts`), dto);
1267
+ await writeFile(join(moduleDir, `${filePath}.controller.ts`), controller);
1268
+ await writeFile(join(moduleDir, `${filePath}.service.ts`), service);
1269
+ await writeFile(moduleFilePath, module);
1270
+ } catch (err) {
1271
+ console.error(`\u751F\u6210 Nest.js ${filePath} \u6A21\u5757\u5931\u8D25: ${err.message}`);
1272
+ await rm(moduleDir, { recursive: true });
1273
+ }
1274
+ }
1275
+
1276
+ // src/commands/db/schema.handler.ts
125
1277
  var require2 = createRequire(import.meta.url);
126
1278
  async function run(options = {}) {
127
1279
  let exitCode = 0;
128
- const envPath2 = path.resolve(process.cwd(), ".env");
129
- if (fs.existsSync(envPath2)) {
1280
+ const envPath2 = path2.resolve(process.cwd(), ".env");
1281
+ if (fs3.existsSync(envPath2)) {
130
1282
  loadEnv({ path: envPath2 });
131
1283
  console.log("[gen-db-schema] \u2713 Loaded .env file");
132
1284
  }
@@ -136,25 +1288,56 @@ async function run(options = {}) {
136
1288
  process.exit(1);
137
1289
  }
138
1290
  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);
1291
+ const OUT_DIR = path2.resolve(process.cwd(), "server/database/.introspect");
1292
+ const SCHEMA_FILE = path2.resolve(process.cwd(), outputPath);
141
1293
  console.log("[gen-db-schema] Starting...");
142
- 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)) {
1294
+ const __filename = fileURLToPath2(import.meta.url);
1295
+ const __dirname2 = path2.dirname(__filename);
1296
+ const configPathCandidates = [
1297
+ path2.resolve(__dirname2, "config/drizzle.config.js"),
1298
+ path2.resolve(__dirname2, "../../config/drizzle.config.js"),
1299
+ path2.resolve(__dirname2, "../../../dist/config/drizzle.config.js")
1300
+ ];
1301
+ const configPath = configPathCandidates.find((p) => fs3.existsSync(p));
1302
+ console.log("[gen-db-schema] Using drizzle config from:", configPath ?? "(not found)");
1303
+ if (!configPath) {
146
1304
  console.error("[gen-db-schema] Error: drizzle config not found in CLI package");
147
1305
  process.exit(1);
148
1306
  }
1307
+ const resolveDrizzleKitBin = () => {
1308
+ const entryPath = require2.resolve("drizzle-kit");
1309
+ let currentDir = path2.dirname(entryPath);
1310
+ let lastDir = null;
1311
+ while (currentDir !== lastDir) {
1312
+ const pkgJsonPath = path2.join(currentDir, "package.json");
1313
+ if (fs3.existsSync(pkgJsonPath)) {
1314
+ const pkgJsonRaw = fs3.readFileSync(pkgJsonPath, "utf8");
1315
+ const pkgJson = JSON.parse(pkgJsonRaw);
1316
+ if (pkgJson.name === "drizzle-kit") {
1317
+ const binField = pkgJson.bin;
1318
+ const binRelPath = typeof binField === "string" ? binField : binField?.["drizzle-kit"];
1319
+ if (!binRelPath) {
1320
+ throw new Error("Unable to resolve drizzle-kit binary from package.json");
1321
+ }
1322
+ return path2.resolve(currentDir, binRelPath);
1323
+ }
1324
+ }
1325
+ lastDir = currentDir;
1326
+ currentDir = path2.dirname(currentDir);
1327
+ }
1328
+ throw new Error("Unable to locate drizzle-kit package root");
1329
+ };
149
1330
  try {
150
1331
  const env = {
151
1332
  ...process.env,
152
1333
  __DRIZZLE_OUT_DIR__: OUT_DIR,
153
- __DRIZZLE_SCHEMA_PATH__: SCHEMA_FILE
1334
+ __DRIZZLE_SCHEMA_PATH__: SCHEMA_FILE,
1335
+ DRIZZLE_SCHEMA_FILTER: options.schemaFilter ?? process.env.DRIZZLE_SCHEMA_FILTER,
1336
+ DRIZZLE_TABLES_FILTER: options.tablesFilter ?? process.env.DRIZZLE_TABLES_FILTER
154
1337
  };
155
- const args = process.argv.slice(3).filter((arg) => !arg.startsWith("--enable-nest-module-generate"));
156
- const spawnArgs = ["--yes", "drizzle-kit", "introspect", "--config", configPath, ...args];
157
- const result = spawnSync("npx", spawnArgs, { stdio: "inherit", env });
1338
+ const drizzleKitBin = resolveDrizzleKitBin();
1339
+ const spawnArgs = [drizzleKitBin, "introspect", "--config", configPath];
1340
+ const result = spawnSync(process.execPath, spawnArgs, { stdio: "inherit", env, cwd: process.cwd() });
158
1341
  if (result.error) {
159
1342
  console.error("[gen-db-schema] Execution failed:", result.error);
160
1343
  throw result.error;
@@ -162,29 +1345,27 @@ async function run(options = {}) {
162
1345
  if ((result.status ?? 0) !== 0) {
163
1346
  throw new Error(`drizzle-kit introspect failed with status ${result.status}`);
164
1347
  }
165
- const generatedSchema = path.join(OUT_DIR, "schema.ts");
166
- if (!fs.existsSync(generatedSchema)) {
1348
+ const generatedSchema = path2.join(OUT_DIR, "schema.ts");
1349
+ if (!fs3.existsSync(generatedSchema)) {
167
1350
  console.error("[gen-db-schema] schema.ts not generated");
168
1351
  throw new Error("drizzle-kit introspect failed to generate schema.ts");
169
1352
  }
170
- const { postprocessDrizzleSchema } = require2("@lark-apaas/devtool-kits");
171
1353
  const stats = postprocessDrizzleSchema(generatedSchema);
172
1354
  if (stats?.unmatchedUnknown?.length) {
173
1355
  console.warn("[gen-db-schema] Unmatched custom types detected:", stats.unmatchedUnknown);
174
1356
  }
175
1357
  console.log("[gen-db-schema] \u2713 Postprocessed schema");
176
- fs.mkdirSync(path.dirname(SCHEMA_FILE), { recursive: true });
177
- fs.copyFileSync(generatedSchema, SCHEMA_FILE);
1358
+ fs3.mkdirSync(path2.dirname(SCHEMA_FILE), { recursive: true });
1359
+ fs3.copyFileSync(generatedSchema, SCHEMA_FILE);
178
1360
  console.log(`[gen-db-schema] \u2713 Copied to ${outputPath}`);
179
1361
  try {
180
1362
  if (options.enableNestModuleGenerate) {
181
- const { parseAndGenerateNestResourceTemplate } = require2("@lark-apaas/devtool-kits");
182
- const tsConfigFilePath = path.resolve(process.cwd(), "tsconfig.json");
1363
+ const tsConfigFilePath = path2.resolve(process.cwd(), "tsconfig.json");
183
1364
  const schemaFilePath = SCHEMA_FILE;
184
1365
  await parseAndGenerateNestResourceTemplate({
185
1366
  tsConfigFilePath,
186
1367
  schemaFilePath,
187
- moduleOutputDir: path.resolve(process.cwd(), "server/modules")
1368
+ moduleOutputDir: path2.resolve(process.cwd(), "server/modules")
188
1369
  });
189
1370
  console.log("[gen-db-schema] \u2713 Generate NestJS Module Boilerplate Successfully");
190
1371
  }
@@ -196,8 +1377,8 @@ async function run(options = {}) {
196
1377
  console.error("[gen-db-schema] Failed:", err instanceof Error ? err.message : String(err));
197
1378
  exitCode = 1;
198
1379
  } finally {
199
- if (fs.existsSync(OUT_DIR)) {
200
- fs.rmSync(OUT_DIR, { recursive: true, force: true });
1380
+ if (fs3.existsSync(OUT_DIR)) {
1381
+ fs3.rmSync(OUT_DIR, { recursive: true, force: true });
201
1382
  }
202
1383
  process.exit(exitCode);
203
1384
  }
@@ -215,9 +1396,9 @@ var genDbSchemaCommand = {
215
1396
  };
216
1397
 
217
1398
  // src/commands/sync/run.handler.ts
218
- import path3 from "path";
219
- import fs3 from "fs";
220
- import { fileURLToPath as fileURLToPath2 } from "url";
1399
+ import path4 from "path";
1400
+ import fs5 from "fs";
1401
+ import { fileURLToPath as fileURLToPath3 } from "url";
221
1402
 
222
1403
  // src/config/sync.ts
223
1404
  var syncConfig = {
@@ -280,38 +1461,38 @@ function genSyncConfig(perms = {}) {
280
1461
  }
281
1462
 
282
1463
  // src/utils/file-ops.ts
283
- import fs2 from "fs";
284
- import path2 from "path";
1464
+ import fs4 from "fs";
1465
+ import path3 from "path";
285
1466
  function removeLineFromFile(filePath, pattern) {
286
- if (!fs2.existsSync(filePath)) {
287
- console.log(`[fullstack-cli] \u25CB ${path2.basename(filePath)} (not found)`);
1467
+ if (!fs4.existsSync(filePath)) {
1468
+ console.log(`[fullstack-cli] \u25CB ${path3.basename(filePath)} (not found)`);
288
1469
  return false;
289
1470
  }
290
- const content = fs2.readFileSync(filePath, "utf-8");
1471
+ const content = fs4.readFileSync(filePath, "utf-8");
291
1472
  const lines = content.split("\n");
292
1473
  const trimmedPattern = pattern.trim();
293
1474
  const filteredLines = lines.filter((line) => line.trim() !== trimmedPattern);
294
1475
  if (filteredLines.length === lines.length) {
295
- console.log(`[fullstack-cli] \u25CB ${path2.basename(filePath)} (pattern not found: ${pattern})`);
1476
+ console.log(`[fullstack-cli] \u25CB ${path3.basename(filePath)} (pattern not found: ${pattern})`);
296
1477
  return false;
297
1478
  }
298
- fs2.writeFileSync(filePath, filteredLines.join("\n"));
299
- console.log(`[fullstack-cli] \u2713 ${path2.basename(filePath)} (removed: ${pattern})`);
1479
+ fs4.writeFileSync(filePath, filteredLines.join("\n"));
1480
+ console.log(`[fullstack-cli] \u2713 ${path3.basename(filePath)} (removed: ${pattern})`);
300
1481
  return true;
301
1482
  }
302
1483
 
303
1484
  // src/commands/sync/run.handler.ts
304
1485
  async function run2(options) {
305
1486
  const userProjectRoot = process.env.INIT_CWD || process.cwd();
306
- const __filename = fileURLToPath2(import.meta.url);
307
- const __dirname2 = path3.dirname(__filename);
308
- const pluginRoot = path3.resolve(__dirname2, "..");
1487
+ const __filename = fileURLToPath3(import.meta.url);
1488
+ const __dirname2 = path4.dirname(__filename);
1489
+ const pluginRoot = path4.resolve(__dirname2, "..");
309
1490
  if (userProjectRoot === pluginRoot) {
310
1491
  console.log("[fullstack-cli] Skip syncing (installing plugin itself)");
311
1492
  process.exit(0);
312
1493
  }
313
- const userPackageJson = path3.join(userProjectRoot, "package.json");
314
- if (!fs3.existsSync(userPackageJson)) {
1494
+ const userPackageJson = path4.join(userProjectRoot, "package.json");
1495
+ if (!fs5.existsSync(userPackageJson)) {
315
1496
  console.log("[fullstack-cli] Skip syncing (not a valid npm project)");
316
1497
  process.exit(0);
317
1498
  }
@@ -339,7 +1520,7 @@ async function run2(options) {
339
1520
  }
340
1521
  async function syncRule(rule, pluginRoot, userProjectRoot) {
341
1522
  if (rule.type === "delete-file" || rule.type === "delete-directory") {
342
- const destPath2 = path3.join(userProjectRoot, rule.to);
1523
+ const destPath2 = path4.join(userProjectRoot, rule.to);
343
1524
  if (rule.type === "delete-file") {
344
1525
  deleteFile(destPath2);
345
1526
  } else {
@@ -348,16 +1529,16 @@ async function syncRule(rule, pluginRoot, userProjectRoot) {
348
1529
  return;
349
1530
  }
350
1531
  if (rule.type === "remove-line") {
351
- const destPath2 = path3.join(userProjectRoot, rule.to);
1532
+ const destPath2 = path4.join(userProjectRoot, rule.to);
352
1533
  removeLineFromFile(destPath2, rule.pattern);
353
1534
  return;
354
1535
  }
355
1536
  if (!("from" in rule)) {
356
1537
  return;
357
1538
  }
358
- const srcPath = path3.join(pluginRoot, rule.from);
359
- const destPath = path3.join(userProjectRoot, rule.to);
360
- if (!fs3.existsSync(srcPath)) {
1539
+ const srcPath = path4.join(pluginRoot, rule.from);
1540
+ const destPath = path4.join(userProjectRoot, rule.to);
1541
+ if (!fs5.existsSync(srcPath)) {
361
1542
  console.warn(`[fullstack-cli] Source not found: ${rule.from}`);
362
1543
  return;
363
1544
  }
@@ -374,64 +1555,64 @@ async function syncRule(rule, pluginRoot, userProjectRoot) {
374
1555
  }
375
1556
  }
376
1557
  function syncFile(src, dest, overwrite = true) {
377
- const destDir = path3.dirname(dest);
378
- if (!fs3.existsSync(destDir)) {
379
- fs3.mkdirSync(destDir, { recursive: true });
1558
+ const destDir = path4.dirname(dest);
1559
+ if (!fs5.existsSync(destDir)) {
1560
+ fs5.mkdirSync(destDir, { recursive: true });
380
1561
  }
381
- if (fs3.existsSync(dest) && !overwrite) {
382
- console.log(`[fullstack-cli] \u25CB ${path3.basename(dest)} (skipped, already exists)`);
1562
+ if (fs5.existsSync(dest) && !overwrite) {
1563
+ console.log(`[fullstack-cli] \u25CB ${path4.basename(dest)} (skipped, already exists)`);
383
1564
  return;
384
1565
  }
385
- fs3.copyFileSync(src, dest);
386
- console.log(`[fullstack-cli] \u2713 ${path3.basename(dest)}`);
1566
+ fs5.copyFileSync(src, dest);
1567
+ console.log(`[fullstack-cli] \u2713 ${path4.basename(dest)}`);
387
1568
  }
388
1569
  function syncDirectory(src, dest, overwrite = true) {
389
- if (!fs3.existsSync(dest)) {
390
- fs3.mkdirSync(dest, { recursive: true });
1570
+ if (!fs5.existsSync(dest)) {
1571
+ fs5.mkdirSync(dest, { recursive: true });
391
1572
  }
392
- const files = fs3.readdirSync(src);
1573
+ const files = fs5.readdirSync(src);
393
1574
  let count = 0;
394
1575
  files.forEach((file) => {
395
- const srcFile = path3.join(src, file);
396
- const destFile = path3.join(dest, file);
397
- const stats = fs3.statSync(srcFile);
1576
+ const srcFile = path4.join(src, file);
1577
+ const destFile = path4.join(dest, file);
1578
+ const stats = fs5.statSync(srcFile);
398
1579
  if (stats.isDirectory()) {
399
1580
  syncDirectory(srcFile, destFile, overwrite);
400
1581
  } else {
401
- if (overwrite || !fs3.existsSync(destFile)) {
402
- fs3.copyFileSync(srcFile, destFile);
403
- console.log(`[fullstack-cli] \u2713 ${path3.relative(dest, destFile)}`);
1582
+ if (overwrite || !fs5.existsSync(destFile)) {
1583
+ fs5.copyFileSync(srcFile, destFile);
1584
+ console.log(`[fullstack-cli] \u2713 ${path4.relative(dest, destFile)}`);
404
1585
  count++;
405
1586
  }
406
1587
  }
407
1588
  });
408
1589
  if (count > 0) {
409
- console.log(`[fullstack-cli] Synced ${count} files to ${path3.basename(dest)}/`);
1590
+ console.log(`[fullstack-cli] Synced ${count} files to ${path4.basename(dest)}/`);
410
1591
  }
411
1592
  }
412
1593
  function appendToFile(src, dest) {
413
- const content = fs3.readFileSync(src, "utf-8");
1594
+ const content = fs5.readFileSync(src, "utf-8");
414
1595
  let existingContent = "";
415
- if (fs3.existsSync(dest)) {
416
- existingContent = fs3.readFileSync(dest, "utf-8");
1596
+ if (fs5.existsSync(dest)) {
1597
+ existingContent = fs5.readFileSync(dest, "utf-8");
417
1598
  }
418
1599
  if (existingContent.includes(content.trim())) {
419
- console.log(`[fullstack-cli] \u25CB ${path3.basename(dest)} (already contains content)`);
1600
+ console.log(`[fullstack-cli] \u25CB ${path4.basename(dest)} (already contains content)`);
420
1601
  return;
421
1602
  }
422
- fs3.appendFileSync(dest, content);
423
- console.log(`[fullstack-cli] \u2713 ${path3.basename(dest)} (appended)`);
1603
+ fs5.appendFileSync(dest, content);
1604
+ console.log(`[fullstack-cli] \u2713 ${path4.basename(dest)} (appended)`);
424
1605
  }
425
1606
  function setPermissions(permissions, projectRoot) {
426
1607
  for (const [pattern, mode] of Object.entries(permissions)) {
427
1608
  if (pattern === "**/*.sh") {
428
- const scriptsDir = path3.join(projectRoot, "scripts");
429
- if (fs3.existsSync(scriptsDir)) {
430
- const files = fs3.readdirSync(scriptsDir);
1609
+ const scriptsDir = path4.join(projectRoot, "scripts");
1610
+ if (fs5.existsSync(scriptsDir)) {
1611
+ const files = fs5.readdirSync(scriptsDir);
431
1612
  files.forEach((file) => {
432
1613
  if (file.endsWith(".sh")) {
433
- const filePath = path3.join(scriptsDir, file);
434
- fs3.chmodSync(filePath, mode);
1614
+ const filePath = path4.join(scriptsDir, file);
1615
+ fs5.chmodSync(filePath, mode);
435
1616
  }
436
1617
  });
437
1618
  }
@@ -439,19 +1620,19 @@ function setPermissions(permissions, projectRoot) {
439
1620
  }
440
1621
  }
441
1622
  function deleteFile(filePath) {
442
- if (fs3.existsSync(filePath)) {
443
- fs3.unlinkSync(filePath);
444
- console.log(`[fullstack-cli] \u2713 ${path3.basename(filePath)} (deleted)`);
1623
+ if (fs5.existsSync(filePath)) {
1624
+ fs5.unlinkSync(filePath);
1625
+ console.log(`[fullstack-cli] \u2713 ${path4.basename(filePath)} (deleted)`);
445
1626
  } else {
446
- console.log(`[fullstack-cli] \u25CB ${path3.basename(filePath)} (not found)`);
1627
+ console.log(`[fullstack-cli] \u25CB ${path4.basename(filePath)} (not found)`);
447
1628
  }
448
1629
  }
449
1630
  function deleteDirectory(dirPath) {
450
- if (fs3.existsSync(dirPath)) {
451
- fs3.rmSync(dirPath, { recursive: true });
452
- console.log(`[fullstack-cli] \u2713 ${path3.basename(dirPath)} (deleted)`);
1631
+ if (fs5.existsSync(dirPath)) {
1632
+ fs5.rmSync(dirPath, { recursive: true });
1633
+ console.log(`[fullstack-cli] \u2713 ${path4.basename(dirPath)} (deleted)`);
453
1634
  } else {
454
- console.log(`[fullstack-cli] \u25CB ${path3.basename(dirPath)} (not found)`);
1635
+ console.log(`[fullstack-cli] \u25CB ${path4.basename(dirPath)} (not found)`);
455
1636
  }
456
1637
  }
457
1638
 
@@ -467,8 +1648,8 @@ var syncCommand = {
467
1648
  };
468
1649
 
469
1650
  // src/commands/action-plugin/utils.ts
470
- import fs4 from "fs";
471
- import path4 from "path";
1651
+ import fs6 from "fs";
1652
+ import path5 from "path";
472
1653
  import { spawnSync as spawnSync2, execSync } from "child_process";
473
1654
  function parsePluginName(input) {
474
1655
  const match = input.match(/^(@[^/]+\/[^@]+)(?:@(.+))?$/);
@@ -486,18 +1667,18 @@ function getProjectRoot() {
486
1667
  return process.cwd();
487
1668
  }
488
1669
  function getPackageJsonPath() {
489
- return path4.join(getProjectRoot(), "package.json");
1670
+ return path5.join(getProjectRoot(), "package.json");
490
1671
  }
491
1672
  function getPluginPath(pluginName) {
492
- return path4.join(getProjectRoot(), "node_modules", pluginName);
1673
+ return path5.join(getProjectRoot(), "node_modules", pluginName);
493
1674
  }
494
1675
  function readPackageJson() {
495
1676
  const pkgPath = getPackageJsonPath();
496
- if (!fs4.existsSync(pkgPath)) {
1677
+ if (!fs6.existsSync(pkgPath)) {
497
1678
  throw new Error("package.json not found in current directory");
498
1679
  }
499
1680
  try {
500
- const content = fs4.readFileSync(pkgPath, "utf-8");
1681
+ const content = fs6.readFileSync(pkgPath, "utf-8");
501
1682
  return JSON.parse(content);
502
1683
  } catch {
503
1684
  throw new Error("Failed to parse package.json");
@@ -505,7 +1686,7 @@ function readPackageJson() {
505
1686
  }
506
1687
  function writePackageJson(pkg2) {
507
1688
  const pkgPath = getPackageJsonPath();
508
- fs4.writeFileSync(pkgPath, JSON.stringify(pkg2, null, 2) + "\n", "utf-8");
1689
+ fs6.writeFileSync(pkgPath, JSON.stringify(pkg2, null, 2) + "\n", "utf-8");
509
1690
  }
510
1691
  function readActionPlugins() {
511
1692
  const pkg2 = readPackageJson();
@@ -538,12 +1719,12 @@ function npmInstall(tgzPath) {
538
1719
  }
539
1720
  }
540
1721
  function getPackageVersion(pluginName) {
541
- const pkgJsonPath = path4.join(getPluginPath(pluginName), "package.json");
542
- if (!fs4.existsSync(pkgJsonPath)) {
1722
+ const pkgJsonPath = path5.join(getPluginPath(pluginName), "package.json");
1723
+ if (!fs6.existsSync(pkgJsonPath)) {
543
1724
  return null;
544
1725
  }
545
1726
  try {
546
- const content = fs4.readFileSync(pkgJsonPath, "utf-8");
1727
+ const content = fs6.readFileSync(pkgJsonPath, "utf-8");
547
1728
  const pkg2 = JSON.parse(content);
548
1729
  return pkg2.version || null;
549
1730
  } catch {
@@ -551,49 +1732,49 @@ function getPackageVersion(pluginName) {
551
1732
  }
552
1733
  }
553
1734
  function readPluginPackageJson(pluginPath) {
554
- const pkgJsonPath = path4.join(pluginPath, "package.json");
555
- if (!fs4.existsSync(pkgJsonPath)) {
1735
+ const pkgJsonPath = path5.join(pluginPath, "package.json");
1736
+ if (!fs6.existsSync(pkgJsonPath)) {
556
1737
  return null;
557
1738
  }
558
1739
  try {
559
- const content = fs4.readFileSync(pkgJsonPath, "utf-8");
1740
+ const content = fs6.readFileSync(pkgJsonPath, "utf-8");
560
1741
  return JSON.parse(content);
561
1742
  } catch {
562
1743
  return null;
563
1744
  }
564
1745
  }
565
1746
  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 });
1747
+ const nodeModulesPath = path5.join(getProjectRoot(), "node_modules");
1748
+ const targetDir = path5.join(nodeModulesPath, pluginName);
1749
+ const scopeDir = path5.dirname(targetDir);
1750
+ if (!fs6.existsSync(scopeDir)) {
1751
+ fs6.mkdirSync(scopeDir, { recursive: true });
571
1752
  }
572
- if (fs4.existsSync(targetDir)) {
573
- fs4.rmSync(targetDir, { recursive: true });
1753
+ if (fs6.existsSync(targetDir)) {
1754
+ fs6.rmSync(targetDir, { recursive: true });
574
1755
  }
575
- const tempDir = path4.join(nodeModulesPath, ".cache", "fullstack-cli", "extract-temp");
576
- if (fs4.existsSync(tempDir)) {
577
- fs4.rmSync(tempDir, { recursive: true });
1756
+ const tempDir = path5.join(nodeModulesPath, ".cache", "fullstack-cli", "extract-temp");
1757
+ if (fs6.existsSync(tempDir)) {
1758
+ fs6.rmSync(tempDir, { recursive: true });
578
1759
  }
579
- fs4.mkdirSync(tempDir, { recursive: true });
1760
+ fs6.mkdirSync(tempDir, { recursive: true });
580
1761
  try {
581
1762
  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);
1763
+ const extractedDir = path5.join(tempDir, "package");
1764
+ if (fs6.existsSync(extractedDir)) {
1765
+ fs6.renameSync(extractedDir, targetDir);
585
1766
  } else {
586
- const files = fs4.readdirSync(tempDir);
1767
+ const files = fs6.readdirSync(tempDir);
587
1768
  if (files.length === 1) {
588
- fs4.renameSync(path4.join(tempDir, files[0]), targetDir);
1769
+ fs6.renameSync(path5.join(tempDir, files[0]), targetDir);
589
1770
  } else {
590
1771
  throw new Error("Unexpected tgz structure");
591
1772
  }
592
1773
  }
593
1774
  return targetDir;
594
1775
  } finally {
595
- if (fs4.existsSync(tempDir)) {
596
- fs4.rmSync(tempDir, { recursive: true });
1776
+ if (fs6.existsSync(tempDir)) {
1777
+ fs6.rmSync(tempDir, { recursive: true });
597
1778
  }
598
1779
  }
599
1780
  }
@@ -602,10 +1783,10 @@ function checkMissingPeerDeps(peerDeps) {
602
1783
  return [];
603
1784
  }
604
1785
  const missing = [];
605
- const nodeModulesPath = path4.join(getProjectRoot(), "node_modules");
1786
+ const nodeModulesPath = path5.join(getProjectRoot(), "node_modules");
606
1787
  for (const [depName, _version] of Object.entries(peerDeps)) {
607
- const depPath = path4.join(nodeModulesPath, depName);
608
- if (!fs4.existsSync(depPath)) {
1788
+ const depPath = path5.join(nodeModulesPath, depName);
1789
+ if (!fs6.existsSync(depPath)) {
609
1790
  missing.push(depName);
610
1791
  }
611
1792
  }
@@ -629,16 +1810,16 @@ function installMissingDeps(deps) {
629
1810
  }
630
1811
  function removePluginDirectory(pluginName) {
631
1812
  const pluginPath = getPluginPath(pluginName);
632
- if (fs4.existsSync(pluginPath)) {
633
- fs4.rmSync(pluginPath, { recursive: true });
1813
+ if (fs6.existsSync(pluginPath)) {
1814
+ fs6.rmSync(pluginPath, { recursive: true });
634
1815
  console.log(`[action-plugin] Removed ${pluginName}`);
635
1816
  }
636
1817
  }
637
1818
 
638
1819
  // src/commands/action-plugin/api-client.ts
639
1820
  import { HttpClient as HttpClient2 } from "@lark-apaas/http-client";
640
- import fs5 from "fs";
641
- import path5 from "path";
1821
+ import fs7 from "fs";
1822
+ import path6 from "path";
642
1823
 
643
1824
  // src/utils/http-client.ts
644
1825
  import { HttpClient } from "@lark-apaas/http-client";
@@ -723,19 +1904,19 @@ async function downloadFromPublic(downloadURL) {
723
1904
  return Buffer.from(arrayBuffer);
724
1905
  }
725
1906
  function getPluginCacheDir() {
726
- return path5.join(process.cwd(), PLUGIN_CACHE_DIR);
1907
+ return path6.join(process.cwd(), PLUGIN_CACHE_DIR);
727
1908
  }
728
1909
  function ensureCacheDir() {
729
1910
  const cacheDir = getPluginCacheDir();
730
- if (!fs5.existsSync(cacheDir)) {
731
- fs5.mkdirSync(cacheDir, { recursive: true });
1911
+ if (!fs7.existsSync(cacheDir)) {
1912
+ fs7.mkdirSync(cacheDir, { recursive: true });
732
1913
  }
733
1914
  }
734
1915
  function getTempFilePath(pluginKey, version) {
735
1916
  ensureCacheDir();
736
1917
  const safeKey = pluginKey.replace(/[/@]/g, "_");
737
1918
  const filename = `${safeKey}-${version}.tgz`;
738
- return path5.join(getPluginCacheDir(), filename);
1919
+ return path6.join(getPluginCacheDir(), filename);
739
1920
  }
740
1921
  async function downloadPlugin(pluginKey, requestedVersion) {
741
1922
  console.log(`[action-plugin] Fetching plugin info for ${pluginKey}@${requestedVersion}...`);
@@ -751,7 +1932,7 @@ async function downloadPlugin(pluginKey, requestedVersion) {
751
1932
  tgzBuffer = await downloadFromPublic(pluginInfo.downloadURL);
752
1933
  }
753
1934
  const tgzPath = getTempFilePath(pluginKey, pluginInfo.version);
754
- fs5.writeFileSync(tgzPath, tgzBuffer);
1935
+ fs7.writeFileSync(tgzPath, tgzBuffer);
755
1936
  console.log(`[action-plugin] Downloaded to ${tgzPath} (${(tgzBuffer.length / 1024).toFixed(2)} KB)`);
756
1937
  return {
757
1938
  tgzPath,
@@ -761,8 +1942,8 @@ async function downloadPlugin(pluginKey, requestedVersion) {
761
1942
  }
762
1943
  function cleanupTempFile(tgzPath) {
763
1944
  try {
764
- if (fs5.existsSync(tgzPath)) {
765
- fs5.unlinkSync(tgzPath);
1945
+ if (fs7.existsSync(tgzPath)) {
1946
+ fs7.unlinkSync(tgzPath);
766
1947
  }
767
1948
  } catch {
768
1949
  }
@@ -1098,39 +2279,39 @@ var actionPluginCommandGroup = {
1098
2279
  };
1099
2280
 
1100
2281
  // src/commands/capability/utils.ts
1101
- import fs6 from "fs";
1102
- import path6 from "path";
2282
+ import fs8 from "fs";
2283
+ import path7 from "path";
1103
2284
  var CAPABILITIES_DIR = "server/capabilities";
1104
2285
  function getProjectRoot2() {
1105
2286
  return process.cwd();
1106
2287
  }
1107
2288
  function getCapabilitiesDir() {
1108
- return path6.join(getProjectRoot2(), CAPABILITIES_DIR);
2289
+ return path7.join(getProjectRoot2(), CAPABILITIES_DIR);
1109
2290
  }
1110
2291
  function getCapabilityPath(id) {
1111
- return path6.join(getCapabilitiesDir(), `${id}.json`);
2292
+ return path7.join(getCapabilitiesDir(), `${id}.json`);
1112
2293
  }
1113
2294
  function getPluginManifestPath(pluginKey) {
1114
- return path6.join(getProjectRoot2(), "node_modules", pluginKey, "manifest.json");
2295
+ return path7.join(getProjectRoot2(), "node_modules", pluginKey, "manifest.json");
1115
2296
  }
1116
2297
  function capabilitiesDirExists() {
1117
- return fs6.existsSync(getCapabilitiesDir());
2298
+ return fs8.existsSync(getCapabilitiesDir());
1118
2299
  }
1119
2300
  function listCapabilityIds() {
1120
2301
  const dir = getCapabilitiesDir();
1121
- if (!fs6.existsSync(dir)) {
2302
+ if (!fs8.existsSync(dir)) {
1122
2303
  return [];
1123
2304
  }
1124
- const files = fs6.readdirSync(dir);
2305
+ const files = fs8.readdirSync(dir);
1125
2306
  return files.filter((f) => f.endsWith(".json")).map((f) => f.replace(/\.json$/, ""));
1126
2307
  }
1127
2308
  function readCapability(id) {
1128
2309
  const filePath = getCapabilityPath(id);
1129
- if (!fs6.existsSync(filePath)) {
2310
+ if (!fs8.existsSync(filePath)) {
1130
2311
  throw new Error(`Capability not found: ${id}`);
1131
2312
  }
1132
2313
  try {
1133
- const content = fs6.readFileSync(filePath, "utf-8");
2314
+ const content = fs8.readFileSync(filePath, "utf-8");
1134
2315
  return JSON.parse(content);
1135
2316
  } catch (error) {
1136
2317
  if (error instanceof SyntaxError) {
@@ -1145,11 +2326,11 @@ function readAllCapabilities() {
1145
2326
  }
1146
2327
  function readPluginManifest(pluginKey) {
1147
2328
  const manifestPath = getPluginManifestPath(pluginKey);
1148
- if (!fs6.existsSync(manifestPath)) {
2329
+ if (!fs8.existsSync(manifestPath)) {
1149
2330
  throw new Error(`Plugin not installed: ${pluginKey} (manifest.json not found)`);
1150
2331
  }
1151
2332
  try {
1152
- const content = fs6.readFileSync(manifestPath, "utf-8");
2333
+ const content = fs8.readFileSync(manifestPath, "utf-8");
1153
2334
  return JSON.parse(content);
1154
2335
  } catch (error) {
1155
2336
  if (error instanceof SyntaxError) {
@@ -1323,58 +2504,58 @@ var capabilityCommandGroup = {
1323
2504
  };
1324
2505
 
1325
2506
  // src/commands/migration/version-manager.ts
1326
- import fs7 from "fs";
1327
- import path7 from "path";
2507
+ import fs9 from "fs";
2508
+ import path8 from "path";
1328
2509
  var PACKAGE_JSON = "package.json";
1329
2510
  var VERSION_FIELD = "migrationVersion";
1330
2511
  function getPackageJsonPath2() {
1331
- return path7.join(process.cwd(), PACKAGE_JSON);
2512
+ return path8.join(process.cwd(), PACKAGE_JSON);
1332
2513
  }
1333
2514
  function getCurrentVersion() {
1334
2515
  const pkgPath = getPackageJsonPath2();
1335
- if (!fs7.existsSync(pkgPath)) {
2516
+ if (!fs9.existsSync(pkgPath)) {
1336
2517
  throw new Error("package.json not found");
1337
2518
  }
1338
- const pkg2 = JSON.parse(fs7.readFileSync(pkgPath, "utf-8"));
2519
+ const pkg2 = JSON.parse(fs9.readFileSync(pkgPath, "utf-8"));
1339
2520
  return pkg2[VERSION_FIELD] ?? 0;
1340
2521
  }
1341
2522
  function setCurrentVersion(version) {
1342
2523
  const pkgPath = getPackageJsonPath2();
1343
- const pkg2 = JSON.parse(fs7.readFileSync(pkgPath, "utf-8"));
2524
+ const pkg2 = JSON.parse(fs9.readFileSync(pkgPath, "utf-8"));
1344
2525
  pkg2[VERSION_FIELD] = version;
1345
- fs7.writeFileSync(pkgPath, JSON.stringify(pkg2, null, 2) + "\n", "utf-8");
2526
+ fs9.writeFileSync(pkgPath, JSON.stringify(pkg2, null, 2) + "\n", "utf-8");
1346
2527
  }
1347
2528
 
1348
2529
  // src/commands/migration/versions/v001_capability/json-migrator/detector.ts
1349
- import fs9 from "fs";
1350
- import path9 from "path";
2530
+ import fs11 from "fs";
2531
+ import path10 from "path";
1351
2532
 
1352
2533
  // src/commands/migration/versions/v001_capability/utils.ts
1353
- import fs8 from "fs";
1354
- import path8 from "path";
2534
+ import fs10 from "fs";
2535
+ import path9 from "path";
1355
2536
  var CAPABILITIES_DIR2 = "server/capabilities";
1356
2537
  function getProjectRoot3() {
1357
2538
  return process.cwd();
1358
2539
  }
1359
2540
  function getCapabilitiesDir2() {
1360
- return path8.join(getProjectRoot3(), CAPABILITIES_DIR2);
2541
+ return path9.join(getProjectRoot3(), CAPABILITIES_DIR2);
1361
2542
  }
1362
2543
  function getPluginManifestPath2(pluginKey) {
1363
- return path8.join(getProjectRoot3(), "node_modules", pluginKey, "manifest.json");
2544
+ return path9.join(getProjectRoot3(), "node_modules", pluginKey, "manifest.json");
1364
2545
  }
1365
2546
 
1366
2547
  // src/commands/migration/versions/v001_capability/json-migrator/detector.ts
1367
2548
  function detectJsonMigration() {
1368
2549
  const capabilitiesDir = getCapabilitiesDir2();
1369
- const oldFilePath = path9.join(capabilitiesDir, "capabilities.json");
1370
- if (!fs9.existsSync(oldFilePath)) {
2550
+ const oldFilePath = path10.join(capabilitiesDir, "capabilities.json");
2551
+ if (!fs11.existsSync(oldFilePath)) {
1371
2552
  return {
1372
2553
  needsMigration: false,
1373
2554
  reason: "capabilities.json not found"
1374
2555
  };
1375
2556
  }
1376
2557
  try {
1377
- const content = fs9.readFileSync(oldFilePath, "utf-8");
2558
+ const content = fs11.readFileSync(oldFilePath, "utf-8");
1378
2559
  const parsed = JSON.parse(content);
1379
2560
  const capabilities = Array.isArray(parsed) ? parsed : [];
1380
2561
  return {
@@ -1414,8 +2595,8 @@ async function check(options) {
1414
2595
  }
1415
2596
 
1416
2597
  // src/commands/migration/versions/v001_capability/json-migrator/index.ts
1417
- import fs10 from "fs";
1418
- import path10 from "path";
2598
+ import fs12 from "fs";
2599
+ import path11 from "path";
1419
2600
 
1420
2601
  // src/commands/migration/versions/v001_capability/mapping.ts
1421
2602
  var DEFAULT_PLUGIN_VERSION = "1.0.0";
@@ -1645,18 +2826,18 @@ function transformCapabilities(oldCapabilities) {
1645
2826
  // src/commands/migration/versions/v001_capability/json-migrator/index.ts
1646
2827
  function loadExistingCapabilities() {
1647
2828
  const capabilitiesDir = getCapabilitiesDir2();
1648
- if (!fs10.existsSync(capabilitiesDir)) {
2829
+ if (!fs12.existsSync(capabilitiesDir)) {
1649
2830
  return [];
1650
2831
  }
1651
- const files = fs10.readdirSync(capabilitiesDir);
2832
+ const files = fs12.readdirSync(capabilitiesDir);
1652
2833
  const capabilities = [];
1653
2834
  for (const file of files) {
1654
2835
  if (file === "capabilities.json" || !file.endsWith(".json")) {
1655
2836
  continue;
1656
2837
  }
1657
2838
  try {
1658
- const filePath = path10.join(capabilitiesDir, file);
1659
- const content = fs10.readFileSync(filePath, "utf-8");
2839
+ const filePath = path11.join(capabilitiesDir, file);
2840
+ const content = fs12.readFileSync(filePath, "utf-8");
1660
2841
  const capability = JSON.parse(content);
1661
2842
  if (capability.id && capability.pluginKey) {
1662
2843
  capabilities.push(capability);
@@ -1714,9 +2895,9 @@ async function migrateJsonFiles(options) {
1714
2895
  }
1715
2896
  const capabilitiesDir = getCapabilitiesDir2();
1716
2897
  for (const cap of newCapabilities) {
1717
- const filePath = path10.join(capabilitiesDir, `${cap.id}.json`);
2898
+ const filePath = path11.join(capabilitiesDir, `${cap.id}.json`);
1718
2899
  const content = JSON.stringify(cap, null, 2);
1719
- fs10.writeFileSync(filePath, content, "utf-8");
2900
+ fs12.writeFileSync(filePath, content, "utf-8");
1720
2901
  console.log(` \u2713 Created: ${cap.id}.json`);
1721
2902
  }
1722
2903
  return {
@@ -1728,11 +2909,11 @@ async function migrateJsonFiles(options) {
1728
2909
  }
1729
2910
 
1730
2911
  // src/commands/migration/versions/v001_capability/plugin-installer/detector.ts
1731
- import fs11 from "fs";
2912
+ import fs13 from "fs";
1732
2913
  function isPluginInstalled2(pluginKey) {
1733
2914
  const actionPlugins = readActionPlugins();
1734
2915
  const manifestPath = getPluginManifestPath2(pluginKey);
1735
- return fs11.existsSync(manifestPath) && !!actionPlugins[pluginKey];
2916
+ return fs13.existsSync(manifestPath) && !!actionPlugins[pluginKey];
1736
2917
  }
1737
2918
  function detectPluginsToInstall(capabilities) {
1738
2919
  const pluginKeys = /* @__PURE__ */ new Set();
@@ -1808,12 +2989,12 @@ async function installPlugins(capabilities, options) {
1808
2989
  }
1809
2990
 
1810
2991
  // src/commands/migration/versions/v001_capability/code-migrator/index.ts
1811
- import path12 from "path";
1812
- import { Project } from "ts-morph";
2992
+ import path13 from "path";
2993
+ import { Project as Project2 } from "ts-morph";
1813
2994
 
1814
2995
  // src/commands/migration/versions/v001_capability/code-migrator/scanner.ts
1815
- import fs12 from "fs";
1816
- import path11 from "path";
2996
+ import fs14 from "fs";
2997
+ import path12 from "path";
1817
2998
  var EXCLUDED_DIRS = [
1818
2999
  "node_modules",
1819
3000
  "dist",
@@ -1828,9 +3009,9 @@ var EXCLUDED_PATTERNS = [
1828
3009
  /\.d\.ts$/
1829
3010
  ];
1830
3011
  function scanDirectory(dir, files = []) {
1831
- const entries = fs12.readdirSync(dir, { withFileTypes: true });
3012
+ const entries = fs14.readdirSync(dir, { withFileTypes: true });
1832
3013
  for (const entry of entries) {
1833
- const fullPath = path11.join(dir, entry.name);
3014
+ const fullPath = path12.join(dir, entry.name);
1834
3015
  if (entry.isDirectory()) {
1835
3016
  if (EXCLUDED_DIRS.includes(entry.name)) {
1836
3017
  continue;
@@ -1846,14 +3027,14 @@ function scanDirectory(dir, files = []) {
1846
3027
  return files;
1847
3028
  }
1848
3029
  function scanServerFiles() {
1849
- const serverDir = path11.join(getProjectRoot3(), "server");
1850
- if (!fs12.existsSync(serverDir)) {
3030
+ const serverDir = path12.join(getProjectRoot3(), "server");
3031
+ if (!fs14.existsSync(serverDir)) {
1851
3032
  return [];
1852
3033
  }
1853
3034
  return scanDirectory(serverDir);
1854
3035
  }
1855
3036
  function hasCapabilityImport(filePath) {
1856
- const content = fs12.readFileSync(filePath, "utf-8");
3037
+ const content = fs14.readFileSync(filePath, "utf-8");
1857
3038
  return /import\s+.*from\s+['"][^'"]*capabilities[^'"]*['"]/.test(content);
1858
3039
  }
1859
3040
  function scanFilesToMigrate() {
@@ -2228,7 +3409,7 @@ function analyzeFile(project, filePath, actionNameMap) {
2228
3409
  const callSites = analyzeCallSites(sourceFile, imports);
2229
3410
  const classInfo = analyzeClass(sourceFile);
2230
3411
  const { canMigrate, reason } = canAutoMigrate(classInfo);
2231
- const relativePath = path12.relative(getProjectRoot3(), filePath);
3412
+ const relativePath = path13.relative(getProjectRoot3(), filePath);
2232
3413
  return {
2233
3414
  filePath: relativePath,
2234
3415
  imports,
@@ -2239,7 +3420,7 @@ function analyzeFile(project, filePath, actionNameMap) {
2239
3420
  };
2240
3421
  }
2241
3422
  function migrateFile(project, analysis, dryRun) {
2242
- const absolutePath = path12.join(getProjectRoot3(), analysis.filePath);
3423
+ const absolutePath = path13.join(getProjectRoot3(), analysis.filePath);
2243
3424
  if (!analysis.canAutoMigrate) {
2244
3425
  return {
2245
3426
  filePath: analysis.filePath,
@@ -2299,7 +3480,7 @@ async function migrateCode(options, capabilities) {
2299
3480
  console.log(" No files need code migration.\n");
2300
3481
  return result;
2301
3482
  }
2302
- const project = new Project({
3483
+ const project = new Project2({
2303
3484
  skipAddingFilesFromTsConfig: true,
2304
3485
  compilerOptions: {
2305
3486
  allowJs: true
@@ -2342,17 +3523,17 @@ function getSuggestion(analysis) {
2342
3523
  }
2343
3524
 
2344
3525
  // src/commands/migration/versions/v001_capability/cleanup.ts
2345
- import fs13 from "fs";
2346
- import path13 from "path";
3526
+ import fs15 from "fs";
3527
+ import path14 from "path";
2347
3528
  function cleanupOldFiles(capabilities, dryRun) {
2348
3529
  const deletedFiles = [];
2349
3530
  const errors = [];
2350
3531
  const capabilitiesDir = getCapabilitiesDir2();
2351
- const oldJsonPath = path13.join(capabilitiesDir, "capabilities.json");
2352
- if (fs13.existsSync(oldJsonPath)) {
3532
+ const oldJsonPath = path14.join(capabilitiesDir, "capabilities.json");
3533
+ if (fs15.existsSync(oldJsonPath)) {
2353
3534
  try {
2354
3535
  if (!dryRun) {
2355
- fs13.unlinkSync(oldJsonPath);
3536
+ fs15.unlinkSync(oldJsonPath);
2356
3537
  }
2357
3538
  deletedFiles.push("capabilities.json");
2358
3539
  } catch (error) {
@@ -2360,11 +3541,11 @@ function cleanupOldFiles(capabilities, dryRun) {
2360
3541
  }
2361
3542
  }
2362
3543
  for (const cap of capabilities) {
2363
- const tsFilePath = path13.join(capabilitiesDir, `${cap.id}.ts`);
2364
- if (fs13.existsSync(tsFilePath)) {
3544
+ const tsFilePath = path14.join(capabilitiesDir, `${cap.id}.ts`);
3545
+ if (fs15.existsSync(tsFilePath)) {
2365
3546
  try {
2366
3547
  if (!dryRun) {
2367
- fs13.unlinkSync(tsFilePath);
3548
+ fs15.unlinkSync(tsFilePath);
2368
3549
  }
2369
3550
  deletedFiles.push(`${cap.id}.ts`);
2370
3551
  } catch (error) {
@@ -2380,8 +3561,8 @@ function cleanupOldFiles(capabilities, dryRun) {
2380
3561
  }
2381
3562
 
2382
3563
  // src/commands/migration/versions/v001_capability/report-generator.ts
2383
- import fs14 from "fs";
2384
- import path14 from "path";
3564
+ import fs16 from "fs";
3565
+ import path15 from "path";
2385
3566
  var REPORT_FILE = "capability-migration-report.md";
2386
3567
  function printSummary(result) {
2387
3568
  const { jsonMigration, pluginInstallation, codeMigration, cleanup } = result;
@@ -2544,15 +3725,15 @@ async function generateReport(result) {
2544
3725
  }
2545
3726
  lines.push("");
2546
3727
  const logDir = process.env.LOG_DIR || "logs";
2547
- if (!fs14.existsSync(logDir)) {
3728
+ if (!fs16.existsSync(logDir)) {
2548
3729
  return;
2549
3730
  }
2550
- const reportDir = path14.join(logDir, "migration");
2551
- if (!fs14.existsSync(reportDir)) {
2552
- fs14.mkdirSync(reportDir, { recursive: true });
3731
+ const reportDir = path15.join(logDir, "migration");
3732
+ if (!fs16.existsSync(reportDir)) {
3733
+ fs16.mkdirSync(reportDir, { recursive: true });
2553
3734
  }
2554
- const reportPath = path14.join(reportDir, REPORT_FILE);
2555
- fs14.writeFileSync(reportPath, lines.join("\n"), "utf-8");
3735
+ const reportPath = path15.join(reportDir, REPORT_FILE);
3736
+ fs16.writeFileSync(reportPath, lines.join("\n"), "utf-8");
2556
3737
  console.log(`\u{1F4C4} Report generated: ${reportPath}`);
2557
3738
  }
2558
3739
 
@@ -3084,10 +4265,10 @@ var migrationCommand = {
3084
4265
  };
3085
4266
 
3086
4267
  // src/commands/read-logs/index.ts
3087
- import path15 from "path";
4268
+ import path16 from "path";
3088
4269
 
3089
4270
  // src/commands/read-logs/std-utils.ts
3090
- import fs15 from "fs";
4271
+ import fs17 from "fs";
3091
4272
  function formatStdPrefixTime(localTime) {
3092
4273
  const match = localTime.match(/^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/);
3093
4274
  if (!match) return localTime;
@@ -3117,11 +4298,11 @@ function stripPrefixFromStdLine(line) {
3117
4298
  return `[${time}] ${content}`;
3118
4299
  }
3119
4300
  function readStdLinesTailFromLastMarkerPaged(filePath, maxLines, offset, isMarker) {
3120
- const stat = fs15.statSync(filePath);
4301
+ const stat = fs17.statSync(filePath);
3121
4302
  if (stat.size === 0) {
3122
4303
  return { lines: [], markerFound: false, totalLinesCount: 0 };
3123
4304
  }
3124
- const fd = fs15.openSync(filePath, "r");
4305
+ const fd = fs17.openSync(filePath, "r");
3125
4306
  const chunkSize = 64 * 1024;
3126
4307
  let position = stat.size;
3127
4308
  let remainder = "";
@@ -3135,7 +4316,7 @@ function readStdLinesTailFromLastMarkerPaged(filePath, maxLines, offset, isMarke
3135
4316
  const length = Math.min(chunkSize, position);
3136
4317
  position -= length;
3137
4318
  const buffer = Buffer.alloc(length);
3138
- fs15.readSync(fd, buffer, 0, length, position);
4319
+ fs17.readSync(fd, buffer, 0, length, position);
3139
4320
  let chunk = buffer.toString("utf8");
3140
4321
  if (remainder) {
3141
4322
  chunk += remainder;
@@ -3177,7 +4358,7 @@ function readStdLinesTailFromLastMarkerPaged(filePath, maxLines, offset, isMarke
3177
4358
  }
3178
4359
  }
3179
4360
  } finally {
3180
- fs15.closeSync(fd);
4361
+ fs17.closeSync(fd);
3181
4362
  }
3182
4363
  return { lines: collected.reverse(), markerFound, totalLinesCount };
3183
4364
  }
@@ -3198,21 +4379,21 @@ function readServerStdSegment(filePath, maxLines, offset) {
3198
4379
  }
3199
4380
 
3200
4381
  // src/commands/read-logs/tail.ts
3201
- import fs16 from "fs";
4382
+ import fs18 from "fs";
3202
4383
  function fileExists(filePath) {
3203
4384
  try {
3204
- fs16.accessSync(filePath, fs16.constants.F_OK | fs16.constants.R_OK);
4385
+ fs18.accessSync(filePath, fs18.constants.F_OK | fs18.constants.R_OK);
3205
4386
  return true;
3206
4387
  } catch {
3207
4388
  return false;
3208
4389
  }
3209
4390
  }
3210
4391
  function readFileTailLines(filePath, maxLines) {
3211
- const stat = fs16.statSync(filePath);
4392
+ const stat = fs18.statSync(filePath);
3212
4393
  if (stat.size === 0) {
3213
4394
  return [];
3214
4395
  }
3215
- const fd = fs16.openSync(filePath, "r");
4396
+ const fd = fs18.openSync(filePath, "r");
3216
4397
  const chunkSize = 64 * 1024;
3217
4398
  const chunks = [];
3218
4399
  let position = stat.size;
@@ -3222,13 +4403,13 @@ function readFileTailLines(filePath, maxLines) {
3222
4403
  const length = Math.min(chunkSize, position);
3223
4404
  position -= length;
3224
4405
  const buffer = Buffer.alloc(length);
3225
- fs16.readSync(fd, buffer, 0, length, position);
4406
+ fs18.readSync(fd, buffer, 0, length, position);
3226
4407
  chunks.unshift(buffer.toString("utf8"));
3227
4408
  const chunkLines = buffer.toString("utf8").split("\n").length - 1;
3228
4409
  collectedLines += chunkLines;
3229
4410
  }
3230
4411
  } finally {
3231
- fs16.closeSync(fd);
4412
+ fs18.closeSync(fd);
3232
4413
  }
3233
4414
  const content = chunks.join("");
3234
4415
  const allLines = content.split("\n");
@@ -3244,11 +4425,11 @@ function readFileTailLines(filePath, maxLines) {
3244
4425
  return allLines.slice(allLines.length - maxLines);
3245
4426
  }
3246
4427
  function readFileTailNonEmptyLinesWithOffset(filePath, maxLines, offset) {
3247
- const stat = fs16.statSync(filePath);
4428
+ const stat = fs18.statSync(filePath);
3248
4429
  if (stat.size === 0) {
3249
4430
  return { lines: [], totalLinesCount: 0 };
3250
4431
  }
3251
- const fd = fs16.openSync(filePath, "r");
4432
+ const fd = fs18.openSync(filePath, "r");
3252
4433
  const chunkSize = 64 * 1024;
3253
4434
  let position = stat.size;
3254
4435
  let remainder = "";
@@ -3260,7 +4441,7 @@ function readFileTailNonEmptyLinesWithOffset(filePath, maxLines, offset) {
3260
4441
  const length = Math.min(chunkSize, position);
3261
4442
  position -= length;
3262
4443
  const buffer = Buffer.alloc(length);
3263
- fs16.readSync(fd, buffer, 0, length, position);
4444
+ fs18.readSync(fd, buffer, 0, length, position);
3264
4445
  let chunk = buffer.toString("utf8");
3265
4446
  if (remainder) {
3266
4447
  chunk += remainder;
@@ -3291,7 +4472,7 @@ function readFileTailNonEmptyLinesWithOffset(filePath, maxLines, offset) {
3291
4472
  }
3292
4473
  }
3293
4474
  } finally {
3294
- fs16.closeSync(fd);
4475
+ fs18.closeSync(fd);
3295
4476
  }
3296
4477
  return { lines: collected.reverse(), totalLinesCount };
3297
4478
  }
@@ -3393,7 +4574,7 @@ function extractClientStdSegment(lines, maxLines, offset) {
3393
4574
  }
3394
4575
 
3395
4576
  // src/commands/read-logs/json-lines.ts
3396
- import fs17 from "fs";
4577
+ import fs19 from "fs";
3397
4578
  function normalizePid(value) {
3398
4579
  if (typeof value === "number") {
3399
4580
  return String(value);
@@ -3444,11 +4625,11 @@ function buildWantedLevelSet(levels) {
3444
4625
  return set.size > 0 ? set : null;
3445
4626
  }
3446
4627
  function readJsonLinesLastPid(filePath, maxLines, offset, levels) {
3447
- const stat = fs17.statSync(filePath);
4628
+ const stat = fs19.statSync(filePath);
3448
4629
  if (stat.size === 0) {
3449
4630
  return { lines: [], totalLinesCount: 0 };
3450
4631
  }
3451
- const fd = fs17.openSync(filePath, "r");
4632
+ const fd = fs19.openSync(filePath, "r");
3452
4633
  const chunkSize = 64 * 1024;
3453
4634
  let position = stat.size;
3454
4635
  let remainder = "";
@@ -3463,7 +4644,7 @@ function readJsonLinesLastPid(filePath, maxLines, offset, levels) {
3463
4644
  const length = Math.min(chunkSize, position);
3464
4645
  position -= length;
3465
4646
  const buffer = Buffer.alloc(length);
3466
- fs17.readSync(fd, buffer, 0, length, position);
4647
+ fs19.readSync(fd, buffer, 0, length, position);
3467
4648
  let chunk = buffer.toString("utf8");
3468
4649
  if (remainder) {
3469
4650
  chunk += remainder;
@@ -3525,7 +4706,7 @@ function readJsonLinesLastPid(filePath, maxLines, offset, levels) {
3525
4706
  }
3526
4707
  }
3527
4708
  } finally {
3528
- fs17.closeSync(fd);
4709
+ fs19.closeSync(fd);
3529
4710
  }
3530
4711
  return { lines: collected.reverse(), totalLinesCount };
3531
4712
  }
@@ -3568,11 +4749,11 @@ function extractTraceId(obj) {
3568
4749
  function readJsonLinesByTraceId(filePath, traceId, maxLines, offset, levels) {
3569
4750
  const wanted = traceId.trim();
3570
4751
  if (!wanted) return { lines: [], totalLinesCount: 0 };
3571
- const stat = fs17.statSync(filePath);
4752
+ const stat = fs19.statSync(filePath);
3572
4753
  if (stat.size === 0) {
3573
4754
  return { lines: [], totalLinesCount: 0 };
3574
4755
  }
3575
- const fd = fs17.openSync(filePath, "r");
4756
+ const fd = fs19.openSync(filePath, "r");
3576
4757
  const chunkSize = 64 * 1024;
3577
4758
  let position = stat.size;
3578
4759
  let remainder = "";
@@ -3585,7 +4766,7 @@ function readJsonLinesByTraceId(filePath, traceId, maxLines, offset, levels) {
3585
4766
  const length = Math.min(chunkSize, position);
3586
4767
  position -= length;
3587
4768
  const buffer = Buffer.alloc(length);
3588
- fs17.readSync(fd, buffer, 0, length, position);
4769
+ fs19.readSync(fd, buffer, 0, length, position);
3589
4770
  let chunk = buffer.toString("utf8");
3590
4771
  if (remainder) {
3591
4772
  chunk += remainder;
@@ -3638,7 +4819,7 @@ function readJsonLinesByTraceId(filePath, traceId, maxLines, offset, levels) {
3638
4819
  }
3639
4820
  }
3640
4821
  } finally {
3641
- fs17.closeSync(fd);
4822
+ fs19.closeSync(fd);
3642
4823
  }
3643
4824
  return { lines: collected.reverse(), totalLinesCount };
3644
4825
  }
@@ -3647,11 +4828,11 @@ function readJsonLinesTailByLevel(filePath, maxLines, offset, levels) {
3647
4828
  if (!wantedLevelSet) {
3648
4829
  return { lines: [], totalLinesCount: 0 };
3649
4830
  }
3650
- const stat = fs17.statSync(filePath);
4831
+ const stat = fs19.statSync(filePath);
3651
4832
  if (stat.size === 0) {
3652
4833
  return { lines: [], totalLinesCount: 0 };
3653
4834
  }
3654
- const fd = fs17.openSync(filePath, "r");
4835
+ const fd = fs19.openSync(filePath, "r");
3655
4836
  const chunkSize = 64 * 1024;
3656
4837
  let position = stat.size;
3657
4838
  let remainder = "";
@@ -3663,7 +4844,7 @@ function readJsonLinesTailByLevel(filePath, maxLines, offset, levels) {
3663
4844
  const length = Math.min(chunkSize, position);
3664
4845
  position -= length;
3665
4846
  const buffer = Buffer.alloc(length);
3666
- fs17.readSync(fd, buffer, 0, length, position);
4847
+ fs19.readSync(fd, buffer, 0, length, position);
3667
4848
  let chunk = buffer.toString("utf8");
3668
4849
  if (remainder) {
3669
4850
  chunk += remainder;
@@ -3710,7 +4891,7 @@ function readJsonLinesTailByLevel(filePath, maxLines, offset, levels) {
3710
4891
  }
3711
4892
  }
3712
4893
  } finally {
3713
- fs17.closeSync(fd);
4894
+ fs19.closeSync(fd);
3714
4895
  }
3715
4896
  return { lines: collected.reverse(), totalLinesCount };
3716
4897
  }
@@ -3841,21 +5022,21 @@ async function readLogsJsonResult(options) {
3841
5022
  };
3842
5023
  }
3843
5024
  function resolveLogFilePath(logDir, type) {
3844
- const base = path15.isAbsolute(logDir) ? logDir : path15.join(process.cwd(), logDir);
5025
+ const base = path16.isAbsolute(logDir) ? logDir : path16.join(process.cwd(), logDir);
3845
5026
  if (type === "server") {
3846
- return path15.join(base, "server.log");
5027
+ return path16.join(base, "server.log");
3847
5028
  }
3848
5029
  if (type === "trace") {
3849
- return path15.join(base, "trace.log");
5030
+ return path16.join(base, "trace.log");
3850
5031
  }
3851
5032
  if (type === "server-std") {
3852
- return path15.join(base, "server.std.log");
5033
+ return path16.join(base, "server.std.log");
3853
5034
  }
3854
5035
  if (type === "client-std") {
3855
- return path15.join(base, "client.std.log");
5036
+ return path16.join(base, "client.std.log");
3856
5037
  }
3857
5038
  if (type === "browser") {
3858
- return path15.join(base, "browser.log");
5039
+ return path16.join(base, "browser.log");
3859
5040
  }
3860
5041
  throw new Error(`Unsupported log type: ${type}`);
3861
5042
  }
@@ -3930,12 +5111,12 @@ var commands = [
3930
5111
  ];
3931
5112
 
3932
5113
  // src/index.ts
3933
- var envPath = path16.join(process.cwd(), ".env");
3934
- if (fs18.existsSync(envPath)) {
5114
+ var envPath = path17.join(process.cwd(), ".env");
5115
+ if (fs20.existsSync(envPath)) {
3935
5116
  dotenvConfig({ path: envPath });
3936
5117
  }
3937
- var __dirname = path16.dirname(fileURLToPath3(import.meta.url));
3938
- var pkg = JSON.parse(fs18.readFileSync(path16.join(__dirname, "../package.json"), "utf-8"));
5118
+ var __dirname = path17.dirname(fileURLToPath4(import.meta.url));
5119
+ var pkg = JSON.parse(fs20.readFileSync(path17.join(__dirname, "../package.json"), "utf-8"));
3939
5120
  var cli = new FullstackCLI(pkg.version);
3940
5121
  cli.useAll(commands);
3941
5122
  cli.run();