@lark-apaas/fullstack-cli 1.1.13-alpha.0 → 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
  }
@@ -897,6 +2078,7 @@ async function install(namesWithVersion) {
897
2078
  }
898
2079
  const results = [];
899
2080
  for (const nameWithVersion of namesWithVersion) {
2081
+ console.log(`[action-plugin] Processing ${nameWithVersion}...`);
900
2082
  const result = await installOne(nameWithVersion);
901
2083
  results.push(result);
902
2084
  }
@@ -1097,39 +2279,39 @@ var actionPluginCommandGroup = {
1097
2279
  };
1098
2280
 
1099
2281
  // src/commands/capability/utils.ts
1100
- import fs6 from "fs";
1101
- import path6 from "path";
2282
+ import fs8 from "fs";
2283
+ import path7 from "path";
1102
2284
  var CAPABILITIES_DIR = "server/capabilities";
1103
2285
  function getProjectRoot2() {
1104
2286
  return process.cwd();
1105
2287
  }
1106
2288
  function getCapabilitiesDir() {
1107
- return path6.join(getProjectRoot2(), CAPABILITIES_DIR);
2289
+ return path7.join(getProjectRoot2(), CAPABILITIES_DIR);
1108
2290
  }
1109
2291
  function getCapabilityPath(id) {
1110
- return path6.join(getCapabilitiesDir(), `${id}.json`);
2292
+ return path7.join(getCapabilitiesDir(), `${id}.json`);
1111
2293
  }
1112
2294
  function getPluginManifestPath(pluginKey) {
1113
- return path6.join(getProjectRoot2(), "node_modules", pluginKey, "manifest.json");
2295
+ return path7.join(getProjectRoot2(), "node_modules", pluginKey, "manifest.json");
1114
2296
  }
1115
2297
  function capabilitiesDirExists() {
1116
- return fs6.existsSync(getCapabilitiesDir());
2298
+ return fs8.existsSync(getCapabilitiesDir());
1117
2299
  }
