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,247 @@
|
|
|
1
|
+
import * as fs from 'fs/promises';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import simpleGit from 'simple-git';
|
|
4
|
+
import { ColynError } from '../types/index.js';
|
|
5
|
+
import { t } from '../i18n/index.js';
|
|
6
|
+
/**
|
|
7
|
+
* 从 .env.local 文件解析环境变量
|
|
8
|
+
*/
|
|
9
|
+
async function parseEnvFile(filePath) {
|
|
10
|
+
try {
|
|
11
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
12
|
+
const env = {};
|
|
13
|
+
const lines = content.split('\n');
|
|
14
|
+
for (const line of lines) {
|
|
15
|
+
const trimmed = line.trim();
|
|
16
|
+
// 跳过注释和空行
|
|
17
|
+
if (trimmed.startsWith('#') || trimmed === '') {
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
// 解析环境变量
|
|
21
|
+
const match = trimmed.match(/^([^=]+)=(.*)$/);
|
|
22
|
+
if (match) {
|
|
23
|
+
const key = match[1].trim();
|
|
24
|
+
const value = match[2].trim();
|
|
25
|
+
env[key] = value;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return env;
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return {};
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 从主分支目录获取当前分支名称
|
|
36
|
+
*/
|
|
37
|
+
export async function getMainBranch(mainDir) {
|
|
38
|
+
try {
|
|
39
|
+
const git = simpleGit(mainDir);
|
|
40
|
+
const branchSummary = await git.branch();
|
|
41
|
+
return branchSummary.current;
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// 如果获取失败,默认使用 'main'
|
|
45
|
+
return 'main';
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* 从主分支的 .env.local 获取端口
|
|
50
|
+
*/
|
|
51
|
+
export async function getMainPort(mainDir) {
|
|
52
|
+
const envPath = path.join(mainDir, '.env.local');
|
|
53
|
+
const env = await parseEnvFile(envPath);
|
|
54
|
+
const port = parseInt(env.PORT || '');
|
|
55
|
+
if (isNaN(port)) {
|
|
56
|
+
throw new ColynError(t('errors.cannotGetMainPort'), t('errors.cannotGetMainPortHint', { path: envPath }));
|
|
57
|
+
}
|
|
58
|
+
return port;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* 扫描 worktrees 目录获取下一个可用 ID
|
|
62
|
+
*/
|
|
63
|
+
export async function getNextWorktreeId(worktreesDir) {
|
|
64
|
+
try {
|
|
65
|
+
const entries = await fs.readdir(worktreesDir);
|
|
66
|
+
const ids = entries
|
|
67
|
+
.filter(e => e.startsWith('task-'))
|
|
68
|
+
.map(e => parseInt(e.replace('task-', '')))
|
|
69
|
+
.filter(n => !isNaN(n));
|
|
70
|
+
return ids.length > 0 ? Math.max(...ids) + 1 : 1;
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
// 目录不存在或无法读取,返回 1
|
|
74
|
+
return 1;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* 发现所有 worktree 信息
|
|
79
|
+
* 结合 git worktree list 和各目录的 .env.local
|
|
80
|
+
*/
|
|
81
|
+
export async function discoverWorktrees(mainDir, worktreesDir) {
|
|
82
|
+
const worktrees = [];
|
|
83
|
+
try {
|
|
84
|
+
// 使用 git worktree list --porcelain 获取所有 worktree
|
|
85
|
+
const git = simpleGit(mainDir);
|
|
86
|
+
const result = await git.raw(['worktree', 'list', '--porcelain']);
|
|
87
|
+
// 解析 porcelain 输出
|
|
88
|
+
const blocks = result.trim().split('\n\n');
|
|
89
|
+
for (const block of blocks) {
|
|
90
|
+
const lines = block.split('\n');
|
|
91
|
+
let worktreePath = '';
|
|
92
|
+
let branch = '';
|
|
93
|
+
for (const line of lines) {
|
|
94
|
+
if (line.startsWith('worktree ')) {
|
|
95
|
+
worktreePath = line.substring(9);
|
|
96
|
+
}
|
|
97
|
+
else if (line.startsWith('branch ')) {
|
|
98
|
+
// 格式: branch refs/heads/feature/xxx
|
|
99
|
+
branch = line.substring(7).replace('refs/heads/', '');
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// 只处理 worktrees 目录下的 worktree(排除主分支)
|
|
103
|
+
if (worktreePath && worktreePath.startsWith(worktreesDir)) {
|
|
104
|
+
const dirName = path.basename(worktreePath);
|
|
105
|
+
const idMatch = dirName.match(/^task-(\d+)$/);
|
|
106
|
+
if (idMatch) {
|
|
107
|
+
const id = parseInt(idMatch[1]);
|
|
108
|
+
const envPath = path.join(worktreePath, '.env.local');
|
|
109
|
+
const env = await parseEnvFile(envPath);
|
|
110
|
+
const port = parseInt(env.PORT || '0');
|
|
111
|
+
// 获取目录创建时间作为 createdAt
|
|
112
|
+
let createdAt = new Date().toISOString();
|
|
113
|
+
try {
|
|
114
|
+
const stats = await fs.stat(worktreePath);
|
|
115
|
+
createdAt = stats.birthtime.toISOString();
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
// 忽略错误,使用当前时间
|
|
119
|
+
}
|
|
120
|
+
worktrees.push({
|
|
121
|
+
id,
|
|
122
|
+
branch: branch || 'unknown',
|
|
123
|
+
path: worktreePath,
|
|
124
|
+
port,
|
|
125
|
+
createdAt
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
// 按 ID 排序
|
|
131
|
+
worktrees.sort((a, b) => a.id - b.id);
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
// 如果 git worktree list 失败,尝试直接扫描目录
|
|
135
|
+
try {
|
|
136
|
+
const entries = await fs.readdir(worktreesDir);
|
|
137
|
+
for (const entry of entries) {
|
|
138
|
+
if (entry.startsWith('task-')) {
|
|
139
|
+
const idMatch = entry.match(/^task-(\d+)$/);
|
|
140
|
+
if (idMatch) {
|
|
141
|
+
const id = parseInt(idMatch[1]);
|
|
142
|
+
const worktreePath = path.join(worktreesDir, entry);
|
|
143
|
+
const envPath = path.join(worktreePath, '.env.local');
|
|
144
|
+
const env = await parseEnvFile(envPath);
|
|
145
|
+
const port = parseInt(env.PORT || '0');
|
|
146
|
+
// 尝试获取分支名
|
|
147
|
+
let branch = 'unknown';
|
|
148
|
+
try {
|
|
149
|
+
const git = simpleGit(worktreePath);
|
|
150
|
+
const branchSummary = await git.branch();
|
|
151
|
+
branch = branchSummary.current;
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
// 忽略错误
|
|
155
|
+
}
|
|
156
|
+
// 获取目录创建时间
|
|
157
|
+
let createdAt = new Date().toISOString();
|
|
158
|
+
try {
|
|
159
|
+
const stats = await fs.stat(worktreePath);
|
|
160
|
+
createdAt = stats.birthtime.toISOString();
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
// 忽略错误
|
|
164
|
+
}
|
|
165
|
+
worktrees.push({
|
|
166
|
+
id,
|
|
167
|
+
branch,
|
|
168
|
+
path: worktreePath,
|
|
169
|
+
port,
|
|
170
|
+
createdAt
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
worktrees.sort((a, b) => a.id - b.id);
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
// 目录不存在或无法读取
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return worktrees;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* 获取完整的项目信息
|
|
185
|
+
* 这是获取项目配置的主入口,替代原来的 loadConfig
|
|
186
|
+
*/
|
|
187
|
+
export async function discoverProjectInfo(mainDir, worktreesDir) {
|
|
188
|
+
const [mainBranch, mainPort, nextWorktreeId, worktrees] = await Promise.all([
|
|
189
|
+
getMainBranch(mainDir),
|
|
190
|
+
getMainPort(mainDir),
|
|
191
|
+
getNextWorktreeId(worktreesDir),
|
|
192
|
+
discoverWorktrees(mainDir, worktreesDir)
|
|
193
|
+
]);
|
|
194
|
+
return {
|
|
195
|
+
mainBranch,
|
|
196
|
+
mainPort,
|
|
197
|
+
nextWorktreeId,
|
|
198
|
+
worktrees
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* 检查分支是否已有 worktree
|
|
203
|
+
*/
|
|
204
|
+
export async function findWorktreeByBranch(mainDir, worktreesDir, branch) {
|
|
205
|
+
const worktrees = await discoverWorktrees(mainDir, worktreesDir);
|
|
206
|
+
return worktrees.find(w => w.branch === branch);
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* 获取当前目录的 worktree ID
|
|
210
|
+
*
|
|
211
|
+
* 从当前目录的 .env.local 读取 WORKTREE 变量,并验证与目录名一致
|
|
212
|
+
*
|
|
213
|
+
* @returns worktree ID,如果不在 worktree 目录中返回 null
|
|
214
|
+
* @throws ColynError 如果 .env.local 中的 WORKTREE 与目录名不一致
|
|
215
|
+
*/
|
|
216
|
+
export async function getCurrentWorktreeId() {
|
|
217
|
+
const cwd = process.cwd();
|
|
218
|
+
const dirName = path.basename(cwd);
|
|
219
|
+
// 检查当前目录名是否符合 task-{id} 格式
|
|
220
|
+
const dirMatch = dirName.match(/^task-(\d+)$/);
|
|
221
|
+
if (!dirMatch) {
|
|
222
|
+
// 不在 worktree 目录中
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
const dirId = parseInt(dirMatch[1]);
|
|
226
|
+
// 读取 .env.local 文件
|
|
227
|
+
const envPath = path.join(cwd, '.env.local');
|
|
228
|
+
const env = await parseEnvFile(envPath);
|
|
229
|
+
const envWorktree = env.WORKTREE;
|
|
230
|
+
if (!envWorktree) {
|
|
231
|
+
throw new ColynError(t('errors.worktreeConfigIncomplete'), t('errors.worktreeConfigIncompleteHint', { path: envPath }));
|
|
232
|
+
}
|
|
233
|
+
const envId = parseInt(envWorktree);
|
|
234
|
+
if (isNaN(envId)) {
|
|
235
|
+
throw new ColynError(t('errors.worktreeConfigInvalid'), t('errors.worktreeConfigInvalidHint', { value: envWorktree, path: envPath }));
|
|
236
|
+
}
|
|
237
|
+
// 验证 .env.local 中的 WORKTREE 与目录名一致
|
|
238
|
+
if (envId !== dirId) {
|
|
239
|
+
throw new ColynError(t('errors.worktreeConfigMismatch'), t('errors.worktreeConfigMismatchHint', {
|
|
240
|
+
dirName,
|
|
241
|
+
dirId: String(dirId),
|
|
242
|
+
envId: String(envId)
|
|
243
|
+
}));
|
|
244
|
+
}
|
|
245
|
+
return envId;
|
|
246
|
+
}
|
|
247
|
+
//# sourceMappingURL=discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../src/core/discovery.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 读取环境变量文件
|
|
3
|
+
*/
|
|
4
|
+
export declare function readEnvFile(filePath: string): Promise<Record<string, string>>;
|
|
5
|
+
/**
|
|
6
|
+
* 写入环境变量文件
|
|
7
|
+
*/
|
|
8
|
+
export declare function writeEnvFile(filePath: string, env: Record<string, string>): Promise<void>;
|
|
9
|
+
/**
|
|
10
|
+
* 更新环境变量文件(保留注释)
|
|
11
|
+
*/
|
|
12
|
+
export declare function updateEnvFilePreserveComments(filePath: string, updates: Record<string, string>): Promise<void>;
|
|
13
|
+
//# sourceMappingURL=env.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../src/core/env.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,wBAAsB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CASnF;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC1B,OAAO,CAAC,IAAI,CAAC,CAQf;AAED;;GAEG;AACH,wBAAsB,6BAA6B,CACjD,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC9B,OAAO,CAAC,IAAI,CAAC,CA+Cf"}
|
package/dist/core/env.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import * as fs from 'fs/promises';
|
|
2
|
+
import dotenv from 'dotenv';
|
|
3
|
+
/**
|
|
4
|
+
* 读取环境变量文件
|
|
5
|
+
*/
|
|
6
|
+
export async function readEnvFile(filePath) {
|
|
7
|
+
try {
|
|
8
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
9
|
+
const parsed = dotenv.parse(content);
|
|
10
|
+
return parsed;
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
// 文件不存在,返回空对象
|
|
14
|
+
return {};
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* 写入环境变量文件
|
|
19
|
+
*/
|
|
20
|
+
export async function writeEnvFile(filePath, env) {
|
|
21
|
+
const lines = Object.entries(env).map(([key, value]) => {
|
|
22
|
+
// 如果值包含空格或特殊字符,需要加引号
|
|
23
|
+
const needsQuotes = /\s|[#"']/.test(value);
|
|
24
|
+
return `${key}=${needsQuotes ? `"${value}"` : value}`;
|
|
25
|
+
});
|
|
26
|
+
await fs.writeFile(filePath, lines.join('\n') + '\n', 'utf-8');
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* 更新环境变量文件(保留注释)
|
|
30
|
+
*/
|
|
31
|
+
export async function updateEnvFilePreserveComments(filePath, updates) {
|
|
32
|
+
let content = '';
|
|
33
|
+
try {
|
|
34
|
+
content = await fs.readFile(filePath, 'utf-8');
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// 文件不存在,创建新的
|
|
38
|
+
await writeEnvFile(filePath, updates);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const lines = content.split('\n');
|
|
42
|
+
const result = [];
|
|
43
|
+
const updatedKeys = new Set();
|
|
44
|
+
for (const line of lines) {
|
|
45
|
+
const trimmed = line.trim();
|
|
46
|
+
// 保留注释和空行
|
|
47
|
+
if (trimmed.startsWith('#') || trimmed === '') {
|
|
48
|
+
result.push(line);
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
// 解析 key=value
|
|
52
|
+
const match = trimmed.match(/^([^=]+)=(.*)$/);
|
|
53
|
+
if (match) {
|
|
54
|
+
const key = match[1].trim();
|
|
55
|
+
if (updates[key] !== undefined) {
|
|
56
|
+
result.push(`${key}=${updates[key]}`);
|
|
57
|
+
updatedKeys.add(key);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
result.push(line);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
result.push(line);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// 添加新的环境变量
|
|
68
|
+
for (const [key, value] of Object.entries(updates)) {
|
|
69
|
+
if (!updatedKeys.has(key)) {
|
|
70
|
+
result.push(`${key}=${value}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
await fs.writeFile(filePath, result.join('\n') + '\n', 'utf-8');
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=env.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../../src/core/env.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
interface GitStatusLike {
|
|
2
|
+
modified: string[];
|
|
3
|
+
created: string[];
|
|
4
|
+
deleted: string[];
|
|
5
|
+
renamed: Array<{
|
|
6
|
+
to: string;
|
|
7
|
+
}>;
|
|
8
|
+
not_added: string[];
|
|
9
|
+
}
|
|
10
|
+
export declare function getRelevantStatusFiles(status: GitStatusLike): string[];
|
|
11
|
+
/**
|
|
12
|
+
* 检查是否为 git 仓库
|
|
13
|
+
* @param dir 要检查的目录,默认为当前目录
|
|
14
|
+
*/
|
|
15
|
+
export declare function checkIsRepo(dir?: string): Promise<boolean>;
|
|
16
|
+
/**
|
|
17
|
+
* 检查工作目录是否干净
|
|
18
|
+
*/
|
|
19
|
+
export declare function checkWorkingDirectoryClean(): Promise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* 获取当前分支名称
|
|
22
|
+
* @param dir 工作目录,默认为当前目录
|
|
23
|
+
* @returns 当前分支名称
|
|
24
|
+
*/
|
|
25
|
+
export declare function getCurrentBranch(dir?: string): Promise<string>;
|
|
26
|
+
/**
|
|
27
|
+
* 检测主分支名称
|
|
28
|
+
*/
|
|
29
|
+
export declare function detectMainBranch(): Promise<string>;
|
|
30
|
+
export {};
|
|
31
|
+
//# sourceMappingURL=git.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../src/core/git.ts"],"names":[],"mappings":"AAKA,UAAU,aAAa;IACrB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/B,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAID,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,EAAE,CAUtE;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAGhE;AAED;;GAEG;AACH,wBAAsB,0BAA0B,IAAI,OAAO,CAAC,IAAI,CAAC,CAUhE;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAUpE;AAED;;GAEG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC,CAExD"}
|
package/dist/core/git.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import simpleGit from 'simple-git';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { ColynError } from '../types/index.js';
|
|
4
|
+
import { t } from '../i18n/index.js';
|
|
5
|
+
const IGNORED_STATUS_BASENAMES = new Set(['.env.local']);
|
|
6
|
+
export function getRelevantStatusFiles(status) {
|
|
7
|
+
const changedFiles = [
|
|
8
|
+
...status.modified,
|
|
9
|
+
...status.created,
|
|
10
|
+
...status.deleted,
|
|
11
|
+
...status.renamed.map(r => r.to),
|
|
12
|
+
...status.not_added
|
|
13
|
+
];
|
|
14
|
+
return changedFiles.filter((file) => !IGNORED_STATUS_BASENAMES.has(path.basename(file)));
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* 检查是否为 git 仓库
|
|
18
|
+
* @param dir 要检查的目录,默认为当前目录
|
|
19
|
+
*/
|
|
20
|
+
export async function checkIsRepo(dir) {
|
|
21
|
+
const git = simpleGit(dir);
|
|
22
|
+
return await git.checkIsRepo();
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* 检查工作目录是否干净
|
|
26
|
+
*/
|
|
27
|
+
export async function checkWorkingDirectoryClean() {
|
|
28
|
+
const git = simpleGit();
|
|
29
|
+
const status = await git.status();
|
|
30
|
+
if (getRelevantStatusFiles(status).length > 0) {
|
|
31
|
+
throw new ColynError(t('errors.workingDirNotClean'), t('errors.workingDirNotCleanHint'));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 获取当前分支名称
|
|
36
|
+
* @param dir 工作目录,默认为当前目录
|
|
37
|
+
* @returns 当前分支名称
|
|
38
|
+
*/
|
|
39
|
+
export async function getCurrentBranch(dir) {
|
|
40
|
+
const git = simpleGit(dir);
|
|
41
|
+
try {
|
|
42
|
+
const branchSummary = await git.branch();
|
|
43
|
+
return branchSummary.current;
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
// 如果获取失败,默认返回 'main'
|
|
47
|
+
return 'main';
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* 检测主分支名称
|
|
52
|
+
*/
|
|
53
|
+
export async function detectMainBranch() {
|
|
54
|
+
return await getCurrentBranch();
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=git.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/core/git.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,YAAY,CAAC;AACnC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,CAAC,EAAE,MAAM,kBAAkB,CAAC;AAUrC,MAAM,wBAAwB,GAAG,IAAI,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC;AAEzD,MAAM,UAAU,sBAAsB,CAAC,MAAqB;IAC1D,MAAM,YAAY,GAAG;QACnB,GAAG,MAAM,CAAC,QAAQ;QAClB,GAAG,MAAM,CAAC,OAAO;QACjB,GAAG,MAAM,CAAC,OAAO;QACjB,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChC,GAAG,MAAM,CAAC,SAAS;KACpB,CAAC;IAEF,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,wBAAwB,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC3F,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,GAAY;IAC5C,MAAM,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IAC3B,OAAO,MAAM,GAAG,CAAC,WAAW,EAAE,CAAC;AACjC,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B;IAC9C,MAAM,GAAG,GAAG,SAAS,EAAE,CAAC;IACxB,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC;IAElC,IAAI,sBAAsB,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9C,MAAM,IAAI,UAAU,CAClB,CAAC,CAAC,2BAA2B,CAAC,EAC9B,CAAC,CAAC,+BAA+B,CAAC,CACnC,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,GAAY;IACjD,MAAM,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IAE3B,IAAI,CAAC;QACH,MAAM,aAAa,GAAG,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC;QACzC,OAAO,aAAa,CAAC,OAAO,CAAC;IAC/B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,qBAAqB;QACrB,OAAO,MAAM,CAAC;IAChB,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,OAAO,MAAM,gBAAgB,EAAE,CAAC;AAClC,CAAC"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 项目路径信息
|
|
3
|
+
*/
|
|
4
|
+
export interface ProjectPaths {
|
|
5
|
+
/** 项目根目录(包含 .colyn 的目录) */
|
|
6
|
+
rootDir: string;
|
|
7
|
+
/** 主分支目录名称 */
|
|
8
|
+
mainDirName: string;
|
|
9
|
+
/** 主分支目录完整路径 */
|
|
10
|
+
mainDir: string;
|
|
11
|
+
/** worktrees 目录完整路径 */
|
|
12
|
+
worktreesDir: string;
|
|
13
|
+
/** .colyn 配置目录完整路径 */
|
|
14
|
+
configDir: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* 当前 worktree 信息
|
|
18
|
+
*/
|
|
19
|
+
export interface CurrentWorktreeInfo {
|
|
20
|
+
/** 是否在 worktree 目录中 */
|
|
21
|
+
isWorktree: boolean;
|
|
22
|
+
/** worktree ID(如果在 worktree 中) */
|
|
23
|
+
worktreeId?: number;
|
|
24
|
+
/** 当前目录路径 */
|
|
25
|
+
currentDir: string;
|
|
26
|
+
/** 相对于根目录的路径 */
|
|
27
|
+
relativeToRoot?: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* 从当前目录向上查找项目根目录
|
|
31
|
+
* 根目录的标志是包含 .colyn 目录,并且通过多重验证确保是有效的 colyn 项目
|
|
32
|
+
*/
|
|
33
|
+
export declare function findProjectRoot(startDir?: string): Promise<string>;
|
|
34
|
+
/**
|
|
35
|
+
* 获取项目所有相关路径
|
|
36
|
+
*/
|
|
37
|
+
export declare function getProjectPaths(startDir?: string): Promise<ProjectPaths>;
|
|
38
|
+
/**
|
|
39
|
+
* 获取当前 worktree 信息
|
|
40
|
+
* 通过读取 .env.local 文件中的 WORKTREE 变量来判断
|
|
41
|
+
*/
|
|
42
|
+
export declare function getCurrentWorktreeInfo(startDir?: string): Promise<CurrentWorktreeInfo>;
|
|
43
|
+
/**
|
|
44
|
+
* 完整的当前位置信息
|
|
45
|
+
*/
|
|
46
|
+
export interface LocationInfo {
|
|
47
|
+
/** 项目名(主目录名) */
|
|
48
|
+
project: string;
|
|
49
|
+
/** 项目根目录完整路径 */
|
|
50
|
+
projectPath: string;
|
|
51
|
+
/** 主分支目录完整路径 */
|
|
52
|
+
mainBranchPath: string;
|
|
53
|
+
/** worktree ID(主分支为 0) */
|
|
54
|
+
worktreeId: number;
|
|
55
|
+
/** worktree 目录名 */
|
|
56
|
+
worktreeDir: string;
|
|
57
|
+
/** worktree 完整路径 */
|
|
58
|
+
worktreePath: string;
|
|
59
|
+
/** 当前分支 */
|
|
60
|
+
branch: string;
|
|
61
|
+
/** 是否在主分支目录 */
|
|
62
|
+
isMainBranch: boolean;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* 获取当前位置的完整信息
|
|
66
|
+
* 用于 info 命令
|
|
67
|
+
*/
|
|
68
|
+
export declare function getLocationInfo(startDir?: string): Promise<LocationInfo>;
|
|
69
|
+
/**
|
|
70
|
+
* 验证目录存在
|
|
71
|
+
*/
|
|
72
|
+
export declare function validateDirectoryExists(dirPath: string, errorMessage: string): Promise<void>;
|
|
73
|
+
/**
|
|
74
|
+
* 验证项目已初始化
|
|
75
|
+
*/
|
|
76
|
+
export declare function validateProjectInitialized(paths: ProjectPaths): Promise<void>;
|
|
77
|
+
/**
|
|
78
|
+
* 获取指定目录相对于根目录的简短描述
|
|
79
|
+
*/
|
|
80
|
+
export declare function getDirectoryDescription(currentDir: string, paths: ProjectPaths): string;
|
|
81
|
+
/**
|
|
82
|
+
* 切换到指定目录执行操作
|
|
83
|
+
* 执行完成后恢复原目录
|
|
84
|
+
*/
|
|
85
|
+
export declare function executeInDirectory<T>(targetDir: string, operation: () => Promise<T>): Promise<T>;
|
|
86
|
+
//# sourceMappingURL=paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/core/paths.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,2BAA2B;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,uBAAuB;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,sBAAsB;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,uBAAuB;IACvB,UAAU,EAAE,OAAO,CAAC;IACpB,kCAAkC;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AA+BD;;;GAGG;AACH,wBAAsB,eAAe,CAAC,QAAQ,GAAE,MAAsB,GAAG,OAAO,CAAC,MAAM,CAAC,CAkCvF;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,QAAQ,GAAE,MAAsB,GAAG,OAAO,CAAC,YAAY,CAAC,CAW7F;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,CAC1C,QAAQ,GAAE,MAAsB,GAC/B,OAAO,CAAC,mBAAmB,CAAC,CAyD9B;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,gBAAgB;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,0BAA0B;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,mBAAmB;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,oBAAoB;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW;IACX,MAAM,EAAE,MAAM,CAAC;IACf,eAAe;IACf,YAAY,EAAE,OAAO,CAAC;CACvB;AAED;;;GAGG;AACH,wBAAsB,eAAe,CACnC,QAAQ,GAAE,MAAsB,GAC/B,OAAO,CAAC,YAAY,CAAC,CA+DvB;AAED;;GAEG;AACH,wBAAsB,uBAAuB,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAYlG;AAED;;GAEG;AACH,wBAAsB,0BAA0B,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAsBnF;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,YAAY,GAClB,MAAM,CAoBR;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,CAAC,EACxC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAC1B,OAAO,CAAC,CAAC,CAAC,CASZ"}
|