yg-team-cli 2.3.0 → 2.3.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/cli.js +346 -134
- package/dist/cli.js.map +1 -1
- package/dist/index.js +338 -133
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -264,6 +264,12 @@ var init_utils = __esm({
|
|
|
264
264
|
static async writeJson(file, data) {
|
|
265
265
|
await fs.writeJson(file, data, { spaces: 2 });
|
|
266
266
|
}
|
|
267
|
+
/**
|
|
268
|
+
* 获取路径的目录名 (ESM 兼容)
|
|
269
|
+
*/
|
|
270
|
+
static getDirName(url) {
|
|
271
|
+
return path2.dirname(new URL(url).pathname);
|
|
272
|
+
}
|
|
267
273
|
};
|
|
268
274
|
StringUtils2 = class {
|
|
269
275
|
/**
|
|
@@ -310,6 +316,12 @@ var init_utils = __esm({
|
|
|
310
316
|
static slugify(str) {
|
|
311
317
|
return str.toLowerCase().trim().replace(/[^\w\s-]/g, "").replace(/[\s_-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
312
318
|
}
|
|
319
|
+
/**
|
|
320
|
+
* 验证项目名称
|
|
321
|
+
*/
|
|
322
|
+
static validateProjectName(name) {
|
|
323
|
+
return /^[a-z0-9-]+$/.test(name);
|
|
324
|
+
}
|
|
313
325
|
};
|
|
314
326
|
DateUtils = class _DateUtils {
|
|
315
327
|
/**
|
|
@@ -428,7 +440,7 @@ __export(user_config_exports, {
|
|
|
428
440
|
UserConfigManager: () => UserConfigManager,
|
|
429
441
|
userConfigManager: () => userConfigManager
|
|
430
442
|
});
|
|
431
|
-
import
|
|
443
|
+
import path6 from "path";
|
|
432
444
|
import os2 from "os";
|
|
433
445
|
import crypto from "crypto";
|
|
434
446
|
var UserConfigManager, userConfigManager;
|
|
@@ -441,8 +453,8 @@ var init_user_config = __esm({
|
|
|
441
453
|
UserConfigManager = class {
|
|
442
454
|
configPath;
|
|
443
455
|
constructor() {
|
|
444
|
-
const configDir =
|
|
445
|
-
this.configPath =
|
|
456
|
+
const configDir = path6.join(os2.homedir(), ".team-cli");
|
|
457
|
+
this.configPath = path6.join(configDir, "config.json");
|
|
446
458
|
}
|
|
447
459
|
/**
|
|
448
460
|
* 加载用户配置
|
|
@@ -469,7 +481,7 @@ var init_user_config = __esm({
|
|
|
469
481
|
*/
|
|
470
482
|
async save(config) {
|
|
471
483
|
try {
|
|
472
|
-
const configDir =
|
|
484
|
+
const configDir = path6.dirname(this.configPath);
|
|
473
485
|
await FileUtils.ensureDir(configDir);
|
|
474
486
|
const configToSave = JSON.parse(JSON.stringify(config));
|
|
475
487
|
if (configToSave.gitlab?.accessToken) {
|
|
@@ -575,7 +587,7 @@ var init_user_config = __esm({
|
|
|
575
587
|
* 获取配置目录
|
|
576
588
|
*/
|
|
577
589
|
getConfigDir() {
|
|
578
|
-
return
|
|
590
|
+
return path6.dirname(this.configPath);
|
|
579
591
|
}
|
|
580
592
|
/**
|
|
581
593
|
* 获取配置文件路径
|
|
@@ -790,22 +802,22 @@ var init_gitlab_api = __esm({
|
|
|
790
802
|
* 从 Git URL 中提取项目路径
|
|
791
803
|
*/
|
|
792
804
|
static parseProjectPath(repository) {
|
|
793
|
-
let
|
|
794
|
-
if (
|
|
795
|
-
|
|
796
|
-
const colonIndex =
|
|
805
|
+
let path20 = repository;
|
|
806
|
+
if (path20.startsWith("git@")) {
|
|
807
|
+
path20 = path20.replace(/^git@/, "");
|
|
808
|
+
const colonIndex = path20.indexOf(":");
|
|
797
809
|
if (colonIndex !== -1) {
|
|
798
|
-
|
|
810
|
+
path20 = path20.substring(colonIndex + 1);
|
|
799
811
|
}
|
|
800
812
|
} else {
|
|
801
|
-
|
|
802
|
-
const parts =
|
|
813
|
+
path20 = path20.replace(/^https?:\/\//, "");
|
|
814
|
+
const parts = path20.split("/");
|
|
803
815
|
if (parts.length > 1) {
|
|
804
|
-
|
|
816
|
+
path20 = parts.slice(1).join("/");
|
|
805
817
|
}
|
|
806
818
|
}
|
|
807
|
-
|
|
808
|
-
return
|
|
819
|
+
path20 = path20.replace(/\.git$/, "");
|
|
820
|
+
return path20;
|
|
809
821
|
}
|
|
810
822
|
/**
|
|
811
823
|
* 编码项目路径用于 API 请求
|
|
@@ -861,14 +873,17 @@ init_esm_shims();
|
|
|
861
873
|
init_logger();
|
|
862
874
|
import { Command as Command16 } from "commander";
|
|
863
875
|
import chalk4 from "chalk";
|
|
876
|
+
import fs6 from "fs-extra";
|
|
877
|
+
import path19 from "path";
|
|
878
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
864
879
|
|
|
865
880
|
// src/commands/init.ts
|
|
866
881
|
init_esm_shims();
|
|
867
882
|
init_logger();
|
|
868
883
|
import { Command } from "commander";
|
|
869
884
|
import inquirer from "inquirer";
|
|
870
|
-
import
|
|
871
|
-
import
|
|
885
|
+
import path7 from "path";
|
|
886
|
+
import fs4 from "fs-extra";
|
|
872
887
|
|
|
873
888
|
// src/lib/claude.ts
|
|
874
889
|
init_esm_shims();
|
|
@@ -1323,6 +1338,128 @@ async function updateTemplateVersion(projectPath, type, commit, options) {
|
|
|
1323
1338
|
await saveTemplateConfig(projectPath, config);
|
|
1324
1339
|
}
|
|
1325
1340
|
|
|
1341
|
+
// src/lib/module-registry.ts
|
|
1342
|
+
init_esm_shims();
|
|
1343
|
+
init_utils();
|
|
1344
|
+
import path5 from "path";
|
|
1345
|
+
import fs3 from "fs-extra";
|
|
1346
|
+
var ModuleManager = class {
|
|
1347
|
+
static MODULES = [
|
|
1348
|
+
{
|
|
1349
|
+
id: "acl",
|
|
1350
|
+
name: "ACL (Access Control List)",
|
|
1351
|
+
description: "\u57FA\u4E8E\u89D2\u8272\u7684\u8BBF\u95EE\u63A7\u5236\u6A21\u5757\uFF08\u672C\u5730\u6A21\u677F\u7248\uFF09",
|
|
1352
|
+
type: "local",
|
|
1353
|
+
specs: ["acl/spec.md"],
|
|
1354
|
+
backendFragments: [
|
|
1355
|
+
{
|
|
1356
|
+
source: "acl/backend/AclResultCode.java",
|
|
1357
|
+
target: "common/enums/AclResultCode.java"
|
|
1358
|
+
},
|
|
1359
|
+
{
|
|
1360
|
+
source: "acl/backend/RequiredPermission.java",
|
|
1361
|
+
target: "common/annotation/RequiredPermission.java"
|
|
1362
|
+
}
|
|
1363
|
+
]
|
|
1364
|
+
},
|
|
1365
|
+
{
|
|
1366
|
+
id: "permission-remote",
|
|
1367
|
+
name: "\u6743\u9650\u7BA1\u7406 (\u8FDC\u7A0B MCP \u7248)",
|
|
1368
|
+
description: "\u4ECE api-metadata \u5B9E\u65F6\u83B7\u53D6\u6700\u65B0\u6743\u9650\u63A5\u53E3\u5B9A\u4E49\u5E76\u751F\u6210\u4EE3\u7801",
|
|
1369
|
+
type: "remote",
|
|
1370
|
+
mcpServer: "api-metadata",
|
|
1371
|
+
specs: ["permission-remote/spec.md"]
|
|
1372
|
+
},
|
|
1373
|
+
{
|
|
1374
|
+
id: "audit-log",
|
|
1375
|
+
name: "\u5BA1\u8BA1\u65E5\u5FD7 (Audit Log)",
|
|
1376
|
+
description: "\u8BB0\u5F55\u7528\u6237\u64CD\u4F5C\u65E5\u5FD7\uFF0C\u652F\u6301 AOP \u81EA\u52A8\u62E6\u622A\u548C\u5F02\u6B65\u5B58\u50A8",
|
|
1377
|
+
type: "local",
|
|
1378
|
+
specs: ["audit-log/spec.md"]
|
|
1379
|
+
}
|
|
1380
|
+
];
|
|
1381
|
+
/**
|
|
1382
|
+
* 获取所有可用模块
|
|
1383
|
+
*/
|
|
1384
|
+
static getAvailableModules() {
|
|
1385
|
+
return [...this.MODULES];
|
|
1386
|
+
}
|
|
1387
|
+
/**
|
|
1388
|
+
* 根据 ID 获取模块
|
|
1389
|
+
*/
|
|
1390
|
+
static getModuleById(id) {
|
|
1391
|
+
return this.MODULES.find((m) => m.id === id);
|
|
1392
|
+
}
|
|
1393
|
+
/**
|
|
1394
|
+
* 注入模块到项目
|
|
1395
|
+
*/
|
|
1396
|
+
static async injectModule(projectPath, moduleId, templatesDir) {
|
|
1397
|
+
const module = this.getModuleById(moduleId);
|
|
1398
|
+
if (!module) return;
|
|
1399
|
+
for (const specRelPath of module.specs) {
|
|
1400
|
+
const sourcePath = path5.join(templatesDir, "modules", specRelPath);
|
|
1401
|
+
const targetPath = path5.join(projectPath, "docs/specs", path5.basename(specRelPath));
|
|
1402
|
+
if (await FileUtils.exists(sourcePath)) {
|
|
1403
|
+
await FileUtils.copy(sourcePath, targetPath);
|
|
1404
|
+
} else if (module.type === "remote") {
|
|
1405
|
+
await this.generateRemoteSpecPlaceholder(targetPath, module);
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
if (module.type === "local" && module.backendFragments) {
|
|
1409
|
+
const backendBase = path5.join(projectPath, "backend/src/main/java");
|
|
1410
|
+
const basePackagePath = await this.findBasePackage(backendBase);
|
|
1411
|
+
if (basePackagePath) {
|
|
1412
|
+
for (const fragment of module.backendFragments) {
|
|
1413
|
+
const sourcePath = path5.join(templatesDir, "modules", fragment.source);
|
|
1414
|
+
const targetPath = path5.join(basePackagePath, fragment.target);
|
|
1415
|
+
if (await FileUtils.exists(sourcePath)) {
|
|
1416
|
+
await FileUtils.ensureDir(path5.dirname(targetPath));
|
|
1417
|
+
await FileUtils.copy(sourcePath, targetPath);
|
|
1418
|
+
}
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1421
|
+
} else if (module.type === "remote") {
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
/**
|
|
1425
|
+
* 生成远程模块的 Spec 占位符
|
|
1426
|
+
*/
|
|
1427
|
+
static async generateRemoteSpecPlaceholder(targetPath, module) {
|
|
1428
|
+
const content = `# ${module.name} (Remote)
|
|
1429
|
+
|
|
1430
|
+
## \u529F\u80FD\u6982\u8FF0
|
|
1431
|
+
\u8BE5\u6A21\u5757\u901A\u8FC7\u8FDC\u7A0B MCP \u670D\u52A1 \`${module.mcpServer}\` \u83B7\u53D6\u5B9E\u65F6\u5143\u6570\u636E\u3002
|
|
1432
|
+
|
|
1433
|
+
## \u4F7F\u7528\u8BF4\u660E
|
|
1434
|
+
1. \u786E\u4FDD\u5DF2\u5B89\u88C5\u5E76\u914D\u7F6E MCP \u670D\u52A1\u3002
|
|
1435
|
+
2. \u8FD0\u884C \`team-cli dev\` \u5E76\u9009\u62E9\u6B64 Spec\u3002
|
|
1436
|
+
3. Claude \u5C06\u81EA\u52A8\u8C03\u7528 MCP \u83B7\u53D6\u6700\u65B0\u7684 API \u4FE1\u606F\u5E76\u5B8C\u6210\u5B9E\u73B0\u3002
|
|
1437
|
+
`;
|
|
1438
|
+
await FileUtils.write(targetPath, content);
|
|
1439
|
+
}
|
|
1440
|
+
/**
|
|
1441
|
+
* 自动探测项目的 Base Package
|
|
1442
|
+
*/
|
|
1443
|
+
static async findBasePackage(searchDir) {
|
|
1444
|
+
if (!await FileUtils.exists(searchDir)) return null;
|
|
1445
|
+
const files = await FileUtils.findFiles("**/Application.java", searchDir);
|
|
1446
|
+
if (files.length > 0) {
|
|
1447
|
+
return path5.dirname(path5.join(searchDir, files[0]));
|
|
1448
|
+
}
|
|
1449
|
+
let current = searchDir;
|
|
1450
|
+
while (true) {
|
|
1451
|
+
const items = await fs3.readdir(current);
|
|
1452
|
+
const dirs = items.filter((c) => fs3.statSync(path5.join(current, c)).isDirectory());
|
|
1453
|
+
if (dirs.length === 1 && !["model", "controller", "service", "mapper", "config", "common"].includes(dirs[0])) {
|
|
1454
|
+
current = path5.join(current, dirs[0]);
|
|
1455
|
+
} else {
|
|
1456
|
+
break;
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
return current;
|
|
1460
|
+
}
|
|
1461
|
+
};
|
|
1462
|
+
|
|
1326
1463
|
// src/commands/init.ts
|
|
1327
1464
|
var initCommand = new Command("init").argument("[project-name]", "\u9879\u76EE\u540D\u79F0").description("\u521D\u59CB\u5316\u65B0\u9879\u76EE").option("-d, --dir <directory>", "\u9879\u76EE\u76EE\u5F55", ".").option("--no-docker", "\u4E0D\u751F\u6210 Docker \u914D\u7F6E").option("--no-git", "\u4E0D\u521D\u59CB\u5316 Git").option("--tag <tag>", "\u6307\u5B9A\u6A21\u677F\u6807\u7B7E (\u524D\u540E\u7AEF\u901A\u7528)").option("--backend-tag <tag>", "\u6307\u5B9A\u540E\u7AEF\u6A21\u677F\u6807\u7B7E").option("--frontend-tag <tag>", "\u6307\u5B9A\u524D\u7AEF\u6A21\u677F\u6807\u7B7E").option("--backend-branch <branch>", "\u6307\u5B9A\u540E\u7AEF\u6A21\u677F\u5206\u652F").option("--frontend-branch <branch>", "\u6307\u5B9A\u524D\u7AEF\u6A21\u677F\u5206\u652F").action(async (projectName, options) => {
|
|
1328
1465
|
try {
|
|
@@ -1355,7 +1492,19 @@ var initCommand = new Command("init").argument("[project-name]", "\u9879\u76EE\u
|
|
|
1355
1492
|
logger.info("\u8BF7\u5B89\u88C5 Claude CLI: npm install -g @anthropic-ai/claude-code");
|
|
1356
1493
|
process.exit(1);
|
|
1357
1494
|
}
|
|
1358
|
-
const projectPath =
|
|
1495
|
+
const projectPath = path7.resolve(options.dir, projectName);
|
|
1496
|
+
const availableModules = ModuleManager.getAvailableModules();
|
|
1497
|
+
const { selectedModules } = await inquirer.prompt([
|
|
1498
|
+
{
|
|
1499
|
+
type: "checkbox",
|
|
1500
|
+
name: "selectedModules",
|
|
1501
|
+
message: "\u8BF7\u9009\u62E9\u8981\u5F00\u542F\u7684\u5185\u7F6E\u901A\u7528\u6A21\u5757:",
|
|
1502
|
+
choices: availableModules.map((m) => ({
|
|
1503
|
+
name: `${m.name} - ${m.description}`,
|
|
1504
|
+
value: m.id
|
|
1505
|
+
}))
|
|
1506
|
+
}
|
|
1507
|
+
]);
|
|
1359
1508
|
if (await FileUtils.exists(projectPath)) {
|
|
1360
1509
|
logger.error(`\u76EE\u5F55\u5DF2\u5B58\u5728: ${projectPath}`);
|
|
1361
1510
|
logger.info("\u8BF7\u9009\u62E9\u5176\u4ED6\u9879\u76EE\u540D\u79F0\u6216\u5220\u9664\u73B0\u6709\u76EE\u5F55");
|
|
@@ -1374,11 +1523,11 @@ var initCommand = new Command("init").argument("[project-name]", "\u9879\u76EE\u
|
|
|
1374
1523
|
title: "\u521B\u5EFA\u9879\u76EE\u76EE\u5F55",
|
|
1375
1524
|
task: async () => {
|
|
1376
1525
|
await FileUtils.ensureDir(projectPath);
|
|
1377
|
-
await FileUtils.ensureDir(
|
|
1378
|
-
await FileUtils.ensureDir(
|
|
1379
|
-
await FileUtils.ensureDir(
|
|
1380
|
-
await FileUtils.ensureDir(
|
|
1381
|
-
await FileUtils.ensureDir(
|
|
1526
|
+
await FileUtils.ensureDir(path7.join(projectPath, "frontend"));
|
|
1527
|
+
await FileUtils.ensureDir(path7.join(projectPath, "backend"));
|
|
1528
|
+
await FileUtils.ensureDir(path7.join(projectPath, "docs/specs"));
|
|
1529
|
+
await FileUtils.ensureDir(path7.join(projectPath, "docs/api"));
|
|
1530
|
+
await FileUtils.ensureDir(path7.join(projectPath, "docs/sessions"));
|
|
1382
1531
|
}
|
|
1383
1532
|
},
|
|
1384
1533
|
{
|
|
@@ -1426,7 +1575,7 @@ var initCommand = new Command("init").argument("[project-name]", "\u9879\u76EE\u
|
|
|
1426
1575
|
{
|
|
1427
1576
|
title: "\u751F\u6210 Docker \u914D\u7F6E",
|
|
1428
1577
|
task: async () => {
|
|
1429
|
-
await generateDockerFiles(
|
|
1578
|
+
await generateDockerFiles();
|
|
1430
1579
|
}
|
|
1431
1580
|
}
|
|
1432
1581
|
] : [],
|
|
@@ -1437,7 +1586,61 @@ var initCommand = new Command("init").argument("[project-name]", "\u9879\u76EE\u
|
|
|
1437
1586
|
await initGit(projectPath, projectName);
|
|
1438
1587
|
}
|
|
1439
1588
|
}
|
|
1440
|
-
] : []
|
|
1589
|
+
] : [],
|
|
1590
|
+
{
|
|
1591
|
+
title: "\u6CE8\u518C\u8FDC\u7A0B MCP \u670D\u52A1",
|
|
1592
|
+
task: async () => {
|
|
1593
|
+
const hasRemoteModule = selectedModules.some(
|
|
1594
|
+
(id) => ModuleManager.getModuleById(id)?.type === "remote"
|
|
1595
|
+
);
|
|
1596
|
+
if (hasRemoteModule) {
|
|
1597
|
+
const mcpCmd = 'claude_m2 mcp add --transport sse --header "Authorization: Bearer mcp_00557dabb71297b4f9ac5fe748395f2c" -- api-metadata https://api-metadata.yungu.org/sse';
|
|
1598
|
+
const { execaCommand } = await import("execa");
|
|
1599
|
+
try {
|
|
1600
|
+
await execaCommand(mcpCmd);
|
|
1601
|
+
logger.info("\u8FDC\u7A0B MCP \u670D\u52A1 api-metadata \u5DF2\u6CE8\u518C");
|
|
1602
|
+
} catch (err) {
|
|
1603
|
+
logger.warn("\u8FDC\u7A0B MCP \u670D\u52A1\u6CE8\u518C\u5931\u8D25\uFF0C\u53EF\u80FD\u5DF2\u5B58\u5728\u6216\u6743\u9650\u4E0D\u8DB3");
|
|
1604
|
+
}
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1607
|
+
},
|
|
1608
|
+
{
|
|
1609
|
+
title: "\u6CE8\u5165\u901A\u7528\u6A21\u5757",
|
|
1610
|
+
task: async () => {
|
|
1611
|
+
if (selectedModules.length === 0) return;
|
|
1612
|
+
const templatesDir = path7.resolve(FileUtils.getDirName(import.meta.url), "../templates");
|
|
1613
|
+
for (const moduleId of selectedModules) {
|
|
1614
|
+
await ModuleManager.injectModule(projectPath, moduleId, templatesDir);
|
|
1615
|
+
logger.info(`\u6CE8\u5165\u6A21\u5757: ${moduleId}`);
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
},
|
|
1619
|
+
{
|
|
1620
|
+
title: "\u6267\u884C\u8FDC\u7A0B\u6A21\u5757\u4EE3\u7801\u751F\u6210",
|
|
1621
|
+
task: async () => {
|
|
1622
|
+
const remoteModules = selectedModules.map((id) => ModuleManager.getModuleById(id)).filter((m) => m?.type === "remote");
|
|
1623
|
+
if (remoteModules.length === 0) return;
|
|
1624
|
+
const { execaCommand } = await import("execa");
|
|
1625
|
+
for (const module of remoteModules) {
|
|
1626
|
+
if (!module) continue;
|
|
1627
|
+
logger.info(`\u6B63\u5728\u4E3A\u60A8\u751F\u6210 ${module.name} \u7684\u8FDC\u7A0B\u8C03\u7528\u4EE3\u7801...`);
|
|
1628
|
+
const prompt = `\u4F7F\u7528 api-metadata MCP \u5DE5\u5177\u83B7\u53D6\u6240\u6709\u4E0E "${module.id.replace("-remote", "")}" \u76F8\u5173\u7684 API \u5143\u6570\u636E\u3002
|
|
1629
|
+
\u7136\u540E\u5728\u9879\u76EE\u8DEF\u5F84 \`${projectPath}\` \u7684\u540E\u7AEF\u76EE\u5F55\u4E2D\uFF0C\u76F4\u63A5\u751F\u6210\u5BF9\u5E94\u7684 Java \u8C03\u7528\u4EE3\u7801\uFF08\u5982 Feign Client \u6216 RestTemplate \u5C01\u88C5\uFF09\u3002
|
|
1630
|
+
\u8BF7\u786E\u4FDD\u4EE3\u7801\u7B26\u5408 \`CONVENTIONS.md\` \u4E2D\u7684\u89C4\u8303\u3002
|
|
1631
|
+
\u751F\u6210\u5B8C\u6210\u540E\uFF0C\u8BF7\u7B80\u8981\u5217\u51FA\u751F\u6210\u7684\u6587\u4EF6\u3002`;
|
|
1632
|
+
try {
|
|
1633
|
+
await execaCommand(`claude_m2 -p "${prompt}" --add-dir ${projectPath}`, {
|
|
1634
|
+
stdio: "inherit",
|
|
1635
|
+
timeout: 3e5
|
|
1636
|
+
// 5分钟超时
|
|
1637
|
+
});
|
|
1638
|
+
} catch (err) {
|
|
1639
|
+
logger.error(`${module.name} \u4EE3\u7801\u751F\u6210\u5931\u8D25\uFF0C\u60A8\u53EF\u4EE5\u7A0D\u540E\u5728\u5F00\u53D1\u6A21\u5F0F\u4E0B\u624B\u52A8\u8FD0\u884C\u3002`);
|
|
1640
|
+
}
|
|
1641
|
+
}
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1441
1644
|
],
|
|
1442
1645
|
{
|
|
1443
1646
|
concurrent: false,
|
|
@@ -1558,7 +1761,7 @@ docs/
|
|
|
1558
1761
|
\u2514\u2500\u2500 sessions/ # \u5F00\u53D1\u4F1A\u8BDD\u8BB0\u5F55
|
|
1559
1762
|
\`\`\`
|
|
1560
1763
|
`;
|
|
1561
|
-
await FileUtils.write(
|
|
1764
|
+
await FileUtils.write(path7.join(projectPath, "TECH_STACK.md"), content);
|
|
1562
1765
|
}
|
|
1563
1766
|
async function generateConventions(projectPath) {
|
|
1564
1767
|
const content = `# \u5F00\u53D1\u89C4\u8303
|
|
@@ -1861,7 +2064,7 @@ test('renders user name', () => {
|
|
|
1861
2064
|
});
|
|
1862
2065
|
\`\`\`
|
|
1863
2066
|
`;
|
|
1864
|
-
await FileUtils.write(
|
|
2067
|
+
await FileUtils.write(path7.join(projectPath, "CONVENTIONS.md"), content);
|
|
1865
2068
|
}
|
|
1866
2069
|
async function generateAIMemory(projectPath, projectName) {
|
|
1867
2070
|
const content = `# AI Memory - \u9879\u76EE\u72B6\u6001\u8BB0\u5F55
|
|
@@ -1920,7 +2123,7 @@ async function generateAIMemory(projectPath, projectName) {
|
|
|
1920
2123
|
| Bug ID | \u65E5\u671F | \u95EE\u9898\u63CF\u8FF0 | \u72B6\u6001 |
|
|
1921
2124
|
|--------|------|---------|------|
|
|
1922
2125
|
`;
|
|
1923
|
-
await FileUtils.write(
|
|
2126
|
+
await FileUtils.write(path7.join(projectPath, "AI_MEMORY.md"), content);
|
|
1924
2127
|
}
|
|
1925
2128
|
async function generateSpecTemplate(projectPath) {
|
|
1926
2129
|
const content = `# [\u529F\u80FD\u6807\u9898]
|
|
@@ -1984,14 +2187,14 @@ async function generateSpecTemplate(projectPath) {
|
|
|
1984
2187
|
----
|
|
1985
2188
|
*\u751F\u6210\u4E8E: {{TIMESTAMP}} by team-cli*
|
|
1986
2189
|
`;
|
|
1987
|
-
await FileUtils.write(
|
|
2190
|
+
await FileUtils.write(path7.join(projectPath, "docs/specs/template.md"), content);
|
|
1988
2191
|
}
|
|
1989
2192
|
async function cloneBackendTemplate(projectPath, versionOptions) {
|
|
1990
2193
|
const templateRepo = process.env.TEMPLATE_REPO || "git@gitlab.yungu-inc.org:yungu-app/java-scaffold-template.git";
|
|
1991
|
-
const backendPath =
|
|
2194
|
+
const backendPath = path7.join(projectPath, "backend");
|
|
1992
2195
|
try {
|
|
1993
2196
|
const { execaCommand } = await import("execa");
|
|
1994
|
-
const tempDir =
|
|
2197
|
+
const tempDir = path7.join(projectPath, ".template-temp");
|
|
1995
2198
|
if (versionOptions?.tag || versionOptions?.branch) {
|
|
1996
2199
|
const { userConfigManager: userConfigManager2 } = await Promise.resolve().then(() => (init_user_config(), user_config_exports));
|
|
1997
2200
|
const { GitLabAPI: GitLabAPI2 } = await Promise.resolve().then(() => (init_gitlab_api(), gitlab_api_exports));
|
|
@@ -2034,11 +2237,11 @@ async function cloneBackendTemplate(projectPath, versionOptions) {
|
|
|
2034
2237
|
stdio: "pipe"
|
|
2035
2238
|
});
|
|
2036
2239
|
const latestTag = tags.split("\n")[0] || void 0;
|
|
2037
|
-
await
|
|
2240
|
+
await fs4.copy(tempDir, backendPath, {
|
|
2038
2241
|
filter: (src) => !src.includes(".git")
|
|
2039
2242
|
});
|
|
2040
|
-
await
|
|
2041
|
-
const gitDir =
|
|
2243
|
+
await fs4.remove(tempDir);
|
|
2244
|
+
const gitDir = path7.join(backendPath, ".git");
|
|
2042
2245
|
if (await FileUtils.exists(gitDir)) {
|
|
2043
2246
|
await FileUtils.remove(gitDir);
|
|
2044
2247
|
}
|
|
@@ -2049,13 +2252,13 @@ async function cloneBackendTemplate(projectPath, versionOptions) {
|
|
|
2049
2252
|
});
|
|
2050
2253
|
} catch (error) {
|
|
2051
2254
|
logger.warn("\u514B\u9686\u540E\u7AEF\u6A21\u677F\u5931\u8D25\uFF0C\u521B\u5EFA\u57FA\u7840\u7ED3\u6784");
|
|
2052
|
-
await FileUtils.ensureDir(
|
|
2053
|
-
await FileUtils.ensureDir(
|
|
2054
|
-
await FileUtils.ensureDir(
|
|
2255
|
+
await FileUtils.ensureDir(path7.join(backendPath, "src/main/java/com/example"));
|
|
2256
|
+
await FileUtils.ensureDir(path7.join(backendPath, "src/main/resources"));
|
|
2257
|
+
await FileUtils.ensureDir(path7.join(backendPath, "src/test/java"));
|
|
2055
2258
|
}
|
|
2056
2259
|
}
|
|
2057
2260
|
async function generateFrontendScaffold(projectPath) {
|
|
2058
|
-
const frontendPath =
|
|
2261
|
+
const frontendPath = path7.join(projectPath, "frontend");
|
|
2059
2262
|
try {
|
|
2060
2263
|
const prompt = `Read TECH_STACK.md and CONVENTIONS.md.
|
|
2061
2264
|
Initialize a Next.js 14 frontend in ./frontend with:
|
|
@@ -2068,19 +2271,19 @@ Initialize a Next.js 14 frontend in ./frontend with:
|
|
|
2068
2271
|
Do not run any servers, just generate the folder structure and configuration files.`;
|
|
2069
2272
|
await claudeAI.prompt(prompt, {
|
|
2070
2273
|
contextFiles: [
|
|
2071
|
-
|
|
2072
|
-
|
|
2274
|
+
path7.join(projectPath, "TECH_STACK.md"),
|
|
2275
|
+
path7.join(projectPath, "CONVENTIONS.md")
|
|
2073
2276
|
]
|
|
2074
2277
|
});
|
|
2075
2278
|
} catch (error) {
|
|
2076
2279
|
logger.warn("Claude \u751F\u6210\u524D\u7AEF\u5931\u8D25\uFF0C\u5C06\u521B\u5EFA\u57FA\u7840\u7ED3\u6784");
|
|
2077
|
-
await FileUtils.ensureDir(
|
|
2078
|
-
await FileUtils.ensureDir(
|
|
2079
|
-
await FileUtils.ensureDir(
|
|
2080
|
-
await FileUtils.ensureDir(
|
|
2280
|
+
await FileUtils.ensureDir(path7.join(frontendPath, "src/app"));
|
|
2281
|
+
await FileUtils.ensureDir(path7.join(frontendPath, "src/components"));
|
|
2282
|
+
await FileUtils.ensureDir(path7.join(frontendPath, "src/lib"));
|
|
2283
|
+
await FileUtils.ensureDir(path7.join(frontendPath, "public"));
|
|
2081
2284
|
}
|
|
2082
2285
|
}
|
|
2083
|
-
async function generateDockerFiles(
|
|
2286
|
+
async function generateDockerFiles() {
|
|
2084
2287
|
logger.info("Docker \u914D\u7F6E\u751F\u6210\u5F85\u5B9E\u73B0");
|
|
2085
2288
|
}
|
|
2086
2289
|
async function initGit(projectPath, projectName) {
|
|
@@ -2104,7 +2307,7 @@ init_utils();
|
|
|
2104
2307
|
init_logger();
|
|
2105
2308
|
import { Command as Command2 } from "commander";
|
|
2106
2309
|
import inquirer2 from "inquirer";
|
|
2107
|
-
import
|
|
2310
|
+
import path8 from "path";
|
|
2108
2311
|
import { Listr as Listr2 } from "listr2";
|
|
2109
2312
|
var breakdownCommand = new Command2("breakdown").argument("[spec-file]", "Spec \u6587\u4EF6\u8DEF\u5F84").description("\u5C06 spec \u62C6\u5206\u4E3A milestones \u548C todos").action(async (specFile) => {
|
|
2110
2313
|
try {
|
|
@@ -2150,9 +2353,9 @@ var breakdownCommand = new Command2("breakdown").argument("[spec-file]", "Spec \
|
|
|
2150
2353
|
choices: ctx.specs
|
|
2151
2354
|
}
|
|
2152
2355
|
]);
|
|
2153
|
-
return
|
|
2356
|
+
return path8.join("docs/specs", selectedFile);
|
|
2154
2357
|
}
|
|
2155
|
-
const fullPath = specFile.startsWith("docs/specs/") ? specFile :
|
|
2358
|
+
const fullPath = specFile.startsWith("docs/specs/") ? specFile : path8.join("docs/specs", specFile);
|
|
2156
2359
|
const exists = await FileUtils.exists(fullPath);
|
|
2157
2360
|
if (!exists) {
|
|
2158
2361
|
throw new Error(`Spec \u6587\u4EF6\u4E0D\u5B58\u5728: ${specFile}`);
|
|
@@ -2284,7 +2487,7 @@ init_utils();
|
|
|
2284
2487
|
init_logger();
|
|
2285
2488
|
import { Command as Command3 } from "commander";
|
|
2286
2489
|
import inquirer3 from "inquirer";
|
|
2287
|
-
import
|
|
2490
|
+
import path9 from "path";
|
|
2288
2491
|
var devCommand = new Command3("dev").description("\u5F00\u53D1\u6A21\u5F0F\uFF0C\u6267\u884C\u5177\u4F53\u4EFB\u52A1").action(async () => {
|
|
2289
2492
|
try {
|
|
2290
2493
|
logger.header("\u5F00\u53D1\u6A21\u5F0F");
|
|
@@ -2329,7 +2532,7 @@ async function selectSpec() {
|
|
|
2329
2532
|
}
|
|
2330
2533
|
const specs = [];
|
|
2331
2534
|
for (let i = 0; i < specFiles.length; i++) {
|
|
2332
|
-
const file =
|
|
2535
|
+
const file = path9.join(specDir, specFiles[i]);
|
|
2333
2536
|
const spec = await FileUtils.read(file);
|
|
2334
2537
|
const status = parseSpecStatus(spec);
|
|
2335
2538
|
const dependencies = parseDependencies(spec);
|
|
@@ -2651,8 +2854,8 @@ async function generateSessionLog(specFile, milestone, todo, taskDescription, re
|
|
|
2651
2854
|
const sessionDir = "docs/sessions";
|
|
2652
2855
|
await FileUtils.ensureDir(sessionDir);
|
|
2653
2856
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
2654
|
-
const specName =
|
|
2655
|
-
const logFile =
|
|
2857
|
+
const specName = path9.basename(specFile, ".md");
|
|
2858
|
+
const logFile = path9.join(sessionDir, `${timestamp}_${specName}.md`);
|
|
2656
2859
|
const content = `# \u5F00\u53D1\u4F1A\u8BDD\u8BB0\u5F55
|
|
2657
2860
|
|
|
2658
2861
|
**\u65F6\u95F4**: ${(/* @__PURE__ */ new Date()).toLocaleString("zh-CN")}
|
|
@@ -2755,7 +2958,7 @@ init_utils();
|
|
|
2755
2958
|
init_logger();
|
|
2756
2959
|
import { Command as Command4 } from "commander";
|
|
2757
2960
|
import inquirer4 from "inquirer";
|
|
2758
|
-
import
|
|
2961
|
+
import path10 from "path";
|
|
2759
2962
|
import { Listr as Listr3 } from "listr2";
|
|
2760
2963
|
var addFeatureCommand = new Command4("add-feature").argument("<feature-name>", "\u529F\u80FD\u540D\u79F0").description("\u6DFB\u52A0\u65B0\u529F\u80FD\uFF08\u652F\u6301 PRD \u6216\u7B80\u5355\u63CF\u8FF0\u6A21\u5F0F\uFF09").action(async (featureName) => {
|
|
2761
2964
|
try {
|
|
@@ -2774,7 +2977,7 @@ var addFeatureCommand = new Command4("add-feature").argument("<feature-name>", "
|
|
|
2774
2977
|
process.exit(1);
|
|
2775
2978
|
}
|
|
2776
2979
|
const featureSlug = StringUtils2.toKebabCase(featureName);
|
|
2777
|
-
const specFile =
|
|
2980
|
+
const specFile = path10.join("docs/specs", `${featureSlug}.md`);
|
|
2778
2981
|
const specExists = await FileUtils.exists(specFile);
|
|
2779
2982
|
if (specExists) {
|
|
2780
2983
|
logger.error(`Spec \u6587\u4EF6\u5DF2\u5B58\u5728: ${specFile}`);
|
|
@@ -2833,7 +3036,7 @@ async function addFeatureFromPrd(featureName, featureSlug, specFile) {
|
|
|
2833
3036
|
const specs = files.filter((f) => !f.includes("template"));
|
|
2834
3037
|
ctx2.completedSpecs = [];
|
|
2835
3038
|
for (const file of specs) {
|
|
2836
|
-
const status = await SpecUtils.getSpecStatus(
|
|
3039
|
+
const status = await SpecUtils.getSpecStatus(path10.join(specDir, file));
|
|
2837
3040
|
if (status === "\u5DF2\u5B8C\u6210") {
|
|
2838
3041
|
ctx2.completedSpecs.push(file.replace(".md", ""));
|
|
2839
3042
|
}
|
|
@@ -2905,7 +3108,7 @@ async function addFeatureSimple(featureName, featureSlug, specFile) {
|
|
|
2905
3108
|
const specs = files.filter((f) => !f.includes("template"));
|
|
2906
3109
|
ctx2.completedSpecs = [];
|
|
2907
3110
|
for (const file of specs) {
|
|
2908
|
-
const status = await SpecUtils.getSpecStatus(
|
|
3111
|
+
const status = await SpecUtils.getSpecStatus(path10.join(specDir, file));
|
|
2909
3112
|
if (status === "\u5DF2\u5B8C\u6210") {
|
|
2910
3113
|
ctx2.completedSpecs.push(file.replace(".md", ""));
|
|
2911
3114
|
}
|
|
@@ -3002,7 +3205,7 @@ async function buildProjectContext() {
|
|
|
3002
3205
|
const files = await FileUtils.findFiles("*.md", "docs/specs");
|
|
3003
3206
|
const specs = files.filter((f) => !f.includes("template"));
|
|
3004
3207
|
for (const file of specs) {
|
|
3005
|
-
const status = await SpecUtils.getSpecStatus(
|
|
3208
|
+
const status = await SpecUtils.getSpecStatus(path10.join("docs/specs", file));
|
|
3006
3209
|
context.push(` - ${file.replace(".md", "")} [${status}]`);
|
|
3007
3210
|
}
|
|
3008
3211
|
}
|
|
@@ -3246,7 +3449,7 @@ init_esm_shims();
|
|
|
3246
3449
|
init_utils();
|
|
3247
3450
|
init_logger();
|
|
3248
3451
|
import { Command as Command5 } from "commander";
|
|
3249
|
-
import
|
|
3452
|
+
import path11 from "path";
|
|
3250
3453
|
import { Listr as Listr4 } from "listr2";
|
|
3251
3454
|
var splitPrdCommand = new Command5("split-prd").argument("<prd-folder>", "PRD \u6587\u6863\u76EE\u5F55").description("\u5C06 PRD \u62C6\u5206\u6210\u591A\u4E2A specs").action(async (prdFolder) => {
|
|
3252
3455
|
try {
|
|
@@ -3276,7 +3479,7 @@ var splitPrdCommand = new Command5("split-prd").argument("<prd-folder>", "PRD \u
|
|
|
3276
3479
|
ctx2.prdFiles = [];
|
|
3277
3480
|
for (const ext of supportedExtensions) {
|
|
3278
3481
|
const files = await FileUtils.findFiles(`*.${ext}`, prdFolder);
|
|
3279
|
-
ctx2.prdFiles.push(...files.map((f) =>
|
|
3482
|
+
ctx2.prdFiles.push(...files.map((f) => path11.join(prdFolder, f)));
|
|
3280
3483
|
}
|
|
3281
3484
|
if (ctx2.prdFiles.length === 0) {
|
|
3282
3485
|
throw new Error(
|
|
@@ -3294,7 +3497,7 @@ var splitPrdCommand = new Command5("split-prd").argument("<prd-folder>", "PRD \u
|
|
|
3294
3497
|
{
|
|
3295
3498
|
title: "\u626B\u63CF\u622A\u56FE\u6587\u4EF6",
|
|
3296
3499
|
task: async (ctx2) => {
|
|
3297
|
-
const screenshotDir =
|
|
3500
|
+
const screenshotDir = path11.join(prdFolder, "screenshots");
|
|
3298
3501
|
const dirExists = await FileUtils.exists(screenshotDir);
|
|
3299
3502
|
if (!dirExists) {
|
|
3300
3503
|
logger.info("\u672A\u627E\u5230 screenshots \u76EE\u5F55\uFF0C\u8DF3\u8FC7\u622A\u56FE");
|
|
@@ -3305,7 +3508,7 @@ var splitPrdCommand = new Command5("split-prd").argument("<prd-folder>", "PRD \u
|
|
|
3305
3508
|
ctx2.screenshots = [];
|
|
3306
3509
|
for (const ext of imageExtensions) {
|
|
3307
3510
|
const files = await FileUtils.findFiles(`*.${ext}`, screenshotDir);
|
|
3308
|
-
ctx2.screenshots.push(...files.map((f) =>
|
|
3511
|
+
ctx2.screenshots.push(...files.map((f) => path11.join(screenshotDir, f)));
|
|
3309
3512
|
}
|
|
3310
3513
|
logger.success(`\u627E\u5230 ${ctx2.screenshots.length} \u4E2A\u622A\u56FE\u6587\u4EF6`);
|
|
3311
3514
|
}
|
|
@@ -3316,8 +3519,8 @@ var splitPrdCommand = new Command5("split-prd").argument("<prd-folder>", "PRD \u
|
|
|
3316
3519
|
const entries = await FileUtils.findFiles("*/", prdFolder);
|
|
3317
3520
|
ctx2.demoRepos = [];
|
|
3318
3521
|
for (const entry of entries) {
|
|
3319
|
-
const dirPath =
|
|
3320
|
-
const gitDir =
|
|
3522
|
+
const dirPath = path11.join(prdFolder, entry);
|
|
3523
|
+
const gitDir = path11.join(dirPath, ".git");
|
|
3321
3524
|
const hasGit = await FileUtils.exists(gitDir);
|
|
3322
3525
|
if (hasGit) {
|
|
3323
3526
|
ctx2.demoRepos.push(dirPath);
|
|
@@ -3490,7 +3693,7 @@ init_utils();
|
|
|
3490
3693
|
init_logger();
|
|
3491
3694
|
import { Command as Command6 } from "commander";
|
|
3492
3695
|
import inquirer5 from "inquirer";
|
|
3493
|
-
import
|
|
3696
|
+
import path12 from "path";
|
|
3494
3697
|
import { Listr as Listr5 } from "listr2";
|
|
3495
3698
|
var bugfixCommand = new Command6("bugfix").description("\u521B\u5EFA Bugfix \u8BB0\u5F55").action(async () => {
|
|
3496
3699
|
try {
|
|
@@ -3539,7 +3742,7 @@ var bugfixCommand = new Command6("bugfix").description("\u521B\u5EFA Bugfix \u8B
|
|
|
3539
3742
|
const relatedSpec = await findRelatedSpec(answers.description);
|
|
3540
3743
|
const bugfixDir = "docs/bugfixes";
|
|
3541
3744
|
await FileUtils.ensureDir(bugfixDir);
|
|
3542
|
-
const bugfixFile =
|
|
3745
|
+
const bugfixFile = path12.join(bugfixDir, `${timestamp}_${bugId}.md`);
|
|
3543
3746
|
const content = formatBugfixDocument({
|
|
3544
3747
|
id: bugId,
|
|
3545
3748
|
severity: answers.severity,
|
|
@@ -3615,7 +3818,7 @@ var hotfixCommand = new Command6("hotfix").description("\u7D27\u6025\u4FEE\u590D
|
|
|
3615
3818
|
const timestamp = DateUtils.format(/* @__PURE__ */ new Date(), "YYYY-MM-DD HH:mm:ss");
|
|
3616
3819
|
const hotfixDir = "docs/hotfixes";
|
|
3617
3820
|
await FileUtils.ensureDir(hotfixDir);
|
|
3618
|
-
const hotfixFile =
|
|
3821
|
+
const hotfixFile = path12.join(hotfixDir, `${timestamp}_${hotfixId}.md`);
|
|
3619
3822
|
const content = formatHotfixDocument({
|
|
3620
3823
|
id: hotfixId,
|
|
3621
3824
|
description: answers.description,
|
|
@@ -3690,7 +3893,7 @@ async function findRelatedSpec(description) {
|
|
|
3690
3893
|
}
|
|
3691
3894
|
const keywords = extractKeywords(description);
|
|
3692
3895
|
for (const file of specs) {
|
|
3693
|
-
const filePath =
|
|
3896
|
+
const filePath = path12.join(specDir, file);
|
|
3694
3897
|
const content = await FileUtils.read(filePath);
|
|
3695
3898
|
for (const keyword of keywords) {
|
|
3696
3899
|
if (content.toLowerCase().includes(keyword.toLowerCase())) {
|
|
@@ -3908,7 +4111,7 @@ init_esm_shims();
|
|
|
3908
4111
|
init_utils();
|
|
3909
4112
|
init_logger();
|
|
3910
4113
|
import { Command as Command8 } from "commander";
|
|
3911
|
-
import
|
|
4114
|
+
import path13 from "path";
|
|
3912
4115
|
var statusCommand = new Command8("status").description("\u67E5\u770B\u9879\u76EE\u72B6\u6001").action(async () => {
|
|
3913
4116
|
try {
|
|
3914
4117
|
logger.header("\u9879\u76EE\u72B6\u6001");
|
|
@@ -3966,7 +4169,7 @@ async function displayFeatureInventory() {
|
|
|
3966
4169
|
}
|
|
3967
4170
|
const inventory = [];
|
|
3968
4171
|
for (const file of specs) {
|
|
3969
|
-
const filePath =
|
|
4172
|
+
const filePath = path13.join(specDir, file);
|
|
3970
4173
|
const content = await FileUtils.read(filePath);
|
|
3971
4174
|
const status = parseSpecStatus2(content);
|
|
3972
4175
|
inventory.push({
|
|
@@ -4025,7 +4228,7 @@ async function displayRecentActivity() {
|
|
|
4025
4228
|
}
|
|
4026
4229
|
const sorted = files.sort().reverse().slice(0, 5);
|
|
4027
4230
|
for (const file of sorted) {
|
|
4028
|
-
const filePath =
|
|
4231
|
+
const filePath = path13.join(sessionDir, file);
|
|
4029
4232
|
const stat = await FileUtils.read(filePath);
|
|
4030
4233
|
const specMatch = stat.match(/\*\*Spec\*\*:\s*(.+)/);
|
|
4031
4234
|
const spec = specMatch ? specMatch[1].trim() : "\u672A\u77E5";
|
|
@@ -4067,7 +4270,7 @@ init_esm_shims();
|
|
|
4067
4270
|
init_utils();
|
|
4068
4271
|
init_logger();
|
|
4069
4272
|
import { Command as Command9 } from "commander";
|
|
4070
|
-
import
|
|
4273
|
+
import path14 from "path";
|
|
4071
4274
|
import inquirer6 from "inquirer";
|
|
4072
4275
|
var detectDepsCommand = new Command9("detect-deps").argument("[spec-file]", "Spec \u6587\u4EF6\u8DEF\u5F84").description("\u68C0\u6D4B\u4F9D\u8D56\u5173\u7CFB").action(async (specFile) => {
|
|
4073
4276
|
try {
|
|
@@ -4095,7 +4298,7 @@ var detectDepsCommand = new Command9("detect-deps").argument("[spec-file]", "Spe
|
|
|
4095
4298
|
process.exit(1);
|
|
4096
4299
|
}
|
|
4097
4300
|
for (const spec of specs) {
|
|
4098
|
-
const specPath =
|
|
4301
|
+
const specPath = path14.join(specsDir, spec);
|
|
4099
4302
|
logger.step(`\u5904\u7406: ${spec}`);
|
|
4100
4303
|
await detectDependencies(specPath);
|
|
4101
4304
|
logger.newLine();
|
|
@@ -4121,7 +4324,7 @@ async function detectDependencies(specFile) {
|
|
|
4121
4324
|
logger.step("\u81EA\u52A8\u68C0\u6D4B\u4F9D\u8D56\u5173\u7CFB...");
|
|
4122
4325
|
const projectDir = ".";
|
|
4123
4326
|
const allDeps = /* @__PURE__ */ new Set();
|
|
4124
|
-
const backendDir =
|
|
4327
|
+
const backendDir = path14.join(projectDir, "backend");
|
|
4125
4328
|
const backendExists = await FileUtils.exists(backendDir);
|
|
4126
4329
|
if (backendExists) {
|
|
4127
4330
|
const apiDeps = await scanBackendApiCalls(backendDir);
|
|
@@ -4131,7 +4334,7 @@ async function detectDependencies(specFile) {
|
|
|
4131
4334
|
const serviceDeps = await scanBackendServiceRefs(backendDir);
|
|
4132
4335
|
serviceDeps.forEach((d) => allDeps.add(d));
|
|
4133
4336
|
}
|
|
4134
|
-
const frontendDir =
|
|
4337
|
+
const frontendDir = path14.join(projectDir, "frontend");
|
|
4135
4338
|
const frontendExists = await FileUtils.exists(frontendDir);
|
|
4136
4339
|
if (frontendExists) {
|
|
4137
4340
|
const frontendDeps = await scanFrontendApiCalls(frontendDir);
|
|
@@ -4172,11 +4375,11 @@ async function detectDependencies(specFile) {
|
|
|
4172
4375
|
}
|
|
4173
4376
|
async function scanBackendApiCalls(backendDir) {
|
|
4174
4377
|
const deps = [];
|
|
4175
|
-
const srcDir =
|
|
4378
|
+
const srcDir = path14.join(backendDir, "src");
|
|
4176
4379
|
try {
|
|
4177
4380
|
const javaFiles = await FileUtils.findFiles("*.java", srcDir);
|
|
4178
4381
|
for (const file of javaFiles) {
|
|
4179
|
-
const filePath =
|
|
4382
|
+
const filePath = path14.join(srcDir, file);
|
|
4180
4383
|
const content = await FileUtils.read(filePath);
|
|
4181
4384
|
const pathRegex = /"(\/api\/[^"]+)"/g;
|
|
4182
4385
|
let match;
|
|
@@ -4194,11 +4397,11 @@ async function scanBackendApiCalls(backendDir) {
|
|
|
4194
4397
|
}
|
|
4195
4398
|
async function scanBackendEntityRelations(backendDir) {
|
|
4196
4399
|
const deps = [];
|
|
4197
|
-
const srcDir =
|
|
4400
|
+
const srcDir = path14.join(backendDir, "src");
|
|
4198
4401
|
try {
|
|
4199
4402
|
const javaFiles = await FileUtils.findFiles("*.java", srcDir);
|
|
4200
4403
|
for (const file of javaFiles) {
|
|
4201
|
-
const filePath =
|
|
4404
|
+
const filePath = path14.join(srcDir, file);
|
|
4202
4405
|
const content = await FileUtils.read(filePath);
|
|
4203
4406
|
if (content.includes("@JoinColumn") || content.includes("@ManyToOne") || content.includes("@OneToMany")) {
|
|
4204
4407
|
const typeRegex = /type\s*=\s*(\w+)/g;
|
|
@@ -4214,11 +4417,11 @@ async function scanBackendEntityRelations(backendDir) {
|
|
|
4214
4417
|
}
|
|
4215
4418
|
async function scanBackendServiceRefs(backendDir) {
|
|
4216
4419
|
const deps = [];
|
|
4217
|
-
const srcDir =
|
|
4420
|
+
const srcDir = path14.join(backendDir, "src");
|
|
4218
4421
|
try {
|
|
4219
4422
|
const javaFiles = await FileUtils.findFiles("*.java", srcDir);
|
|
4220
4423
|
for (const file of javaFiles) {
|
|
4221
|
-
const filePath =
|
|
4424
|
+
const filePath = path14.join(srcDir, file);
|
|
4222
4425
|
const content = await FileUtils.read(filePath);
|
|
4223
4426
|
const serviceRegex = /private\s+(\w+)Service/g;
|
|
4224
4427
|
let match;
|
|
@@ -4234,11 +4437,11 @@ async function scanBackendServiceRefs(backendDir) {
|
|
|
4234
4437
|
}
|
|
4235
4438
|
async function scanFrontendApiCalls(frontendDir) {
|
|
4236
4439
|
const deps = [];
|
|
4237
|
-
const srcDir =
|
|
4440
|
+
const srcDir = path14.join(frontendDir, "src");
|
|
4238
4441
|
try {
|
|
4239
4442
|
const tsFiles = await FileUtils.findFiles("*.{ts,tsx,js,jsx}", srcDir);
|
|
4240
4443
|
for (const file of tsFiles) {
|
|
4241
|
-
const filePath =
|
|
4444
|
+
const filePath = path14.join(srcDir, file);
|
|
4242
4445
|
const content = await FileUtils.read(filePath);
|
|
4243
4446
|
const pathRegex = /"(\/api\/[^"]+)"/g;
|
|
4244
4447
|
let match;
|
|
@@ -4328,7 +4531,7 @@ init_esm_shims();
|
|
|
4328
4531
|
init_utils();
|
|
4329
4532
|
init_logger();
|
|
4330
4533
|
import { Command as Command10 } from "commander";
|
|
4331
|
-
import
|
|
4534
|
+
import path15 from "path";
|
|
4332
4535
|
var syncMemoryCommand = new Command10("sync-memory").description("\u540C\u6B65 AI_MEMORY.md").action(async () => {
|
|
4333
4536
|
try {
|
|
4334
4537
|
logger.header("\u540C\u6B65 AI_MEMORY.md");
|
|
@@ -4361,7 +4564,7 @@ var syncMemoryCommand = new Command10("sync-memory").description("\u540C\u6B65 A
|
|
|
4361
4564
|
});
|
|
4362
4565
|
async function syncFeatureInventory(aiMemoryFile, projectDir) {
|
|
4363
4566
|
logger.step("\u540C\u6B65\u529F\u80FD\u6E05\u5355...");
|
|
4364
|
-
const specsDir =
|
|
4567
|
+
const specsDir = path15.join(projectDir, "docs/specs");
|
|
4365
4568
|
const exists = await FileUtils.exists(specsDir);
|
|
4366
4569
|
if (!exists) {
|
|
4367
4570
|
return;
|
|
@@ -4376,7 +4579,7 @@ async function syncFeatureInventory(aiMemoryFile, projectDir) {
|
|
|
4376
4579
|
for (const specFile of specs) {
|
|
4377
4580
|
const name = specFile.replace(".md", "");
|
|
4378
4581
|
const displayName = name.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
4379
|
-
const specPath =
|
|
4582
|
+
const specPath = path15.join(specsDir, specFile);
|
|
4380
4583
|
const content = await FileUtils.read(specPath);
|
|
4381
4584
|
const status = parseSpecStatus3(content);
|
|
4382
4585
|
const progress = getSpecProgress(content);
|
|
@@ -4394,7 +4597,7 @@ async function syncFeatureInventory(aiMemoryFile, projectDir) {
|
|
|
4394
4597
|
}
|
|
4395
4598
|
async function syncApiInventory(aiMemoryFile, projectDir) {
|
|
4396
4599
|
logger.step("\u540C\u6B65 API \u5217\u8868...");
|
|
4397
|
-
const backendDir =
|
|
4600
|
+
const backendDir = path15.join(projectDir, "backend");
|
|
4398
4601
|
const exists = await FileUtils.exists(backendDir);
|
|
4399
4602
|
if (!exists) {
|
|
4400
4603
|
return;
|
|
@@ -4404,13 +4607,13 @@ async function syncApiInventory(aiMemoryFile, projectDir) {
|
|
|
4404
4607
|
lines.push("");
|
|
4405
4608
|
lines.push("> \u672C\u90E8\u5206\u7531 team-cli \u81EA\u52A8\u626B\u63CF\u540E\u7AEF Controller \u751F\u6210");
|
|
4406
4609
|
lines.push("");
|
|
4407
|
-
const srcDir =
|
|
4610
|
+
const srcDir = path15.join(backendDir, "src");
|
|
4408
4611
|
const controllers = await FileUtils.findFiles("*Controller.java", srcDir);
|
|
4409
4612
|
if (controllers.length === 0) {
|
|
4410
4613
|
lines.push("\u6682\u65E0 API");
|
|
4411
4614
|
} else {
|
|
4412
4615
|
for (const controllerFile of controllers) {
|
|
4413
|
-
const controllerPath =
|
|
4616
|
+
const controllerPath = path15.join(srcDir, controllerFile);
|
|
4414
4617
|
const controllerName = controllerFile.replace(".java", "");
|
|
4415
4618
|
const module = controllerName.replace(/Controller$/, "").toLowerCase();
|
|
4416
4619
|
lines.push(`### ${module} \u6A21\u5757`);
|
|
@@ -4487,7 +4690,7 @@ function extractMethodComment(content, methodName) {
|
|
|
4487
4690
|
}
|
|
4488
4691
|
async function syncDataModels(aiMemoryFile, projectDir) {
|
|
4489
4692
|
logger.step("\u540C\u6B65\u6570\u636E\u6A21\u578B...");
|
|
4490
|
-
const backendDir =
|
|
4693
|
+
const backendDir = path15.join(projectDir, "backend");
|
|
4491
4694
|
const exists = await FileUtils.exists(backendDir);
|
|
4492
4695
|
if (!exists) {
|
|
4493
4696
|
return;
|
|
@@ -4497,7 +4700,7 @@ async function syncDataModels(aiMemoryFile, projectDir) {
|
|
|
4497
4700
|
lines.push("");
|
|
4498
4701
|
lines.push("> \u672C\u90E8\u5206\u7531 team-cli \u81EA\u52A8\u626B\u63CF\u540E\u7AEF Entity \u751F\u6210");
|
|
4499
4702
|
lines.push("");
|
|
4500
|
-
const srcDir =
|
|
4703
|
+
const srcDir = path15.join(backendDir, "src");
|
|
4501
4704
|
const entities = await FileUtils.findFiles("*Entity.java", srcDir);
|
|
4502
4705
|
if (entities.length === 0) {
|
|
4503
4706
|
lines.push("\u6682\u65E0\u6570\u636E\u6A21\u578B");
|
|
@@ -4505,7 +4708,7 @@ async function syncDataModels(aiMemoryFile, projectDir) {
|
|
|
4505
4708
|
lines.push("| \u6A21\u578B | \u8BF4\u660E | \u5B57\u6BB5 | \u5173\u8054 |");
|
|
4506
4709
|
lines.push("|------|------|------|------|");
|
|
4507
4710
|
for (const entityFile of entities) {
|
|
4508
|
-
const entityPath =
|
|
4711
|
+
const entityPath = path15.join(srcDir, entityFile);
|
|
4509
4712
|
const entityName = entityFile.replace(".java", "").replace(/Entity$/, "");
|
|
4510
4713
|
const displayName = entityName.split(/(?=[A-Z])/).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ");
|
|
4511
4714
|
const content = await FileUtils.read(entityPath);
|
|
@@ -4627,15 +4830,15 @@ async function syncTemplateVersions(aiMemoryFile, projectDir) {
|
|
|
4627
4830
|
await replaceOrInsertSection(aiMemoryFile, "## \u6A21\u677F\u7248\u672C\u4FE1\u606F", newContent);
|
|
4628
4831
|
}
|
|
4629
4832
|
function extractRepoName(repository) {
|
|
4630
|
-
let
|
|
4631
|
-
|
|
4632
|
-
|
|
4633
|
-
const parts =
|
|
4833
|
+
let path20 = repository;
|
|
4834
|
+
path20 = path20.replace(/^https?:\/\//, "");
|
|
4835
|
+
path20 = path20.replace(/^git@/, "");
|
|
4836
|
+
const parts = path20.split("/");
|
|
4634
4837
|
if (parts.length > 1) {
|
|
4635
|
-
|
|
4838
|
+
path20 = parts.slice(1).join("/");
|
|
4636
4839
|
}
|
|
4637
|
-
|
|
4638
|
-
return
|
|
4840
|
+
path20 = path20.replace(/\.git$/, "");
|
|
4841
|
+
return path20;
|
|
4639
4842
|
}
|
|
4640
4843
|
|
|
4641
4844
|
// src/commands/check-api.ts
|
|
@@ -4643,7 +4846,7 @@ init_esm_shims();
|
|
|
4643
4846
|
init_utils();
|
|
4644
4847
|
init_logger();
|
|
4645
4848
|
import { Command as Command11 } from "commander";
|
|
4646
|
-
import
|
|
4849
|
+
import path16 from "path";
|
|
4647
4850
|
import inquirer7 from "inquirer";
|
|
4648
4851
|
import { Listr as Listr6 } from "listr2";
|
|
4649
4852
|
var checkApiCommand = new Command11("check-api").description("API \u68C0\u67E5\uFF08\u51B2\u7A81/\u53D8\u66F4/Registry\uFF09").action(async () => {
|
|
@@ -4707,7 +4910,7 @@ var checkApiCommand = new Command11("check-api").description("API \u68C0\u67E5\u
|
|
|
4707
4910
|
}
|
|
4708
4911
|
});
|
|
4709
4912
|
async function checkApiConflicts(projectDir) {
|
|
4710
|
-
const backendDir =
|
|
4913
|
+
const backendDir = path16.join(projectDir, "backend");
|
|
4711
4914
|
const exists = await FileUtils.exists(backendDir);
|
|
4712
4915
|
if (!exists) {
|
|
4713
4916
|
logger.info("\u672A\u627E\u5230\u540E\u7AEF\u9879\u76EE");
|
|
@@ -4716,10 +4919,10 @@ async function checkApiConflicts(projectDir) {
|
|
|
4716
4919
|
logger.step("\u626B\u63CF\u540E\u7AEF API...");
|
|
4717
4920
|
logger.newLine();
|
|
4718
4921
|
const apiMap = /* @__PURE__ */ new Map();
|
|
4719
|
-
const srcDir =
|
|
4922
|
+
const srcDir = path16.join(backendDir, "src");
|
|
4720
4923
|
const controllers = await FileUtils.findFiles("*Controller.java", srcDir);
|
|
4721
4924
|
for (const controllerFile of controllers) {
|
|
4722
|
-
const controllerPath =
|
|
4925
|
+
const controllerPath = path16.join(srcDir, controllerFile);
|
|
4723
4926
|
const apis = await extractApisFromController(controllerPath);
|
|
4724
4927
|
for (const api of apis) {
|
|
4725
4928
|
const key = `${api.method}:${api.path}`;
|
|
@@ -4750,8 +4953,8 @@ async function checkApiConflicts(projectDir) {
|
|
|
4750
4953
|
}
|
|
4751
4954
|
}
|
|
4752
4955
|
async function detectApiChanges(projectDir) {
|
|
4753
|
-
const backendDir =
|
|
4754
|
-
const registryFile =
|
|
4956
|
+
const backendDir = path16.join(projectDir, "backend");
|
|
4957
|
+
const registryFile = path16.join(projectDir, "docs/api-registry.md");
|
|
4755
4958
|
const registryExists = await FileUtils.exists(registryFile);
|
|
4756
4959
|
if (!registryExists) {
|
|
4757
4960
|
logger.info("API Registry \u4E0D\u5B58\u5728\uFF0C\u8DF3\u8FC7\u53D8\u66F4\u68C0\u6D4B");
|
|
@@ -4763,10 +4966,10 @@ async function detectApiChanges(projectDir) {
|
|
|
4763
4966
|
const registryContent = await FileUtils.read(registryFile);
|
|
4764
4967
|
const existingApis = extractApisFromRegistry(registryContent);
|
|
4765
4968
|
const currentApis = /* @__PURE__ */ new Map();
|
|
4766
|
-
const srcDir =
|
|
4969
|
+
const srcDir = path16.join(backendDir, "src");
|
|
4767
4970
|
const controllers = await FileUtils.findFiles("*Controller.java", srcDir);
|
|
4768
4971
|
for (const controllerFile of controllers) {
|
|
4769
|
-
const controllerPath =
|
|
4972
|
+
const controllerPath = path16.join(srcDir, controllerFile);
|
|
4770
4973
|
const apis = await extractApisFromController(controllerPath);
|
|
4771
4974
|
for (const api of apis) {
|
|
4772
4975
|
const key = `${api.method}:${api.path}`;
|
|
@@ -4828,9 +5031,9 @@ async function detectApiChanges(projectDir) {
|
|
|
4828
5031
|
}
|
|
4829
5032
|
}
|
|
4830
5033
|
async function generateApiRegistry(projectDir) {
|
|
4831
|
-
const registryFile =
|
|
5034
|
+
const registryFile = path16.join(projectDir, "docs/api-registry.md");
|
|
4832
5035
|
logger.step("\u626B\u63CF\u5E76\u751F\u6210 API Registry...");
|
|
4833
|
-
await FileUtils.ensureDir(
|
|
5036
|
+
await FileUtils.ensureDir(path16.dirname(registryFile));
|
|
4834
5037
|
const header = `# API Registry
|
|
4835
5038
|
|
|
4836
5039
|
> \u672C\u6587\u4EF6\u8BB0\u5F55\u6240\u6709 API \u7684\u5B9A\u4E49\u3001\u7248\u672C\u548C\u53D8\u66F4\u5386\u53F2
|
|
@@ -4859,14 +5062,14 @@ async function generateApiRegistry(projectDir) {
|
|
|
4859
5062
|
*\u6700\u540E\u66F4\u65B0: ${DateUtils.format(/* @__PURE__ */ new Date(), "YYYY-MM-DD HH:mm:ss")}*
|
|
4860
5063
|
`;
|
|
4861
5064
|
let content = header;
|
|
4862
|
-
const backendDir =
|
|
5065
|
+
const backendDir = path16.join(projectDir, "backend");
|
|
4863
5066
|
const exists = await FileUtils.exists(backendDir);
|
|
4864
5067
|
if (exists) {
|
|
4865
|
-
const srcDir =
|
|
5068
|
+
const srcDir = path16.join(backendDir, "src");
|
|
4866
5069
|
const controllers = await FileUtils.findFiles("*Controller.java", srcDir);
|
|
4867
5070
|
const moduleMap = /* @__PURE__ */ new Map();
|
|
4868
5071
|
for (const controllerFile of controllers) {
|
|
4869
|
-
const controllerPath =
|
|
5072
|
+
const controllerPath = path16.join(srcDir, controllerFile);
|
|
4870
5073
|
const controllerName = controllerFile.replace(".java", "");
|
|
4871
5074
|
const module = controllerName.replace(/Controller$/, "").toLowerCase();
|
|
4872
5075
|
if (!moduleMap.has(module)) {
|
|
@@ -4950,10 +5153,10 @@ function extractApisFromRegistry(registryContent) {
|
|
|
4950
5153
|
let match;
|
|
4951
5154
|
while ((match = apiRegex.exec(registryContent)) !== null) {
|
|
4952
5155
|
const method = match[1];
|
|
4953
|
-
const
|
|
5156
|
+
const path20 = match[2].trim();
|
|
4954
5157
|
const description = match[3].trim();
|
|
4955
|
-
const key = `${method}:${
|
|
4956
|
-
apis.set(key, { method, path:
|
|
5158
|
+
const key = `${method}:${path20}`;
|
|
5159
|
+
apis.set(key, { method, path: path20, description });
|
|
4957
5160
|
}
|
|
4958
5161
|
return apis;
|
|
4959
5162
|
}
|
|
@@ -4975,7 +5178,7 @@ init_esm_shims();
|
|
|
4975
5178
|
init_utils();
|
|
4976
5179
|
init_logger();
|
|
4977
5180
|
import { Command as Command12 } from "commander";
|
|
4978
|
-
import
|
|
5181
|
+
import path17 from "path";
|
|
4979
5182
|
import inquirer8 from "inquirer";
|
|
4980
5183
|
var logsCommand = new Command12("logs").argument("[filter]", "\u8FC7\u6EE4\u5668 (today, --all, \u6216\u65E5\u671F YYYY-MM-DD)").description("\u67E5\u770B\u4F1A\u8BDD\u65E5\u5FD7").action(async (filter = "today") => {
|
|
4981
5184
|
try {
|
|
@@ -5000,7 +5203,7 @@ var logsCommand = new Command12("logs").argument("[filter]", "\u8FC7\u6EE4\u5668
|
|
|
5000
5203
|
case "":
|
|
5001
5204
|
case "today": {
|
|
5002
5205
|
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
5003
|
-
targetDir =
|
|
5206
|
+
targetDir = path17.join(sessionsDir, today);
|
|
5004
5207
|
const todayExists = await FileUtils.exists(targetDir);
|
|
5005
5208
|
if (!todayExists) {
|
|
5006
5209
|
logger.info("\u4ECA\u65E5\u6682\u65E0\u4F1A\u8BDD\u65E5\u5FD7");
|
|
@@ -5016,7 +5219,7 @@ var logsCommand = new Command12("logs").argument("[filter]", "\u8FC7\u6EE4\u5668
|
|
|
5016
5219
|
break;
|
|
5017
5220
|
}
|
|
5018
5221
|
default: {
|
|
5019
|
-
targetDir =
|
|
5222
|
+
targetDir = path17.join(sessionsDir, filter);
|
|
5020
5223
|
const dateExists = await FileUtils.exists(targetDir);
|
|
5021
5224
|
if (!dateExists) {
|
|
5022
5225
|
logger.error(`\u672A\u627E\u5230\u65E5\u671F '${filter}' \u7684\u65E5\u5FD7`);
|
|
@@ -5040,7 +5243,7 @@ var logsCommand = new Command12("logs").argument("[filter]", "\u8FC7\u6EE4\u5668
|
|
|
5040
5243
|
process.exit(0);
|
|
5041
5244
|
}
|
|
5042
5245
|
for (let i = 0; i < logs.length; i++) {
|
|
5043
|
-
const relPath =
|
|
5246
|
+
const relPath = path17.relative(sessionsDir, logs[i]);
|
|
5044
5247
|
logger.step(`${i + 1}) ${relPath}`);
|
|
5045
5248
|
}
|
|
5046
5249
|
logger.newLine();
|
|
@@ -5081,7 +5284,7 @@ async function collectLogFiles(targetDir) {
|
|
|
5081
5284
|
const allFiles = await FileUtils.findFiles("*.md", targetDir);
|
|
5082
5285
|
const filtered = allFiles.filter((f) => f !== "index.md");
|
|
5083
5286
|
for (const file of filtered) {
|
|
5084
|
-
const filePath =
|
|
5287
|
+
const filePath = path17.join(targetDir, file);
|
|
5085
5288
|
const stat = await FileUtils.exists(filePath);
|
|
5086
5289
|
if (stat) {
|
|
5087
5290
|
logs.push(filePath);
|
|
@@ -5095,12 +5298,12 @@ async function collectLogFiles(targetDir) {
|
|
|
5095
5298
|
// src/commands/update.ts
|
|
5096
5299
|
init_esm_shims();
|
|
5097
5300
|
import { Command as Command13 } from "commander";
|
|
5098
|
-
import
|
|
5301
|
+
import path18 from "path";
|
|
5099
5302
|
init_logger();
|
|
5100
5303
|
init_utils();
|
|
5101
5304
|
import { execa as execa4 } from "execa";
|
|
5102
5305
|
import inquirer9 from "inquirer";
|
|
5103
|
-
import
|
|
5306
|
+
import fs5 from "fs-extra";
|
|
5104
5307
|
var updateCommand = new Command13("update").description("\u68C0\u67E5\u5E76\u66F4\u65B0\u6A21\u677F\u7248\u672C").option("-f, --frontend", "\u68C0\u67E5\u524D\u7AEF\u6A21\u677F\u66F4\u65B0").option("-b, --backend", "\u68C0\u67E5\u540E\u7AEF\u6A21\u677F\u66F4\u65B0").option("-a, --all", "\u68C0\u67E5\u6240\u6709\u6A21\u677F (\u9ED8\u8BA4)").option("-t, --tag <tag>", "\u66F4\u65B0\u5230\u6307\u5B9A\u6807\u7B7E").option("-B, --branch <branch>", "\u66F4\u65B0\u5230\u6307\u5B9A\u5206\u652F").option("--dry-run", "\u9884\u89C8\u66F4\u65B0\uFF0C\u4E0D\u5B9E\u9645\u6267\u884C").action(async (options) => {
|
|
5105
5308
|
try {
|
|
5106
5309
|
logger.header("\u6A21\u677F\u7248\u672C\u68C0\u67E5");
|
|
@@ -5200,7 +5403,7 @@ async function performUpdate(projectPath, updates) {
|
|
|
5200
5403
|
for (const update of updates) {
|
|
5201
5404
|
const { type, info, updateOptions } = update;
|
|
5202
5405
|
const targetDir = type === "frontend" ? "frontend" : "backend";
|
|
5203
|
-
const targetPath =
|
|
5406
|
+
const targetPath = path18.join(projectPath, targetDir);
|
|
5204
5407
|
logger.newLine();
|
|
5205
5408
|
logger.step(`\u66F4\u65B0 ${type === "frontend" ? "\u524D\u7AEF" : "\u540E\u7AEF"}\u6A21\u677F...`);
|
|
5206
5409
|
if (updateOptions?.tag || updateOptions?.branch) {
|
|
@@ -5231,8 +5434,8 @@ async function performUpdate(projectPath, updates) {
|
|
|
5231
5434
|
}
|
|
5232
5435
|
}
|
|
5233
5436
|
const ref = updateOptions?.tag || updateOptions?.branch || "HEAD";
|
|
5234
|
-
const backupDir =
|
|
5235
|
-
await
|
|
5437
|
+
const backupDir = path18.join(projectPath, `.backup-${Date.now()}`);
|
|
5438
|
+
await fs5.copy(targetPath, path18.join(backupDir, targetDir));
|
|
5236
5439
|
logger.info(`\u5DF2\u521B\u5EFA\u5907\u4EFD: ${backupDir}`);
|
|
5237
5440
|
if (updateOptions?.dryRun) {
|
|
5238
5441
|
logger.info("[Dry Run] \u5C06\u4F1A\u66F4\u65B0\u5230\u4EE5\u4E0B\u7248\u672C:");
|
|
@@ -5242,7 +5445,7 @@ async function performUpdate(projectPath, updates) {
|
|
|
5242
5445
|
continue;
|
|
5243
5446
|
}
|
|
5244
5447
|
try {
|
|
5245
|
-
const tempDir =
|
|
5448
|
+
const tempDir = path18.join(projectPath, `.template-update-${Date.now()}`);
|
|
5246
5449
|
await execa4("git", ["clone", "--depth=1", "--branch", ref, info.repository, tempDir], {
|
|
5247
5450
|
stdio: "pipe"
|
|
5248
5451
|
});
|
|
@@ -5259,17 +5462,17 @@ async function performUpdate(projectPath, updates) {
|
|
|
5259
5462
|
const currentFiles = await FileUtils.findFiles("*", targetPath);
|
|
5260
5463
|
for (const file of currentFiles) {
|
|
5261
5464
|
if (!keepFiles.includes(file)) {
|
|
5262
|
-
const filePath =
|
|
5465
|
+
const filePath = path18.join(targetPath, file);
|
|
5263
5466
|
try {
|
|
5264
|
-
await
|
|
5467
|
+
await fs5.remove(filePath);
|
|
5265
5468
|
} catch {
|
|
5266
5469
|
}
|
|
5267
5470
|
}
|
|
5268
5471
|
}
|
|
5269
|
-
await
|
|
5472
|
+
await fs5.copy(tempDir, targetPath, {
|
|
5270
5473
|
filter: (src) => !src.includes(".git")
|
|
5271
5474
|
});
|
|
5272
|
-
await
|
|
5475
|
+
await fs5.remove(tempDir);
|
|
5273
5476
|
await updateTemplateVersion(projectPath, type, commit.trim(), {
|
|
5274
5477
|
tag: updateOptions?.tag || latestTag,
|
|
5275
5478
|
branch: updateOptions?.branch
|
|
@@ -5280,9 +5483,9 @@ async function performUpdate(projectPath, updates) {
|
|
|
5280
5483
|
} catch (error) {
|
|
5281
5484
|
logger.error(`\u66F4\u65B0\u5931\u8D25: ${error.message}`);
|
|
5282
5485
|
logger.info("\u6B63\u5728\u6062\u590D\u5907\u4EFD...");
|
|
5283
|
-
await
|
|
5284
|
-
await
|
|
5285
|
-
await
|
|
5486
|
+
await fs5.remove(targetPath);
|
|
5487
|
+
await fs5.copy(path18.join(backupDir, targetDir), targetPath);
|
|
5488
|
+
await fs5.remove(backupDir);
|
|
5286
5489
|
logger.info("\u5DF2\u6062\u590D\u5230\u66F4\u65B0\u524D\u7684\u72B6\u6001");
|
|
5287
5490
|
}
|
|
5288
5491
|
}
|
|
@@ -5767,8 +5970,10 @@ var Table = class {
|
|
|
5767
5970
|
};
|
|
5768
5971
|
|
|
5769
5972
|
// src/index.ts
|
|
5973
|
+
var __dirname2 = path19.dirname(fileURLToPath2(import.meta.url));
|
|
5974
|
+
var pkg = fs6.readJsonSync(path19.join(__dirname2, "../package.json"));
|
|
5770
5975
|
var program = new Command16();
|
|
5771
|
-
program.name("team-cli").description("AI-Native \u56E2\u961F\u7814\u53D1\u811A\u624B\u67B6").version(
|
|
5976
|
+
program.name("team-cli").description("AI-Native \u56E2\u961F\u7814\u53D1\u811A\u624B\u67B6").version(pkg.version);
|
|
5772
5977
|
program.option("-v, --verbose", "\u8BE6\u7EC6\u8F93\u51FA\u6A21\u5F0F").option("--debug", "\u8C03\u8BD5\u6A21\u5F0F");
|
|
5773
5978
|
program.addCommand(initCommand);
|
|
5774
5979
|
program.addCommand(splitPrdCommand);
|