1118
2300
  function listCapabilityIds() {
1119
2301
  const dir = getCapabilitiesDir();
1120
- if (!fs6.existsSync(dir)) {
2302
+ if (!fs8.existsSync(dir)) {
1121
2303
  return [];
1122
2304
  }
1123
- const files = fs6.readdirSync(dir);
2305
+ const files = fs8.readdirSync(dir);
1124
2306
  return files.filter((f) => f.endsWith(".json")).map((f) => f.replace(/\.json$/, ""));
1125
2307
  }
1126
2308
  function readCapability(id) {
1127
2309
  const filePath = getCapabilityPath(id);
1128
- if (!fs6.existsSync(filePath)) {
2310
+ if (!fs8.existsSync(filePath)) {
1129
2311
  throw new Error(`Capability not found: ${id}`);
1130
2312
  }
1131
2313
  try {
1132
- const content = fs6.readFileSync(filePath, "utf-8");
2314
+ const content = fs8.readFileSync(filePath, "utf-8");
1133
2315
  return JSON.parse(content);
1134
2316
  } catch (error) {
1135
2317
  if (error instanceof SyntaxError) {
@@ -1144,11 +2326,11 @@ function readAllCapabilities() {
1144
2326
  }
1145
2327
  function readPluginManifest(pluginKey) {
1146
2328
  const manifestPath = getPluginManifestPath(pluginKey);
1147
- if (!fs6.existsSync(manifestPath)) {
2329
+ if (!fs8.existsSync(manifestPath)) {
1148
2330
  throw new Error(`Plugin not installed: ${pluginKey} (manifest.json not found)`);
1149
2331
  }
1150
2332
  try {
1151
- const content = fs6.readFileSync(manifestPath, "utf-8");
2333
+ const content = fs8.readFileSync(manifestPath, "utf-8");
1152
2334
  return JSON.parse(content);
1153
2335
  } catch (error) {
1154
2336
  if (error instanceof SyntaxError) {
@@ -1322,58 +2504,58 @@ var capabilityCommandGroup = {
1322
2504
  };
1323
2505
 
1324
2506
  // src/commands/migration/version-manager.ts
1325
- import fs7 from "fs";
1326
- import path7 from "path";
2507
+ import fs9 from "fs";
2508
+ import path8 from "path";
1327
2509
  var PACKAGE_JSON = "package.json";
1328
2510
  var VERSION_FIELD = "migrationVersion";
1329
2511
  function getPackageJsonPath2() {
1330
- return path7.join(process.cwd(), PACKAGE_JSON);
2512
+ return path8.join(process.cwd(), PACKAGE_JSON);
1331
2513
  }
1332
2514
  function getCurrentVersion() {
1333
2515
  const pkgPath = getPackageJsonPath2();
1334
- if (!fs7.existsSync(pkgPath)) {
2516
+ if (!fs9.existsSync(pkgPath)) {
1335
2517
  throw new Error("package.json not found");
1336
2518
  }
1337
- const pkg2 = JSON.parse(fs7.readFileSync(pkgPath, "utf-8"));
2519
+ const pkg2 = JSON.parse(fs9.readFileSync(pkgPath, "utf-8"));
1338
2520
  return pkg2[VERSION_FIELD] ?? 0;
1339
2521
  }
1340
2522
  function setCurrentVersion(version) {
1341
2523
  const pkgPath = getPackageJsonPath2();
1342
- const pkg2 = JSON.parse(fs7.readFileSync(pkgPath, "utf-8"));
2524
+ const pkg2 = JSON.parse(fs9.readFileSync(pkgPath, "utf-8"));
1343
2525
  pkg2[VERSION_FIELD] = version;
1344
- fs7.writeFileSync(pkgPath, JSON.stringify(pkg2, null, 2) + "\n", "utf-8");
2526
+ fs9.writeFileSync(pkgPath, JSON.stringify(pkg2, null, 2) + "\n", "utf-8");
1345
2527
  }
1346
2528
 
1347
2529
  // src/commands/migration/versions/v001_capability/json-migrator/detector.ts
1348
- import fs9 from "fs";
1349
- import path9 from "path";
2530
+ import fs11 from "fs";
2531
+ import path10 from "path";
1350
2532
 
1351
2533
  // src/commands/migration/versions/v001_capability/utils.ts
1352
- import fs8 from "fs";
1353
- import path8 from "path";
2534
+ import fs10 from "fs";
2535
+ import path9 from "path";
1354
2536
  var CAPABILITIES_DIR2 = "server/capabilities";
1355
2537
  function getProjectRoot3() {
1356
2538
  return process.cwd();
1357
2539
  }
1358
2540
  function getCapabilitiesDir2() {
1359
- return path8.join(getProjectRoot3(), CAPABILITIES_DIR2);
2541
+ return path9.join(getProjectRoot3(), CAPABILITIES_DIR2);
1360
2542
  }
1361
2543
  function getPluginManifestPath2(pluginKey) {
1362
- return path8.join(getProjectRoot3(), "node_modules", pluginKey, "manifest.json");
2544
+ return path9.join(getProjectRoot3(), "node_modules", pluginKey, "manifest.json");
1363
2545
  }
1364
2546
 
1365
2547
  // src/commands/migration/versions/v001_capability/json-migrator/detector.ts
1366
2548
  function detectJsonMigration() {
1367
2549
  const capabilitiesDir = getCapabilitiesDir2();
1368
- const oldFilePath = path9.join(capabilitiesDir, "capabilities.json");
1369
- if (!fs9.existsSync(oldFilePath)) {
2550
+ const oldFilePath = path10.join(capabilitiesDir, "capabilities.json");
2551
+ if (!fs11.existsSync(oldFilePath)) {
1370
2552
  return {
1371
2553
  needsMigration: false,
1372
2554
  reason: "capabilities.json not found"
1373
2555
  };
1374
2556
  }
1375
2557
  try {
1376
- const content = fs9.readFileSync(oldFilePath, "utf-8");
2558
+ const content = fs11.readFileSync(oldFilePath, "utf-8");
1377
2559
  const parsed = JSON.parse(content);
1378
2560
  const capabilities = Array.isArray(parsed) ? parsed : [];
1379
2561
  return {
@@ -1413,8 +2595,8 @@ async function check(options) {
1413
2595
  }
1414
2596
 
1415
2597
  // src/commands/migration/versions/v001_capability/json-migrator/index.ts
1416
- import fs10 from "fs";
1417
- import path10 from "path";
2598
+ import fs12 from "fs";
2599
+ import path11 from "path";
1418
2600
 
1419
2601
  // src/commands/migration/versions/v001_capability/mapping.ts
1420
2602
  var DEFAULT_PLUGIN_VERSION = "1.0.0";
@@ -1644,18 +2826,18 @@ function transformCapabilities(oldCapabilities) {
1644
2826
  // src/commands/migration/versions/v001_capability/json-migrator/index.ts
1645
2827
  function loadExistingCapabilities() {
1646
2828
  const capabilitiesDir = getCapabilitiesDir2();
1647
- if (!fs10.existsSync(capabilitiesDir)) {
2829
+ if (!fs12.existsSync(capabilitiesDir)) {
1648
2830
  return [];
1649
2831
  }
1650
- const files = fs10.readdirSync(capabilitiesDir);
2832
+ const files = fs12.readdirSync(capabilitiesDir);
1651
2833
  const capabilities = [];
1652
2834
  for (const file of files) {
1653
2835
  if (file === "capabilities.json" || !file.endsWith(".json")) {
1654
2836
  continue;
1655
2837
  }
1656
2838
  try {
1657
- const filePath = path10.join(capabilitiesDir, file);
1658
- const content = fs10.readFileSync(filePath, "utf-8");
2839
+ const filePath = path11.join(capabilitiesDir, file);
2840
+ const content = fs12.readFileSync(filePath, "utf-8");
1659
2841
  const capability = JSON.parse(content);
1660
2842
  if (capability.id && capability.pluginKey) {
1661
2843
  capabilities.push(capability);
@@ -1713,9 +2895,9 @@ async function migrateJsonFiles(options) {
1713
2895
  }
1714
2896
  const capabilitiesDir = getCapabilitiesDir2();
1715
2897
  for (const cap of newCapabilities) {
1716
- const filePath = path10.join(capabilitiesDir, `${cap.id}.json`);
2898
+ const filePath = path11.join(capabilitiesDir, `${cap.id}.json`);
1717
2899
  const content = JSON.stringify(cap, null, 2);
1718
- fs10.writeFileSync(filePath, content, "utf-8");
2900
+ fs12.writeFileSync(filePath, content, "utf-8");
1719
2901
  console.log(` \u2713 Created: ${cap.id}.json`);
1720
2902
  }
1721
2903
  return {
@@ -1727,10 +2909,11 @@ async function migrateJsonFiles(options) {
1727
2909
  }
1728
2910
 
1729
2911
  // src/commands/migration/versions/v001_capability/plugin-installer/detector.ts
1730
- import fs11 from "fs";
2912
+ import fs13 from "fs";
1731
2913
  function isPluginInstalled2(pluginKey) {
2914
+ const actionPlugins = readActionPlugins();
1732
2915
  const manifestPath = getPluginManifestPath2(pluginKey);
1733
- return fs11.existsSync(manifestPath);
2916
+ return fs13.existsSync(manifestPath) && !!actionPlugins[pluginKey];
1734
2917
  }
1735
2918
  function detectPluginsToInstall(capabilities) {
1736
2919
  const pluginKeys = /* @__PURE__ */ new Set();
@@ -1806,12 +2989,12 @@ async function installPlugins(capabilities, options) {
1806
2989
  }
1807
2990
 
1808
2991
  // src/commands/migration/versions/v001_capability/code-migrator/index.ts
1809
- import path12 from "path";
1810
- import { Project } from "ts-morph";
2992
+ import path13 from "path";
2993
+ import { Project as Project2 } from "ts-morph";
1811
2994
 
1812
2995
  // src/commands/migration/versions/v001_capability/code-migrator/scanner.ts
1813
- import fs12 from "fs";
1814
- import path11 from "path";
2996
+ import fs14 from "fs";
2997
+ import path12 from "path";
1815
2998
  var EXCLUDED_DIRS = [
1816
2999
  "node_modules",
1817
3000
  "dist",
@@ -1826,9 +3009,9 @@ var EXCLUDED_PATTERNS = [
1826
3009
  /\.d\.ts$/
1827
3010
  ];
1828
3011
  function scanDirectory(dir, files = []) {
1829
- const entries = fs12.readdirSync(dir, { withFileTypes: true });
3012
+ const entries = fs14.readdirSync(dir, { withFileTypes: true });
1830
3013
  for (const entry of entries) {
1831
- const fullPath = path11.join(dir, entry.name);
3014
+ const fullPath = path12.join(dir, entry.name);
1832
3015
  if (entry.isDirectory()) {
1833
3016
  if (EXCLUDED_DIRS.includes(entry.name)) {
1834
3017
  continue;
@@ -1844,14 +3027,14 @@ function scanDirectory(dir, files = []) {
1844
3027
  return files;
1845
3028
  }
1846
3029
  function scanServerFiles() {
1847
- const serverDir = path11.join(getProjectRoot3(), "server");
1848
- if (!fs12.existsSync(serverDir)) {
3030
+ const serverDir = path12.join(getProjectRoot3(), "server");
3031
+ if (!fs14.existsSync(serverDir)) {
1849
3032
  return [];
1850
3033
  }
1851
3034
  return scanDirectory(serverDir);
1852
3035
  }
1853
3036
  function hasCapabilityImport(filePath) {
1854
- const content = fs12.readFileSync(filePath, "utf-8");
3037
+ const content = fs14.readFileSync(filePath, "utf-8");
1855
3038
  return /import\s+.*from\s+['"][^'"]*capabilities[^'"]*['"]/.test(content);
1856
3039
  }
1857
3040
  function scanFilesToMigrate() {
@@ -2226,7 +3409,7 @@ function analyzeFile(project, filePath, actionNameMap) {
2226
3409
  const callSites = analyzeCallSites(sourceFile, imports);
2227
3410
  const classInfo = analyzeClass(sourceFile);
2228
3411
  const { canMigrate, reason } = canAutoMigrate(classInfo);
2229
- const relativePath = path12.relative(getProjectRoot3(), filePath);
3412
+ const relativePath = path13.relative(getProjectRoot3(), filePath);
2230
3413
  return {
2231
3414
  filePath: relativePath,
2232
3415
  imports,
@@ -2237,7 +3420,7 @@ function analyzeFile(project, filePath, actionNameMap) {
2237
3420
  };
2238
3421
  }
2239
3422
  function migrateFile(project, analysis, dryRun) {
2240
- const absolutePath = path12.join(getProjectRoot3(), analysis.filePath);
3423
+ const absolutePath = path13.join(getProjectRoot3(), analysis.filePath);
2241
3424
  if (!analysis.canAutoMigrate) {
2242
3425
  return {
2243
3426
  filePath: analysis.filePath,
@@ -2297,7 +3480,7 @@ async function migrateCode(options, capabilities) {
2297
3480
  console.log(" No files need code migration.\n");
2298
3481
  return result;
2299
3482
  }
2300
- const project = new Project({
3483
+ const project = new Project2({
2301
3484
  skipAddingFilesFromTsConfig: true,
2302
3485
  compilerOptions: {
2303
3486
  allowJs: true
@@ -2340,17 +3523,17 @@ function getSuggestion(analysis) {
2340
3523
  }
2341
3524
 
2342
3525
  // src/commands/migration/versions/v001_capability/cleanup.ts
2343
- import fs13 from "fs";
2344
- import path13 from "path";
3526
+ import fs15 from "fs";
3527
+ import path14 from "path";
2345
3528
  function cleanupOldFiles(capabilities, dryRun) {
2346
3529
  const deletedFiles = [];
2347
3530
  const errors = [];
2348
3531
  const capabilitiesDir = getCapabilitiesDir2();
2349
- const oldJsonPath = path13.join(capabilitiesDir, "capabilities.json");
2350
- if (fs13.existsSync(oldJsonPath)) {
3532
+ const oldJsonPath = path14.join(capabilitiesDir, "capabilities.json");
3533
+ if (fs15.existsSync(oldJsonPath)) {
2351
3534
  try {
2352
3535
  if (!dryRun) {
2353
- fs13.unlinkSync(oldJsonPath);
3536
+ fs15.unlinkSync(oldJsonPath);
2354
3537
  }
2355
3538
  deletedFiles.push("capabilities.json");
2356
3539
  } catch (error) {
@@ -2358,11 +3541,11 @@ function cleanupOldFiles(capabilities, dryRun) {
2358
3541
  }
2359
3542
  }
2360
3543
  for (const cap of capabilities) {
2361
- const tsFilePath = path13.join(capabilitiesDir, `${cap.id}.ts`);
2362
- if (fs13.existsSync(tsFilePath)) {
3544
+ const tsFilePath = path14.join(capabilitiesDir, `${cap.id}.ts`);
3545
+ if (fs15.existsSync(tsFilePath)) {
2363
3546
  try {
2364
3547
  if (!dryRun) {
2365
- fs13.unlinkSync(tsFilePath);
3548
+ fs15.unlinkSync(tsFilePath);
2366
3549
  }
2367
3550
  deletedFiles.push(`${cap.id}.ts`);
2368
3551
  } catch (error) {
@@ -2378,8 +3561,8 @@ function cleanupOldFiles(capabilities, dryRun) {
2378
3561
  }
2379
3562
 
2380
3563
  // src/commands/migration/versions/v001_capability/report-generator.ts
2381
- import fs14 from "fs";
2382
- import path14 from "path";
3564
+ import fs16 from "fs";
3565
+ import path15 from "path";
2383
3566
  var REPORT_FILE = "capability-migration-report.md";
2384
3567
  function printSummary(result) {
2385
3568
  const { jsonMigration, pluginInstallation, codeMigration, cleanup } = result;
@@ -2542,15 +3725,15 @@ async function generateReport(result) {
2542
3725
  }
2543
3726
  lines.push("");
2544
3727
  const logDir = process.env.LOG_DIR || "logs";
2545
- if (!fs14.existsSync(logDir)) {
3728
+ if (!fs16.existsSync(logDir)) {
2546
3729
  return;
2547
3730
  }
2548
- const reportDir = path14.join(logDir, "migration");
2549
- if (!fs14.existsSync(reportDir)) {
2550
- fs14.mkdirSync(reportDir, { recursive: true });
3731
+ const reportDir = path15.join(logDir, "migration");
3732
+ if (!fs16.existsSync(reportDir)) {
3733
+ fs16.mkdirSync(reportDir, { recursive: true });
2551
3734
  }
2552
- const reportPath = path14.join(reportDir, REPORT_FILE);
2553
- 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");
2554
3737
  console.log(`\u{1F4C4} Report generated: ${reportPath}`);
2555
3738
  }
2556
3739
 
@@ -3082,10 +4265,10 @@ var migrationCommand = {
3082
4265
  };
3083
4266
 
3084
4267
  // src/commands/read-logs/index.ts
3085
- import path15 from "path";
4268
+ import path16 from "path";
3086
4269
 
3087
4270
  // src/commands/read-logs/std-utils.ts
3088
- import fs15 from "fs";
4271
+ import fs17 from "fs";
3089
4272
  function formatStdPrefixTime(localTime) {
3090
4273
  const match = localTime.match(/^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/);
3091
4274
  if (!match) return localTime;
@@ -3115,11 +4298,11 @@ function stripPrefixFromStdLine(line) {
3115
4298
  return `[${time}] ${content}`;
3116
4299
  }
3117
4300
  function readStdLinesTailFromLastMarkerPaged(filePath, maxLines, offset, isMarker) {
3118
- const stat = fs15.statSync(filePath);
4301
+ const stat = fs17.statSync(filePath);
3119
4302
  if (stat.size === 0) {
3120
4303
  return { lines: [], markerFound: false, totalLinesCount: 0 };
3121
4304
  }
3122
- const fd = fs15.openSync(filePath, "r");
4305
+ const fd = fs17.openSync(filePath, "r");
3123
4306
  const chunkSize = 64 * 1024;
3124
4307
  let position = stat.size;
3125
4308
  let remainder = "";
@@ -3133,7 +4316,7 @@ function readStdLinesTailFromLastMarkerPaged(filePath, maxLines, offset, isMarke
3133
4316
  const length = Math.min(chunkSize, position);
3134
4317
  position -= length;
3135
4318
  const buffer = Buffer.alloc(length);
3136
- fs15.readSync(fd, buffer, 0, length, position);
4319
+ fs17.readSync(fd, buffer, 0, length, position);
3137
4320
  let chunk = buffer.toString("utf8");
3138
4321
  if (remainder) {
3139
4322
  chunk += remainder;
@@ -3175,7 +4358,7 @@ function readStdLinesTailFromLastMarkerPaged(filePath, maxLines, offset, isMarke
3175
4358
  }
3176
4359
  }
3177
4360
  } finally {
3178
- fs15.closeSync(fd);
4361
+ fs17.closeSync(fd);
3179
4362
  }
3180
4363
  return { lines: collected.reverse(), markerFound, totalLinesCount };
3181
4364
  }
@@ -3196,21 +4379,21 @@ function readServerStdSegment(filePath, maxLines, offset) {
3196
4379
  }
3197
4380
 
3198
4381
  // src/commands/read-logs/tail.ts
3199
- import fs16 from "fs";
4382
+ import fs18 from "fs";
3200
4383
  function fileExists(filePath) {
3201
4384
  try {
3202
- fs16.accessSync(filePath, fs16.constants.F_OK | fs16.constants.R_OK);
4385
+ fs18.accessSync(filePath, fs18.constants.F_OK | fs18.constants.R_OK);
3203
4386
  return true;
3204
4387
  } catch {
3205
4388
  return false;
3206
4389
  }
3207
4390
  }
3208
4391
  function readFileTailLines(filePath, maxLines) {
3209
- const stat = fs16.statSync(filePath);
4392
+ const stat = fs18.statSync(filePath);
3210
4393
  if (stat.size === 0) {
3211
4394
  return [];
3212
4395
  }
3213
- const fd = fs16.openSync(filePath, "r");
4396
+ const fd = fs18.openSync(filePath, "r");
3214
4397
  const chunkSize = 64 * 1024;
3215
4398
  const chunks = [];
3216
4399
  let position = stat.size;
@@ -3220,13 +4403,13 @@ function readFileTailLines(filePath, maxLines) {
3220
4403
  const length = Math.min(chunkSize, position);
3221
4404
  position -= length;
3222
4405
  const buffer = Buffer.alloc(length);
3223
- fs16.readSync(fd, buffer, 0, length, position);
4406
+ fs18.readSync(fd, buffer, 0, length, position);
3224
4407
  chunks.unshift(buffer.toString("utf8"));
3225
4408
  const chunkLines = buffer.toString("utf8").split("\n").length - 1;
3226
4409
  collectedLines += chunkLines;
3227
4410
  }
3228
4411
  } finally {
3229
- fs16.closeSync(fd);
4412
+ fs18.closeSync(fd);
3230
4413
  }
3231
4414
  const content = chunks.join("");
3232
4415
  const allLines = content.split("\n");
@@ -3242,11 +4425,11 @@ function readFileTailLines(filePath, maxLines) {
3242
4425
  return allLines.slice(allLines.length - maxLines);
3243
4426
  }
3244
4427
  function readFileTailNonEmptyLinesWithOffset(filePath, maxLines, offset) {
3245
- const stat = fs16.statSync(filePath);
4428
+ const stat = fs18.statSync(filePath);
3246
4429
  if (stat.size === 0) {
3247
4430
  return { lines: [], totalLinesCount: 0 };
3248
4431
  }
3249
- const fd = fs16.openSync(filePath, "r");
4432
+ const fd = fs18.openSync(filePath, "r");
3250
4433
  const chunkSize = 64 * 1024;
3251
4434
  let position = stat.size;
3252
4435
  let remainder = "";
@@ -3258,7 +4441,7 @@ function readFileTailNonEmptyLinesWithOffset(filePath, maxLines, offset) {
3258
4441
  const length = Math.min(chunkSize, position);
3259
4442
  position -= length;
3260
4443
  const buffer = Buffer.alloc(length);
3261
- fs16.readSync(fd, buffer, 0, length, position);
4444
+ fs18.readSync(fd, buffer, 0, length, position);
3262
4445
  let chunk = buffer.toString("utf8");
3263
4446
  if (remainder) {
3264
4447
  chunk += remainder;
@@ -3289,7 +4472,7 @@ function readFileTailNonEmptyLinesWithOffset(filePath, maxLines, offset) {
3289
4472
  }
3290
4473
  }
3291
4474
  } finally {
3292
- fs16.closeSync(fd);
4475
+ fs18.closeSync(fd);
3293
4476
  }
3294
4477
  return { lines: collected.reverse(), totalLinesCount };
3295
4478
  }
@@ -3391,7 +4574,7 @@ function extractClientStdSegment(lines, maxLines, offset) {
3391
4574
  }
3392
4575
 
3393
4576
  // src/commands/read-logs/json-lines.ts
3394
- import fs17 from "fs";
4577
+ import fs19 from "fs";
3395
4578
  function normalizePid(value) {
3396
4579
  if (typeof value === "number") {
3397
4580
  return String(value);
@@ -3442,11 +4625,11 @@ function buildWantedLevelSet(levels) {
3442
4625
  return set.size > 0 ? set : null;
3443
4626
  }
3444
4627
  function readJsonLinesLastPid(filePath, maxLines, offset, levels) {
3445
- const stat = fs17.statSync(filePath);
4628
+ const stat = fs19.statSync(filePath);
3446
4629
  if (stat.size === 0) {
3447
4630
  return { lines: [], totalLinesCount: 0 };
3448
4631
  }
3449
- const fd = fs17.openSync(filePath, "r");
4632
+ const fd = fs19.openSync(filePath, "r");
3450
4633
  const chunkSize = 64 * 1024;
3451
4634
  let position = stat.size;
3452
4635
  let remainder = "";
@@ -3461,7 +4644,7 @@ function readJsonLinesLastPid(filePath, maxLines, offset, levels) {
3461
4644
  const length = Math.min(chunkSize, position);
3462
4645
  position -= length;
3463
4646
  const buffer = Buffer.alloc(length);
3464
- fs17.readSync(fd, buffer, 0, length, position);
4647
+ fs19.readSync(fd, buffer, 0, length, position);
3465
4648
  let chunk = buffer.toString("utf8");
3466
4649
  if (remainder) {
3467
4650
  chunk += remainder;
@@ -3523,7 +4706,7 @@ function readJsonLinesLastPid(filePath, maxLines, offset, levels) {
3523
4706
  }
3524
4707
  }
3525
4708
  } finally {
3526
- fs17.closeSync(fd);
4709
+ fs19.closeSync(fd);
3527
4710
  }
3528
4711
  return { lines: collected.reverse(), totalLinesCount };
3529
4712
  }
@@ -3566,11 +4749,11 @@ function extractTraceId(obj) {
3566
4749
  function readJsonLinesByTraceId(filePath, traceId, maxLines, offset, levels) {
3567
4750
  const wanted = traceId.trim();
3568
4751
  if (!wanted) return { lines: [], totalLinesCount: 0 };
3569
- const stat = fs17.statSync(filePath);
4752
+ const stat = fs19.statSync(filePath);
3570
4753
  if (stat.size === 0) {
3571
4754
  return { lines: [], totalLinesCount: 0 };
3572
4755
  }
3573
- const fd = fs17.openSync(filePath, "r");
4756
+ const fd = fs19.openSync(filePath, "r");
3574
4757
  const chunkSize = 64 * 1024;
3575
4758
  let position = stat.size;
3576
4759
  let remainder = "";
@@ -3583,7 +4766,7 @@ function readJsonLinesByTraceId(filePath, traceId, maxLines, offset, levels) {
3583
4766
  const length = Math.min(chunkSize, position);
3584
4767
  position -= length;
3585
4768
  const buffer = Buffer.alloc(length);
3586
- fs17.readSync(fd, buffer, 0, length, position);
4769
+ fs19.readSync(fd, buffer, 0, length, position);
3587
4770
  let chunk = buffer.toString("utf8");
3588
4771
  if (remainder) {
3589
4772
  chunk += remainder;
@@ -3636,7 +4819,7 @@ function readJsonLinesByTraceId(filePath, traceId, maxLines, offset, levels) {
3636
4819
  }
3637
4820
  }
3638
4821
  } finally {
3639
- fs17.closeSync(fd);
4822
+ fs19.closeSync(fd);
3640
4823
  }
3641
4824
  return { lines: collected.reverse(), totalLinesCount };
3642
4825
  }
@@ -3645,11 +4828,11 @@ function readJsonLinesTailByLevel(filePath, maxLines, offset, levels) {
3645
4828
  if (!wantedLevelSet) {
3646
4829
  return { lines: [], totalLinesCount: 0 };
3647
4830
  }
3648
- const stat = fs17.statSync(filePath);
4831
+ const stat = fs19.statSync(filePath);
3649
4832
  if (stat.size === 0) {
3650
4833
  return { lines: [], totalLinesCount: 0 };
3651
4834
  }
3652
- const fd = fs17.openSync(filePath, "r");
4835
+ const fd = fs19.openSync(filePath, "r");
3653
4836
  const chunkSize = 64 * 1024;
3654
4837
  let position = stat.size;
3655
4838
  let remainder = "";
@@ -3661,7 +4844,7 @@ function readJsonLinesTailByLevel(filePath, maxLines, offset, levels) {
3661
4844
  const length = Math.min(chunkSize, position);
3662
4845
  position -= length;
3663
4846
  const buffer = Buffer.alloc(length);
3664
- fs17.readSync(fd, buffer, 0, length, position);
4847
+ fs19.readSync(fd, buffer, 0, length, position);
3665
4848
  let chunk = buffer.toString("utf8");
3666
4849
  if (remainder) {
3667
4850
  chunk += remainder;
@@ -3708,7 +4891,7 @@ function readJsonLinesTailByLevel(filePath, maxLines, offset, levels) {
3708
4891
  }
3709
4892
  }
3710
4893
  } finally {
3711
- fs17.closeSync(fd);
4894
+ fs19.closeSync(fd);
3712
4895
  }
3713
4896
  return { lines: collected.reverse(), totalLinesCount };
3714
4897
  }
@@ -3839,21 +5022,21 @@ async function readLogsJsonResult(options) {
3839
5022
  };
3840
5023
  }
3841
5024
  function resolveLogFilePath(logDir, type) {
3842
- const base = path15.isAbsolute(logDir) ? logDir : path15.join(process.cwd(), logDir);
5025
+ const base = path16.isAbsolute(logDir) ? logDir : path16.join(process.cwd(), logDir);
3843
5026
  if (type === "server") {
3844
- return path15.join(base, "server.log");
5027
+ return path16.join(base, "server.log");
3845
5028
  }
3846
5029
  if (type === "trace") {
3847
- return path15.join(base, "trace.log");
5030
+ return path16.join(base, "trace.log");
3848
5031
  }
3849
5032
  if (type === "server-std") {
3850
- return path15.join(base, "server.std.log");
5033
+ return path16.join(base, "server.std.log");
3851
5034
  }
3852
5035
  if (type === "client-std") {
3853
- return path15.join(base, "client.std.log");
5036
+ return path16.join(base, "client.std.log");
3854
5037
  }
3855
5038
  if (type === "browser") {
3856
- return path15.join(base, "browser.log");
5039
+ return path16.join(base, "browser.log");
3857
5040
  }
3858
5041
  throw new Error(`Unsupported log type: ${type}`);
3859
5042
  }
@@ -3928,12 +5111,12 @@ var commands = [
3928
5111
  ];
3929
5112
 
3930
5113
  // src/index.ts
3931
- var envPath = path16.join(process.cwd(), ".env");
3932
- if (fs18.existsSync(envPath)) {
5114
+ var envPath = path17.join(process.cwd(), ".env");
5115
+ if (fs20.existsSync(envPath)) {
3933
5116
  dotenvConfig({ path: envPath });
3934
5117
  }
3935
- var __dirname = path16.dirname(fileURLToPath3(import.meta.url));
3936
- 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"));
3937
5120
  var cli = new FullstackCLI(pkg.version);
3938
5121
  cli.useAll(commands);
3939
5122
  cli.run();