colyn-cli 3.1.4
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/README-en.md +85 -0
- package/README.md +85 -0
- package/bin/colyn +25 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +116 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/add.d.ts +6 -0
- package/dist/commands/add.d.ts.map +1 -0
- package/dist/commands/add.helpers.d.ts +48 -0
- package/dist/commands/add.helpers.d.ts.map +1 -0
- package/dist/commands/add.helpers.js +251 -0
- package/dist/commands/add.helpers.js.map +1 -0
- package/dist/commands/add.js +286 -0
- package/dist/commands/add.js.map +1 -0
- package/dist/commands/checkout.d.ts +16 -0
- package/dist/commands/checkout.d.ts.map +1 -0
- package/dist/commands/checkout.js +428 -0
- package/dist/commands/checkout.js.map +1 -0
- package/dist/commands/completion.d.ts +10 -0
- package/dist/commands/completion.d.ts.map +1 -0
- package/dist/commands/completion.js +380 -0
- package/dist/commands/completion.js.map +1 -0
- package/dist/commands/config.d.ts +11 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +338 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/index.d.ts +10 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +41 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/info.d.ts +6 -0
- package/dist/commands/info.d.ts.map +1 -0
- package/dist/commands/info.js +374 -0
- package/dist/commands/info.js.map +1 -0
- package/dist/commands/init.d.ts +6 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.handlers.d.ts +27 -0
- package/dist/commands/init.handlers.d.ts.map +1 -0
- package/dist/commands/init.handlers.js +314 -0
- package/dist/commands/init.handlers.js.map +1 -0
- package/dist/commands/init.helpers.d.ts +42 -0
- package/dist/commands/init.helpers.d.ts.map +1 -0
- package/dist/commands/init.helpers.js +275 -0
- package/dist/commands/init.helpers.js.map +1 -0
- package/dist/commands/init.js +61 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/install.d.ts +6 -0
- package/dist/commands/install.d.ts.map +1 -0
- package/dist/commands/install.helpers.d.ts +32 -0
- package/dist/commands/install.helpers.d.ts.map +1 -0
- package/dist/commands/install.helpers.js +124 -0
- package/dist/commands/install.helpers.js.map +1 -0
- package/dist/commands/install.js +104 -0
- package/dist/commands/install.js.map +1 -0
- package/dist/commands/list-project.d.ts +11 -0
- package/dist/commands/list-project.d.ts.map +1 -0
- package/dist/commands/list-project.js +260 -0
- package/dist/commands/list-project.js.map +1 -0
- package/dist/commands/list.d.ts +15 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.helpers.d.ts +50 -0
- package/dist/commands/list.helpers.d.ts.map +1 -0
- package/dist/commands/list.helpers.js +143 -0
- package/dist/commands/list.helpers.js.map +1 -0
- package/dist/commands/list.js +530 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/merge.d.ts +6 -0
- package/dist/commands/merge.d.ts.map +1 -0
- package/dist/commands/merge.helpers.d.ts +74 -0
- package/dist/commands/merge.helpers.d.ts.map +1 -0
- package/dist/commands/merge.helpers.js +307 -0
- package/dist/commands/merge.helpers.js.map +1 -0
- package/dist/commands/merge.js +260 -0
- package/dist/commands/merge.js.map +1 -0
- package/dist/commands/release.d.ts +6 -0
- package/dist/commands/release.d.ts.map +1 -0
- package/dist/commands/release.helpers.d.ts +61 -0
- package/dist/commands/release.helpers.d.ts.map +1 -0
- package/dist/commands/release.helpers.js +277 -0
- package/dist/commands/release.helpers.js.map +1 -0
- package/dist/commands/release.js +127 -0
- package/dist/commands/release.js.map +1 -0
- package/dist/commands/remove.d.ts +6 -0
- package/dist/commands/remove.d.ts.map +1 -0
- package/dist/commands/remove.helpers.d.ts +59 -0
- package/dist/commands/remove.helpers.d.ts.map +1 -0
- package/dist/commands/remove.helpers.js +190 -0
- package/dist/commands/remove.helpers.js.map +1 -0
- package/dist/commands/remove.js +137 -0
- package/dist/commands/remove.js.map +1 -0
- package/dist/commands/repair.d.ts +6 -0
- package/dist/commands/repair.d.ts.map +1 -0
- package/dist/commands/repair.helpers.d.ts +5 -0
- package/dist/commands/repair.helpers.d.ts.map +1 -0
- package/dist/commands/repair.helpers.js +499 -0
- package/dist/commands/repair.helpers.js.map +1 -0
- package/dist/commands/repair.js +28 -0
- package/dist/commands/repair.js.map +1 -0
- package/dist/commands/status.d.ts +6 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +116 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/system-integration.d.ts +6 -0
- package/dist/commands/system-integration.d.ts.map +1 -0
- package/dist/commands/system-integration.helpers.d.ts +70 -0
- package/dist/commands/system-integration.helpers.d.ts.map +1 -0
- package/dist/commands/system-integration.helpers.js +313 -0
- package/dist/commands/system-integration.helpers.js.map +1 -0
- package/dist/commands/system-integration.js +132 -0
- package/dist/commands/system-integration.js.map +1 -0
- package/dist/commands/tmux.d.ts +11 -0
- package/dist/commands/tmux.d.ts.map +1 -0
- package/dist/commands/tmux.js +500 -0
- package/dist/commands/tmux.js.map +1 -0
- package/dist/commands/todo.d.ts +6 -0
- package/dist/commands/todo.d.ts.map +1 -0
- package/dist/commands/todo.helpers.d.ts +50 -0
- package/dist/commands/todo.helpers.d.ts.map +1 -0
- package/dist/commands/todo.helpers.js +297 -0
- package/dist/commands/todo.helpers.js.map +1 -0
- package/dist/commands/todo.js +579 -0
- package/dist/commands/todo.js.map +1 -0
- package/dist/commands/update.d.ts +18 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.helpers.d.ts +89 -0
- package/dist/commands/update.helpers.d.ts.map +1 -0
- package/dist/commands/update.helpers.js +335 -0
- package/dist/commands/update.helpers.js.map +1 -0
- package/dist/commands/update.js +187 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/core/config-loader.d.ts +47 -0
- package/dist/core/config-loader.d.ts.map +1 -0
- package/dist/core/config-loader.js +188 -0
- package/dist/core/config-loader.js.map +1 -0
- package/dist/core/config-merger.d.ts +29 -0
- package/dist/core/config-merger.d.ts.map +1 -0
- package/dist/core/config-merger.js +100 -0
- package/dist/core/config-merger.js.map +1 -0
- package/dist/core/config-migration.d.ts +64 -0
- package/dist/core/config-migration.d.ts.map +1 -0
- package/dist/core/config-migration.js +340 -0
- package/dist/core/config-migration.js.map +1 -0
- package/dist/core/config-new.d.ts +19 -0
- package/dist/core/config-new.d.ts.map +1 -0
- package/dist/core/config-new.js +58 -0
- package/dist/core/config-new.js.map +1 -0
- package/dist/core/config-schema.d.ts +221 -0
- package/dist/core/config-schema.d.ts.map +1 -0
- package/dist/core/config-schema.js +168 -0
- package/dist/core/config-schema.js.map +1 -0
- package/dist/core/config.d.ts +55 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +143 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/dev-server.d.ts +29 -0
- package/dist/core/dev-server.d.ts.map +1 -0
- package/dist/core/dev-server.js +54 -0
- package/dist/core/dev-server.js.map +1 -0
- package/dist/core/discovery.d.ts +51 -0
- package/dist/core/discovery.d.ts.map +1 -0
- package/dist/core/discovery.js +247 -0
- package/dist/core/discovery.js.map +1 -0
- package/dist/core/env.d.ts +13 -0
- package/dist/core/env.d.ts.map +1 -0
- package/dist/core/env.js +75 -0
- package/dist/core/env.js.map +1 -0
- package/dist/core/git.d.ts +31 -0
- package/dist/core/git.d.ts.map +1 -0
- package/dist/core/git.js +56 -0
- package/dist/core/git.js.map +1 -0
- package/dist/core/paths.d.ts +86 -0
- package/dist/core/paths.d.ts.map +1 -0
- package/dist/core/paths.js +256 -0
- package/dist/core/paths.js.map +1 -0
- package/dist/core/tmux-config.d.ts +174 -0
- package/dist/core/tmux-config.d.ts.map +1 -0
- package/dist/core/tmux-config.js +545 -0
- package/dist/core/tmux-config.js.map +1 -0
- package/dist/core/tmux-config.legacy.d.ts +243 -0
- package/dist/core/tmux-config.legacy.d.ts.map +1 -0
- package/dist/core/tmux-config.legacy.js +896 -0
- package/dist/core/tmux-config.legacy.js.map +1 -0
- package/dist/core/tmux.d.ts +214 -0
- package/dist/core/tmux.d.ts.map +1 -0
- package/dist/core/tmux.js +712 -0
- package/dist/core/tmux.js.map +1 -0
- package/dist/core/toolchain-resolver.d.ts +51 -0
- package/dist/core/toolchain-resolver.d.ts.map +1 -0
- package/dist/core/toolchain-resolver.js +364 -0
- package/dist/core/toolchain-resolver.js.map +1 -0
- package/dist/core/worktree-status.d.ts +20 -0
- package/dist/core/worktree-status.d.ts.map +1 -0
- package/dist/core/worktree-status.js +67 -0
- package/dist/core/worktree-status.js.map +1 -0
- package/dist/i18n/index.d.ts +36 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/i18n/index.js +157 -0
- package/dist/i18n/index.js.map +1 -0
- package/dist/i18n/locales/en.d.ts +866 -0
- package/dist/i18n/locales/en.d.ts.map +1 -0
- package/dist/i18n/locales/en.js +985 -0
- package/dist/i18n/locales/en.js.map +1 -0
- package/dist/i18n/locales/zh-CN.d.ts +865 -0
- package/dist/i18n/locales/zh-CN.d.ts.map +1 -0
- package/dist/i18n/locales/zh-CN.js +985 -0
- package/dist/i18n/locales/zh-CN.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/plugins/builtin/gradle.d.ts +9 -0
- package/dist/plugins/builtin/gradle.d.ts.map +1 -0
- package/dist/plugins/builtin/gradle.js +164 -0
- package/dist/plugins/builtin/gradle.js.map +1 -0
- package/dist/plugins/builtin/maven.d.ts +9 -0
- package/dist/plugins/builtin/maven.d.ts.map +1 -0
- package/dist/plugins/builtin/maven.js +127 -0
- package/dist/plugins/builtin/maven.js.map +1 -0
- package/dist/plugins/builtin/npm.d.ts +9 -0
- package/dist/plugins/builtin/npm.d.ts.map +1 -0
- package/dist/plugins/builtin/npm.js +238 -0
- package/dist/plugins/builtin/npm.js.map +1 -0
- package/dist/plugins/builtin/pip.d.ts +9 -0
- package/dist/plugins/builtin/pip.d.ts.map +1 -0
- package/dist/plugins/builtin/pip.js +210 -0
- package/dist/plugins/builtin/pip.js.map +1 -0
- package/dist/plugins/builtin/xcode.d.ts +12 -0
- package/dist/plugins/builtin/xcode.d.ts.map +1 -0
- package/dist/plugins/builtin/xcode.js +438 -0
- package/dist/plugins/builtin/xcode.js.map +1 -0
- package/dist/plugins/index.d.ts +13 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +24 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins/manager.d.ts +93 -0
- package/dist/plugins/manager.d.ts.map +1 -0
- package/dist/plugins/manager.js +270 -0
- package/dist/plugins/manager.js.map +1 -0
- package/dist/plugins/utils.d.ts +42 -0
- package/dist/plugins/utils.d.ts.map +1 -0
- package/dist/plugins/utils.js +175 -0
- package/dist/plugins/utils.js.map +1 -0
- package/dist/types/index.d.ts +104 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +21 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/plugin.d.ts +200 -0
- package/dist/types/plugin.d.ts.map +1 -0
- package/dist/types/plugin.js +19 -0
- package/dist/types/plugin.js.map +1 -0
- package/dist/utils/logger.d.ts +42 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +80 -0
- package/dist/utils/logger.js.map +1 -0
- package/docs/en/manual/04-command-reference/README.md +58 -0
- package/docs/en/manual/README.md +108 -0
- package/docs/zh-CN/manual/04-command-reference/README.md +58 -0
- package/docs/zh-CN/manual/README.md +108 -0
- package/package.json +65 -0
- package/shell/colyn.sh +55 -0
- package/shell/completion.bash +270 -0
- package/shell/completion.zsh +167 -0
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
import * as fs from 'fs/promises';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import ora from 'ora';
|
|
5
|
+
import Enquirer from 'enquirer';
|
|
6
|
+
const { prompt } = Enquirer;
|
|
7
|
+
import { ColynError } from '../types/index.js';
|
|
8
|
+
import { detectMainBranch, checkWorkingDirectoryClean } from '../core/git.js';
|
|
9
|
+
import { createDirectoryStructure, moveFilesToMainDir, displaySuccessInfo, displayEmptyDirectorySuccess, checkDirectoryConflict, getPortConfig } from './init.helpers.js';
|
|
10
|
+
import { output, outputWarning, outputInfo, outputSuccess } from '../utils/logger.js';
|
|
11
|
+
import { t } from '../i18n/index.js';
|
|
12
|
+
import { isTmuxAvailable, isInTmux, getCurrentSession, createSession, setupWindow, getWindowName } from '../core/tmux.js';
|
|
13
|
+
import { getDevServerCommand } from '../core/dev-server.js';
|
|
14
|
+
import { pluginManager } from '../plugins/index.js';
|
|
15
|
+
import { detectAndConfigureToolchains, saveRepairSettingsResult } from '../core/toolchain-resolver.js';
|
|
16
|
+
/**
|
|
17
|
+
* 检测工具链并执行初始化(gitignore、repairSettings 等)
|
|
18
|
+
* @param nonInteractive 是否非交互模式(默认 false)
|
|
19
|
+
* @returns 检测到的工具链上下文列表
|
|
20
|
+
*/
|
|
21
|
+
async function detectAndInitToolchains(mainDirPath, projectRoot, nonInteractive = false) {
|
|
22
|
+
const contexts = await detectAndConfigureToolchains(projectRoot, mainDirPath, nonInteractive);
|
|
23
|
+
for (const ctx of contexts) {
|
|
24
|
+
await pluginManager.ensureRuntimeConfigIgnored(ctx.absolutePath, [ctx.toolchainName]);
|
|
25
|
+
const newSettings = await pluginManager.runRepairSettings(ctx.absolutePath, ctx.toolchainName, ctx.toolchainSettings, nonInteractive);
|
|
26
|
+
if (newSettings !== null) {
|
|
27
|
+
await saveRepairSettingsResult(projectRoot, ctx.subPath, newSettings);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return contexts;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* 根据工具链上下文列表配置端口和运行时环境
|
|
34
|
+
* 对每个子项目询问端口(如有 portConfig),并写入运行时配置
|
|
35
|
+
*/
|
|
36
|
+
async function configurePortAndEnv(contexts, options, worktreeLabel) {
|
|
37
|
+
let firstPort;
|
|
38
|
+
for (const ctx of contexts) {
|
|
39
|
+
const portConfig = pluginManager.getPortConfig([ctx.toolchainName]);
|
|
40
|
+
if (!portConfig)
|
|
41
|
+
continue;
|
|
42
|
+
const port = await getPortConfig(options, portConfig.defaultPort);
|
|
43
|
+
await pluginManager.writeRuntimeConfig(ctx.absolutePath, { [portConfig.key]: port.toString(), WORKTREE: worktreeLabel }, [ctx.toolchainName]);
|
|
44
|
+
if (firstPort === undefined) {
|
|
45
|
+
firstPort = port;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return firstPort;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* 设置 tmux 环境(Window 0 for main branch)
|
|
52
|
+
* @param projectName 项目名称(用作 session 名称)
|
|
53
|
+
* @param mainDirPath 主分支目录路径
|
|
54
|
+
* @param mainBranch 主分支名称
|
|
55
|
+
* @param configDir .colyn 配置目录路径(可选)
|
|
56
|
+
*/
|
|
57
|
+
async function setupTmuxEnvironment(projectName, mainDirPath, mainBranch, configDir) {
|
|
58
|
+
// 如果 tmux 不可用,直接返回
|
|
59
|
+
if (!isTmuxAvailable()) {
|
|
60
|
+
return { success: false, inTmux: false };
|
|
61
|
+
}
|
|
62
|
+
const sessionName = projectName;
|
|
63
|
+
const windowName = getWindowName(mainBranch);
|
|
64
|
+
const devCommand = await getDevServerCommand(mainDirPath, configDir);
|
|
65
|
+
// 检测当前环境
|
|
66
|
+
const inTmux = isInTmux();
|
|
67
|
+
if (inTmux) {
|
|
68
|
+
// 在 tmux 中:使用当前 session,设置 Window 0 布局
|
|
69
|
+
const currentSession = getCurrentSession();
|
|
70
|
+
if (currentSession) {
|
|
71
|
+
// 设置 Window 0 的布局
|
|
72
|
+
const success = setupWindow({
|
|
73
|
+
sessionName: currentSession,
|
|
74
|
+
windowIndex: 0,
|
|
75
|
+
windowName,
|
|
76
|
+
workingDir: mainDirPath,
|
|
77
|
+
devCommand,
|
|
78
|
+
skipWindowCreation: true, // Window 0 已存在,只设置布局
|
|
79
|
+
});
|
|
80
|
+
return {
|
|
81
|
+
success,
|
|
82
|
+
sessionName: currentSession,
|
|
83
|
+
inTmux: true,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
return { success: false, inTmux: true };
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
// 不在 tmux 中:创建新 session,设置 Window 0
|
|
90
|
+
const created = createSession(sessionName, mainDirPath);
|
|
91
|
+
if (created) {
|
|
92
|
+
// 设置 Window 0 的布局
|
|
93
|
+
const success = setupWindow({
|
|
94
|
+
sessionName,
|
|
95
|
+
windowIndex: 0,
|
|
96
|
+
windowName,
|
|
97
|
+
workingDir: mainDirPath,
|
|
98
|
+
devCommand,
|
|
99
|
+
skipWindowCreation: true, // session 创建时会自动创建 window 0
|
|
100
|
+
});
|
|
101
|
+
return {
|
|
102
|
+
success,
|
|
103
|
+
sessionName,
|
|
104
|
+
inTmux: false,
|
|
105
|
+
createdSession: true,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
return { success: false, inTmux: false };
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* 显示 tmux 设置结果信息
|
|
113
|
+
*/
|
|
114
|
+
function displayTmuxSetupInfo(result) {
|
|
115
|
+
if (!result.success) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (result.inTmux) {
|
|
119
|
+
outputSuccess(t('commands.init.tmuxDetectedInSession'));
|
|
120
|
+
outputSuccess(t('commands.init.tmuxUseCurrentSession', { session: result.sessionName ?? '' }));
|
|
121
|
+
outputSuccess(t('commands.init.tmuxWindow0Set'));
|
|
122
|
+
output(t('commands.init.tmuxPaneClaude'));
|
|
123
|
+
output(t('commands.init.tmuxPaneDevServer'));
|
|
124
|
+
output(t('commands.init.tmuxPaneBash'));
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
outputSuccess(t('commands.init.tmuxDetectedNotInSession'));
|
|
128
|
+
outputSuccess(t('commands.init.tmuxSessionCreated', { session: result.sessionName ?? '' }));
|
|
129
|
+
outputSuccess(t('commands.init.tmuxWindow0Set'));
|
|
130
|
+
output(t('commands.init.tmuxPaneClaude'));
|
|
131
|
+
output(t('commands.init.tmuxPaneDevServer'));
|
|
132
|
+
output(t('commands.init.tmuxPaneBash'));
|
|
133
|
+
output('');
|
|
134
|
+
output(chalk.cyan(t('commands.init.tmuxAttachHint', { session: result.sessionName ?? '' })));
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* 处理空目录情况
|
|
139
|
+
*/
|
|
140
|
+
export async function handleEmptyDirectory(dirInfo, options) {
|
|
141
|
+
const rootDir = process.cwd();
|
|
142
|
+
const mainDirName = dirInfo.currentDirName;
|
|
143
|
+
const mainBranch = 'main'; // 空目录默认使用 main
|
|
144
|
+
// 步骤1: 创建目录结构
|
|
145
|
+
const spinner = ora({ text: t('commands.init.creatingStructure'), stream: process.stderr }).start();
|
|
146
|
+
const mainDirPath = path.join(rootDir, mainDirName);
|
|
147
|
+
const worktreesDirPath = path.join(rootDir, 'worktrees');
|
|
148
|
+
const configDirPath = path.join(rootDir, '.colyn');
|
|
149
|
+
await fs.mkdir(mainDirPath, { recursive: true });
|
|
150
|
+
await fs.mkdir(worktreesDirPath, { recursive: true });
|
|
151
|
+
await fs.mkdir(configDirPath, { recursive: true });
|
|
152
|
+
spinner.succeed(t('commands.init.structureCreated'));
|
|
153
|
+
// 步骤2: 检测工具链并初始化(空目录通常没有工具链)
|
|
154
|
+
const contexts = await detectAndInitToolchains(mainDirPath, rootDir);
|
|
155
|
+
// 步骤3: 如果有 portConfig,询问端口并写入运行时配置
|
|
156
|
+
const port = await configurePortAndEnv(contexts, options, 'main');
|
|
157
|
+
// 步骤4: 设置 tmux 环境
|
|
158
|
+
const tmuxResult = await setupTmuxEnvironment(mainDirName, mainDirPath, mainBranch, configDirPath);
|
|
159
|
+
// 步骤5: 显示成功信息
|
|
160
|
+
displayEmptyDirectorySuccess(mainDirName, port ?? 0, mainBranch);
|
|
161
|
+
// 步骤6: 显示 tmux 设置信息
|
|
162
|
+
if (tmuxResult.success) {
|
|
163
|
+
output('');
|
|
164
|
+
displayTmuxSetupInfo(tmuxResult);
|
|
165
|
+
}
|
|
166
|
+
return { mainDirPath, mainDirName };
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* 处理已初始化目录情况
|
|
170
|
+
*/
|
|
171
|
+
export async function handleInitializedDirectory(dirInfo, options) {
|
|
172
|
+
const rootDir = process.cwd();
|
|
173
|
+
const mainDirName = dirInfo.currentDirName;
|
|
174
|
+
const mainDirPath = path.join(rootDir, mainDirName);
|
|
175
|
+
const configDirPath = path.join(rootDir, '.colyn');
|
|
176
|
+
outputWarning(t('commands.init.detectedInitialized') + '\n');
|
|
177
|
+
const tasks = [];
|
|
178
|
+
// 检查并补全主分支目录
|
|
179
|
+
if (!dirInfo.hasMainDir) {
|
|
180
|
+
tasks.push({
|
|
181
|
+
name: t('commands.init.createMainDir', { name: mainDirName }),
|
|
182
|
+
action: async () => {
|
|
183
|
+
await fs.mkdir(mainDirPath, { recursive: true });
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
// 检查并补全 worktrees 目录
|
|
188
|
+
if (!dirInfo.hasWorktreesDir) {
|
|
189
|
+
tasks.push({
|
|
190
|
+
name: t('commands.init.createWorktreesDir'),
|
|
191
|
+
action: async () => {
|
|
192
|
+
const worktreesDirPath = path.join(rootDir, 'worktrees');
|
|
193
|
+
await fs.mkdir(worktreesDirPath, { recursive: true });
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
// 检查并补全 .colyn 配置目录
|
|
198
|
+
if (!dirInfo.hasConfigDir) {
|
|
199
|
+
tasks.push({
|
|
200
|
+
name: t('commands.init.createConfigDir'),
|
|
201
|
+
action: async () => {
|
|
202
|
+
const newConfigDirPath = path.join(rootDir, '.colyn');
|
|
203
|
+
await fs.mkdir(newConfigDirPath, { recursive: true });
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
// 执行补全任务
|
|
208
|
+
for (const task of tasks) {
|
|
209
|
+
const spinner = ora({ text: task.name, stream: process.stderr }).start();
|
|
210
|
+
try {
|
|
211
|
+
await task.action();
|
|
212
|
+
spinner.succeed();
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
spinner.fail();
|
|
216
|
+
throw error;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
outputSuccess('\n' + t('commands.init.completionDone') + '\n');
|
|
220
|
+
if (tasks.length === 0) {
|
|
221
|
+
outputInfo(t('commands.init.noCompletionNeeded') + '\n');
|
|
222
|
+
}
|
|
223
|
+
// 检测工具链并初始化(gitignore 等)
|
|
224
|
+
const contexts = await detectAndInitToolchains(mainDirPath, rootDir);
|
|
225
|
+
// 如果有 portConfig,询问端口并写入运行时配置
|
|
226
|
+
await configurePortAndEnv(contexts, options, 'main');
|
|
227
|
+
// 设置 tmux 环境(获取主分支名称)
|
|
228
|
+
let mainBranch = 'main';
|
|
229
|
+
if (dirInfo.hasGitRepo) {
|
|
230
|
+
try {
|
|
231
|
+
mainBranch = await detectMainBranch();
|
|
232
|
+
}
|
|
233
|
+
catch {
|
|
234
|
+
// 如果无法获取主分支,使用默认值
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
const tmuxResult = await setupTmuxEnvironment(mainDirName, mainDirPath, mainBranch, configDirPath);
|
|
238
|
+
if (tmuxResult.success) {
|
|
239
|
+
output('');
|
|
240
|
+
displayTmuxSetupInfo(tmuxResult);
|
|
241
|
+
}
|
|
242
|
+
return { mainDirPath, mainDirName };
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* 处理已有项目情况
|
|
246
|
+
*/
|
|
247
|
+
export async function handleExistingProject(dirInfo, options, skipConfirm = false) {
|
|
248
|
+
const rootDir = process.cwd();
|
|
249
|
+
const mainDirName = dirInfo.currentDirName;
|
|
250
|
+
const configDirPath = path.join(rootDir, '.colyn');
|
|
251
|
+
// 步骤1: 显示当前目录的文件列表
|
|
252
|
+
outputWarning('\n' + t('commands.init.detectedExistingFiles'));
|
|
253
|
+
outputInfo(' ' + t('commands.init.existingStep1'));
|
|
254
|
+
outputInfo(' ' + t('commands.init.existingStep2', { name: mainDirName }) + '\n');
|
|
255
|
+
const entries = await fs.readdir(rootDir);
|
|
256
|
+
output(chalk.bold(t('commands.init.currentFileList')));
|
|
257
|
+
// 显示前10个文件,如果超过10个则显示省略
|
|
258
|
+
const displayEntries = entries.slice(0, 10);
|
|
259
|
+
displayEntries.forEach(entry => {
|
|
260
|
+
outputInfo(` - ${entry}`);
|
|
261
|
+
});
|
|
262
|
+
if (entries.length > 10) {
|
|
263
|
+
outputInfo(' ' + t('commands.init.moreFiles', { count: String(entries.length - 10) }));
|
|
264
|
+
}
|
|
265
|
+
output('');
|
|
266
|
+
// 步骤2: 询问用户确认(输出到 stderr,避免被 shell 脚本捕获)
|
|
267
|
+
let confirmed = skipConfirm;
|
|
268
|
+
if (!skipConfirm) {
|
|
269
|
+
if (!process.stdin.isTTY) {
|
|
270
|
+
throw new ColynError(t('commands.init.nonInteractiveConfirm'), t('commands.init.nonInteractiveConfirmHint'));
|
|
271
|
+
}
|
|
272
|
+
const response = await prompt({
|
|
273
|
+
type: 'confirm',
|
|
274
|
+
name: 'confirmed',
|
|
275
|
+
message: t('commands.init.confirmContinue'),
|
|
276
|
+
initial: false, // 默认为否,需要用户主动确认
|
|
277
|
+
stdout: process.stderr
|
|
278
|
+
});
|
|
279
|
+
confirmed = response.confirmed;
|
|
280
|
+
}
|
|
281
|
+
// 步骤3: 如果取消,退出
|
|
282
|
+
if (!confirmed) {
|
|
283
|
+
outputInfo(t('commands.init.initCanceled'));
|
|
284
|
+
return null;
|
|
285
|
+
}
|
|
286
|
+
// 步骤4: 如果是 git 仓库,检查工作目录是否干净
|
|
287
|
+
if (dirInfo.hasGitRepo) {
|
|
288
|
+
await checkWorkingDirectoryClean();
|
|
289
|
+
}
|
|
290
|
+
// 步骤5: 检查目录名冲突
|
|
291
|
+
await checkDirectoryConflict(rootDir, mainDirName);
|
|
292
|
+
// 步骤6: 检测主分支名称
|
|
293
|
+
const mainBranch = await detectMainBranch();
|
|
294
|
+
// 步骤7: 创建目录结构
|
|
295
|
+
await createDirectoryStructure(rootDir, mainDirName, dirInfo);
|
|
296
|
+
// 步骤8: 移动文件
|
|
297
|
+
await moveFilesToMainDir(rootDir, mainDirName);
|
|
298
|
+
// 步骤9: 检测工具链并初始化(含 .gitignore 配置)
|
|
299
|
+
const mainDirPath = path.join(rootDir, mainDirName);
|
|
300
|
+
const contexts = await detectAndInitToolchains(mainDirPath, rootDir);
|
|
301
|
+
// 步骤10: 如果有 portConfig,询问端口并写入运行时配置
|
|
302
|
+
const port = await configurePortAndEnv(contexts, options, 'main');
|
|
303
|
+
// 步骤11: 设置 tmux 环境
|
|
304
|
+
const tmuxResult = await setupTmuxEnvironment(mainDirName, mainDirPath, mainBranch, configDirPath);
|
|
305
|
+
// 步骤12: 显示成功信息
|
|
306
|
+
displaySuccessInfo(mainDirName, port, mainBranch);
|
|
307
|
+
// 步骤13: 显示 tmux 设置信息
|
|
308
|
+
if (tmuxResult.success) {
|
|
309
|
+
output('');
|
|
310
|
+
displayTmuxSetupInfo(tmuxResult);
|
|
311
|
+
}
|
|
312
|
+
return { mainDirPath, mainDirName };
|
|
313
|
+
}
|
|
314
|
+
//# sourceMappingURL=init.handlers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.handlers.js","sourceRoot":"","sources":["../../src/commands/init.handlers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { type DirectoryInfo } from '../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* 检测目录状态
|
|
4
|
+
*/
|
|
5
|
+
export declare function detectDirectoryStatus(): Promise<DirectoryInfo>;
|
|
6
|
+
/**
|
|
7
|
+
* 获取端口配置
|
|
8
|
+
* @param options 命令选项
|
|
9
|
+
* @param defaultPort 默认端口号(由插件 portConfig.defaultPort 提供)
|
|
10
|
+
*/
|
|
11
|
+
export declare function getPortConfig(options: {
|
|
12
|
+
port?: string;
|
|
13
|
+
}, defaultPort?: number): Promise<number>;
|
|
14
|
+
/**
|
|
15
|
+
* 检查目录名冲突
|
|
16
|
+
*/
|
|
17
|
+
export declare function checkDirectoryConflict(rootDir: string, mainDirName: string): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* 创建目录结构
|
|
20
|
+
*/
|
|
21
|
+
export declare function createDirectoryStructure(rootDir: string, mainDirName: string, dirInfo: DirectoryInfo): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* 移动文件到主分支目录
|
|
24
|
+
*/
|
|
25
|
+
export declare function moveFilesToMainDir(rootDir: string, mainDirName: string): Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* 配置 .env.local 文件
|
|
28
|
+
*/
|
|
29
|
+
export declare function configureEnvFile(mainDirPath: string, port: number, worktree: string): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* 配置 .gitignore 文件
|
|
32
|
+
*/
|
|
33
|
+
export declare function configureGitignore(mainDirPath: string): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* 显示成功信息(输出到 stderr)
|
|
36
|
+
*/
|
|
37
|
+
export declare function displaySuccessInfo(mainDirName: string, port: number | undefined, mainBranch: string): void;
|
|
38
|
+
/**
|
|
39
|
+
* 显示空目录成功信息(输出到 stderr)
|
|
40
|
+
*/
|
|
41
|
+
export declare function displayEmptyDirectorySuccess(mainDirName: string, _port: number, _mainBranch: string): void;
|
|
42
|
+
//# sourceMappingURL=init.helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.helpers.d.ts","sourceRoot":"","sources":["../../src/commands/init.helpers.ts"],"names":[],"mappings":"AAKA,OAAO,EAEL,KAAK,aAAa,EAEnB,MAAM,mBAAmB,CAAC;AAa3B;;GAEG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,aAAa,CAAC,CAgEpE;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,EAC1B,WAAW,GAAE,MAAc,GAC1B,OAAO,CAAC,MAAM,CAAC,CA+BjB;AAED;;GAEG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC,CAqBf;AAED;;GAEG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,IAAI,CAAC,CAiBf;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC,CAgCf;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAoBf;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAiC3E;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,UAAU,EAAE,MAAM,GACjB,IAAI,CAyBN;AAED;;GAEG;AACH,wBAAgB,4BAA4B,CAC1C,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,GAClB,IAAI,CAuBN"}
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import * as fs from 'fs/promises';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import ora from 'ora';
|
|
4
|
+
import Enquirer from 'enquirer';
|
|
5
|
+
const { prompt } = Enquirer;
|
|
6
|
+
import { DirectoryStatus, ColynError } from '../types/index.js';
|
|
7
|
+
import { checkIsRepo } from '../core/git.js';
|
|
8
|
+
import { updateEnvFilePreserveComments } from '../core/env.js';
|
|
9
|
+
import { findProjectRoot } from '../core/paths.js';
|
|
10
|
+
import { output, outputLine, outputSuccess, outputBold, outputStep } from '../utils/logger.js';
|
|
11
|
+
import { t } from '../i18n/index.js';
|
|
12
|
+
/**
|
|
13
|
+
* 检测目录状态
|
|
14
|
+
*/
|
|
15
|
+
export async function detectDirectoryStatus() {
|
|
16
|
+
const rootDir = process.cwd();
|
|
17
|
+
const currentDirName = path.basename(rootDir);
|
|
18
|
+
// 检查是否已经在一个 colyn 项目中(防止嵌套初始化)
|
|
19
|
+
try {
|
|
20
|
+
const existingRoot = await findProjectRoot(rootDir);
|
|
21
|
+
if (existingRoot !== rootDir) {
|
|
22
|
+
throw new ColynError(t('commands.init.alreadyInProject'), t('commands.init.alreadyInProjectHint', { root: existingRoot }));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
// 如果找不到项目根目录,说明不在项目中,可以继续
|
|
27
|
+
if (!(error instanceof ColynError) || !error.message.includes(t('errors.projectRootNotFound'))) {
|
|
28
|
+
throw error;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// 检查关键目录是否存在
|
|
32
|
+
const mainDirPath = path.join(rootDir, currentDirName);
|
|
33
|
+
const worktreesDirPath = path.join(rootDir, 'worktrees');
|
|
34
|
+
const configDirPath = path.join(rootDir, '.colyn');
|
|
35
|
+
const [hasMainDir, hasWorktreesDir, hasConfigDir] = await Promise.all([
|
|
36
|
+
fs.access(mainDirPath).then(() => true).catch(() => false),
|
|
37
|
+
fs.access(worktreesDirPath).then(() => true).catch(() => false),
|
|
38
|
+
fs.access(configDirPath).then(() => true).catch(() => false),
|
|
39
|
+
]);
|
|
40
|
+
// 检查是否为 git 仓库
|
|
41
|
+
const hasGitRepo = await checkIsRepo();
|
|
42
|
+
// 统计目录中的文件数量(包括隐藏文件)
|
|
43
|
+
const entries = await fs.readdir(rootDir);
|
|
44
|
+
const fileCount = entries.length;
|
|
45
|
+
// 判断是否为空目录(完全空,没有任何文件)
|
|
46
|
+
const isEmpty = fileCount === 0;
|
|
47
|
+
// 判断是否已初始化
|
|
48
|
+
const isInitialized = hasMainDir || hasWorktreesDir || hasConfigDir;
|
|
49
|
+
// 确定状态
|
|
50
|
+
let status;
|
|
51
|
+
if (isEmpty) {
|
|
52
|
+
status = DirectoryStatus.Empty;
|
|
53
|
+
}
|
|
54
|
+
else if (isInitialized) {
|
|
55
|
+
status = DirectoryStatus.Initialized;
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
status = DirectoryStatus.ExistingProject;
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
status,
|
|
62
|
+
isEmpty,
|
|
63
|
+
hasMainDir,
|
|
64
|
+
hasWorktreesDir,
|
|
65
|
+
hasConfigDir,
|
|
66
|
+
hasGitRepo,
|
|
67
|
+
fileCount,
|
|
68
|
+
currentDirName
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* 获取端口配置
|
|
73
|
+
* @param options 命令选项
|
|
74
|
+
* @param defaultPort 默认端口号(由插件 portConfig.defaultPort 提供)
|
|
75
|
+
*/
|
|
76
|
+
export async function getPortConfig(options, defaultPort = 10000) {
|
|
77
|
+
// 如果提供了 --port 参数
|
|
78
|
+
if (options.port) {
|
|
79
|
+
const port = parseInt(options.port);
|
|
80
|
+
if (isNaN(port) || port < 1 || port > 65535) {
|
|
81
|
+
throw new ColynError(t('commands.init.invalidPort'), t('commands.init.invalidPortHint'));
|
|
82
|
+
}
|
|
83
|
+
return port;
|
|
84
|
+
}
|
|
85
|
+
// 交互式询问(输出到 stderr,避免被 shell 脚本捕获)
|
|
86
|
+
if (!process.stdin.isTTY) {
|
|
87
|
+
throw new ColynError(t('commands.init.nonInteractivePort'), t('commands.init.nonInteractivePortHint'));
|
|
88
|
+
}
|
|
89
|
+
const { port } = await prompt({
|
|
90
|
+
type: 'input',
|
|
91
|
+
name: 'port',
|
|
92
|
+
message: t('commands.init.enterPort'),
|
|
93
|
+
initial: String(defaultPort),
|
|
94
|
+
stdout: process.stderr,
|
|
95
|
+
validate: (value) => {
|
|
96
|
+
const num = parseInt(value);
|
|
97
|
+
return num > 0 && num < 65536 ? true : t('commands.init.portValidation');
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
return parseInt(port);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* 检查目录名冲突
|
|
104
|
+
*/
|
|
105
|
+
export async function checkDirectoryConflict(rootDir, mainDirName) {
|
|
106
|
+
const mainDirPath = path.join(rootDir, mainDirName);
|
|
107
|
+
try {
|
|
108
|
+
const stats = await fs.stat(mainDirPath);
|
|
109
|
+
// 如果已存在且是文件(不是目录),则报错
|
|
110
|
+
if (stats.isFile()) {
|
|
111
|
+
throw new ColynError(t('commands.init.directoryConflict', { name: mainDirName }), t('commands.init.directoryConflictHint'));
|
|
112
|
+
}
|
|
113
|
+
// 如果是目录,可能是已初始化的情况,不报错
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
// 文件/目录不存在,没有冲突
|
|
117
|
+
if (error.code !== 'ENOENT') {
|
|
118
|
+
throw error;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* 创建目录结构
|
|
124
|
+
*/
|
|
125
|
+
export async function createDirectoryStructure(rootDir, mainDirName, dirInfo) {
|
|
126
|
+
const mainDirPath = path.join(rootDir, mainDirName);
|
|
127
|
+
const worktreesDirPath = path.join(rootDir, 'worktrees');
|
|
128
|
+
const configDirPath = path.join(rootDir, '.colyn');
|
|
129
|
+
// 创建主分支目录
|
|
130
|
+
if (!dirInfo.hasMainDir) {
|
|
131
|
+
await fs.mkdir(mainDirPath, { recursive: true });
|
|
132
|
+
}
|
|
133
|
+
// 创建 worktrees 目录
|
|
134
|
+
if (!dirInfo.hasWorktreesDir) {
|
|
135
|
+
await fs.mkdir(worktreesDirPath, { recursive: true });
|
|
136
|
+
}
|
|
137
|
+
// 创建 .colyn 目录
|
|
138
|
+
await fs.mkdir(configDirPath, { recursive: true });
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* 移动文件到主分支目录
|
|
142
|
+
*/
|
|
143
|
+
export async function moveFilesToMainDir(rootDir, mainDirName) {
|
|
144
|
+
const spinner = ora({ text: t('commands.init.movingFiles'), stream: process.stderr }).start();
|
|
145
|
+
try {
|
|
146
|
+
const mainDirPath = path.join(rootDir, mainDirName);
|
|
147
|
+
const entries = await fs.readdir(rootDir);
|
|
148
|
+
// 需要排除的目录(不移动)
|
|
149
|
+
const excludeDirs = new Set([mainDirName, 'worktrees', '.colyn']);
|
|
150
|
+
for (const entry of entries) {
|
|
151
|
+
// 跳过新创建的目录
|
|
152
|
+
if (excludeDirs.has(entry)) {
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
const sourcePath = path.join(rootDir, entry);
|
|
156
|
+
const targetPath = path.join(mainDirPath, entry);
|
|
157
|
+
// 移动文件或目录
|
|
158
|
+
await fs.rename(sourcePath, targetPath);
|
|
159
|
+
spinner.text = t('commands.init.moving', { file: entry });
|
|
160
|
+
}
|
|
161
|
+
spinner.succeed(t('commands.init.filesMoved'));
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
spinner.fail(t('commands.init.moveFilesFailed'));
|
|
165
|
+
throw new ColynError(t('commands.init.moveFilesError'), t('commands.init.moveFilesErrorHint'));
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* 配置 .env.local 文件
|
|
170
|
+
*/
|
|
171
|
+
export async function configureEnvFile(mainDirPath, port, worktree) {
|
|
172
|
+
const spinner = ora({ text: t('commands.init.configuringEnv'), stream: process.stderr }).start();
|
|
173
|
+
try {
|
|
174
|
+
const envFilePath = path.join(mainDirPath, '.env.local');
|
|
175
|
+
// 需要添加的环境变量
|
|
176
|
+
const requiredEnv = {
|
|
177
|
+
PORT: port.toString(),
|
|
178
|
+
WORKTREE: worktree
|
|
179
|
+
};
|
|
180
|
+
// 智能合并
|
|
181
|
+
await updateEnvFilePreserveComments(envFilePath, requiredEnv);
|
|
182
|
+
spinner.succeed(t('commands.init.envConfigured'));
|
|
183
|
+
}
|
|
184
|
+
catch (error) {
|
|
185
|
+
spinner.fail(t('commands.init.envConfigFailed'));
|
|
186
|
+
throw error;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* 配置 .gitignore 文件
|
|
191
|
+
*/
|
|
192
|
+
export async function configureGitignore(mainDirPath) {
|
|
193
|
+
const spinner = ora({ text: t('commands.init.configuringGitignore'), stream: process.stderr }).start();
|
|
194
|
+
try {
|
|
195
|
+
const gitignorePath = path.join(mainDirPath, '.gitignore');
|
|
196
|
+
// 读取现有 .gitignore
|
|
197
|
+
let content = '';
|
|
198
|
+
try {
|
|
199
|
+
content = await fs.readFile(gitignorePath, 'utf-8');
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
// 文件不存在,创建新的
|
|
203
|
+
}
|
|
204
|
+
// 检查是否已有忽略规则
|
|
205
|
+
const hasEnvLocalRule = content.includes('.env.local');
|
|
206
|
+
const hasLocalRule = content.includes('*.local');
|
|
207
|
+
// 如果都没有,添加 .env.local 规则
|
|
208
|
+
if (!hasEnvLocalRule && !hasLocalRule) {
|
|
209
|
+
const newContent = content.trim()
|
|
210
|
+
? `${content}\n\n# Environment files\n.env.local\n`
|
|
211
|
+
: '# Environment files\n.env.local\n';
|
|
212
|
+
await fs.writeFile(gitignorePath, newContent, 'utf-8');
|
|
213
|
+
spinner.succeed(t('commands.init.gitignoreConfigured'));
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
spinner.succeed(t('commands.init.gitignoreSkipped'));
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
catch (error) {
|
|
220
|
+
spinner.fail(t('commands.init.gitignoreFailed'));
|
|
221
|
+
throw error;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* 显示成功信息(输出到 stderr)
|
|
226
|
+
*/
|
|
227
|
+
export function displaySuccessInfo(mainDirName, port, mainBranch) {
|
|
228
|
+
outputLine();
|
|
229
|
+
outputSuccess(t('commands.init.successTitle') + '\n');
|
|
230
|
+
outputBold(t('commands.init.directoryStructure'));
|
|
231
|
+
output(' .');
|
|
232
|
+
output(` \u251C\u2500\u2500 ${mainDirName}/ ${t('commands.init.mainDirComment')}`);
|
|
233
|
+
output(` \u251C\u2500\u2500 worktrees/ ${t('commands.init.worktreesDirComment')}`);
|
|
234
|
+
output(` \u2514\u2500\u2500 .colyn/ ${t('commands.init.configDirComment')}`);
|
|
235
|
+
outputLine();
|
|
236
|
+
outputBold(t('commands.init.configInfo'));
|
|
237
|
+
output(` ${t('commands.init.mainBranch', { branch: mainBranch })}`);
|
|
238
|
+
if (port !== undefined) {
|
|
239
|
+
output(` ${t('commands.init.port', { port: String(port) })}`);
|
|
240
|
+
}
|
|
241
|
+
outputLine();
|
|
242
|
+
outputBold(t('commands.init.nextSteps'));
|
|
243
|
+
outputStep(` ${t('commands.init.step1CreateWorktree')}`);
|
|
244
|
+
output(' colyn add <branch-name>');
|
|
245
|
+
outputLine();
|
|
246
|
+
outputStep(` ${t('commands.init.step2ListWorktrees')}`);
|
|
247
|
+
output(' colyn list');
|
|
248
|
+
outputLine();
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* 显示空目录成功信息(输出到 stderr)
|
|
252
|
+
*/
|
|
253
|
+
export function displayEmptyDirectorySuccess(mainDirName, _port, _mainBranch) {
|
|
254
|
+
outputLine();
|
|
255
|
+
outputSuccess(t('commands.init.successTitle') + '\n');
|
|
256
|
+
outputBold(t('commands.init.directoryStructure'));
|
|
257
|
+
output(' .');
|
|
258
|
+
output(` \u251C\u2500\u2500 ${mainDirName}/ ${t('commands.init.mainDirCommentEmpty')}`);
|
|
259
|
+
output(` \u251C\u2500\u2500 worktrees/ ${t('commands.init.worktreesDirComment')}`);
|
|
260
|
+
output(` \u2514\u2500\u2500 .colyn/ ${t('commands.init.configDirComment')}`);
|
|
261
|
+
outputLine();
|
|
262
|
+
outputBold(t('commands.init.nextSteps'));
|
|
263
|
+
outputStep(` ${t('commands.init.step1EnterDir')}`);
|
|
264
|
+
output(` cd ${mainDirName}`);
|
|
265
|
+
outputLine();
|
|
266
|
+
outputStep(` ${t('commands.init.step2InitGit')}`);
|
|
267
|
+
output(' git init');
|
|
268
|
+
outputLine();
|
|
269
|
+
outputStep(` ${t('commands.init.step3InitProject')}`);
|
|
270
|
+
outputLine();
|
|
271
|
+
outputStep(` ${t('commands.init.step4CreateWorktree')}`);
|
|
272
|
+
output(' colyn add <branch-name>');
|
|
273
|
+
outputLine();
|
|
274
|
+
}
|
|
275
|
+
//# sourceMappingURL=init.helpers.js.map
|