clawt 1.0.0
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/.claude/agent-memory/docs-sync-updater/MEMORY.md +48 -0
- package/.claude/agents/docs-sync-updater.md +128 -0
- package/CLAUDE.md +71 -0
- package/README.md +168 -0
- package/dist/index.js +923 -0
- package/dist/postinstall.js +71 -0
- package/docs/spec.md +710 -0
- package/package.json +38 -0
- package/scripts/postinstall.ts +116 -0
- package/src/commands/create.ts +49 -0
- package/src/commands/list.ts +45 -0
- package/src/commands/merge.ts +142 -0
- package/src/commands/remove.ts +127 -0
- package/src/commands/run.ts +310 -0
- package/src/commands/validate.ts +137 -0
- package/src/constants/branch.ts +6 -0
- package/src/constants/config.ts +8 -0
- package/src/constants/exitCodes.ts +9 -0
- package/src/constants/index.ts +6 -0
- package/src/constants/messages.ts +61 -0
- package/src/constants/paths.ts +14 -0
- package/src/constants/terminal.ts +13 -0
- package/src/errors/index.ts +20 -0
- package/src/index.ts +55 -0
- package/src/logger/index.ts +34 -0
- package/src/types/claudeCode.ts +14 -0
- package/src/types/command.ts +39 -0
- package/src/types/config.ts +7 -0
- package/src/types/index.ts +5 -0
- package/src/types/taskResult.ts +31 -0
- package/src/types/worktree.ts +7 -0
- package/src/utils/branch.ts +51 -0
- package/src/utils/config.ts +35 -0
- package/src/utils/formatter.ts +67 -0
- package/src/utils/fs.ts +28 -0
- package/src/utils/git.ts +243 -0
- package/src/utils/index.ts +35 -0
- package/src/utils/prompt.ts +18 -0
- package/src/utils/shell.ts +53 -0
- package/src/utils/validation.ts +48 -0
- package/src/utils/worktree.ts +107 -0
- package/tsconfig.json +17 -0
- package/tsup.config.ts +25 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import { existsSync, readdirSync } from 'node:fs';
|
|
3
|
+
import { WORKTREES_DIR } from '../constants/index.js';
|
|
4
|
+
import { logger } from '../logger/index.js';
|
|
5
|
+
import { createWorktree as gitCreateWorktree, getProjectName, gitWorktreeList, removeWorktreeByPath, deleteBranch, gitWorktreePrune } from './git.js';
|
|
6
|
+
import { sanitizeBranchName, generateBranchNames, validateBranchesNotExist } from './branch.js';
|
|
7
|
+
import { ensureDir, removeEmptyDir } from './fs.js';
|
|
8
|
+
import type { WorktreeInfo } from '../types/index.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 获取当前项目的 worktree 存放目录
|
|
12
|
+
* @returns {string} 项目 worktree 目录路径
|
|
13
|
+
*/
|
|
14
|
+
export function getProjectWorktreeDir(): string {
|
|
15
|
+
const projectName = getProjectName();
|
|
16
|
+
return join(WORKTREES_DIR, projectName);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 批量创建 worktree(串行执行)
|
|
21
|
+
* 包含完整的校验流程:分支名清理 → 分支存在性检查 → 创建
|
|
22
|
+
* @param {string} branchName - 基础分支名
|
|
23
|
+
* @param {number} count - 创建数量
|
|
24
|
+
* @returns {WorktreeInfo[]} 创建的 worktree 信息列表
|
|
25
|
+
*/
|
|
26
|
+
export function createWorktrees(branchName: string, count: number): WorktreeInfo[] {
|
|
27
|
+
// 1. 分支名清理
|
|
28
|
+
const sanitized = sanitizeBranchName(branchName);
|
|
29
|
+
|
|
30
|
+
// 2. 生成分支名列表
|
|
31
|
+
const branchNames = generateBranchNames(sanitized, count);
|
|
32
|
+
|
|
33
|
+
// 3. 校验所有分支是否都不存在(在创建任何 worktree 之前)
|
|
34
|
+
validateBranchesNotExist(branchNames);
|
|
35
|
+
|
|
36
|
+
// 4. 确保项目 worktree 目录存在
|
|
37
|
+
const projectDir = getProjectWorktreeDir();
|
|
38
|
+
ensureDir(projectDir);
|
|
39
|
+
|
|
40
|
+
// 5. 串行创建 worktree
|
|
41
|
+
const results: WorktreeInfo[] = [];
|
|
42
|
+
for (const name of branchNames) {
|
|
43
|
+
const worktreePath = join(projectDir, name);
|
|
44
|
+
gitCreateWorktree(name, worktreePath);
|
|
45
|
+
results.push({ path: worktreePath, branch: name });
|
|
46
|
+
logger.info(`worktree 创建完成: ${worktreePath} (分支: ${name})`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return results;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* 获取当前项目在 ~/.clawt/worktrees/<project>/ 下的所有 worktree
|
|
54
|
+
* 通过与 git worktree list 交叉验证确认有效性
|
|
55
|
+
* @returns {WorktreeInfo[]} 有效的 worktree 列表
|
|
56
|
+
*/
|
|
57
|
+
export function getProjectWorktrees(): WorktreeInfo[] {
|
|
58
|
+
const projectDir = getProjectWorktreeDir();
|
|
59
|
+
|
|
60
|
+
if (!existsSync(projectDir)) {
|
|
61
|
+
return [];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// 获取 git worktree list 的输出,用于交叉验证
|
|
65
|
+
const worktreeListOutput = gitWorktreeList();
|
|
66
|
+
const registeredPaths = new Set(
|
|
67
|
+
worktreeListOutput.split('\n').map((line) => line.split(/\s+/)[0]),
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
const entries = readdirSync(projectDir, { withFileTypes: true });
|
|
71
|
+
const worktrees: WorktreeInfo[] = [];
|
|
72
|
+
|
|
73
|
+
for (const entry of entries) {
|
|
74
|
+
if (!entry.isDirectory()) {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
const fullPath = join(projectDir, entry.name);
|
|
78
|
+
// 交叉验证:路径必须在 git worktree list 中
|
|
79
|
+
if (registeredPaths.has(fullPath)) {
|
|
80
|
+
worktrees.push({
|
|
81
|
+
path: fullPath,
|
|
82
|
+
branch: entry.name,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return worktrees;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* 批量清理 worktree 及对应分支
|
|
92
|
+
* @param {WorktreeInfo[]} worktrees - 待清理的 worktree 列表
|
|
93
|
+
*/
|
|
94
|
+
export function cleanupWorktrees(worktrees: WorktreeInfo[]): void {
|
|
95
|
+
for (const wt of worktrees) {
|
|
96
|
+
try {
|
|
97
|
+
removeWorktreeByPath(wt.path);
|
|
98
|
+
deleteBranch(wt.branch);
|
|
99
|
+
logger.info(`已清理 worktree 和分支: ${wt.branch}`);
|
|
100
|
+
} catch (error) {
|
|
101
|
+
logger.error(`清理 worktree 失败: ${wt.path} - ${error}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
gitWorktreePrune();
|
|
105
|
+
const projectDir = getProjectWorktreeDir();
|
|
106
|
+
removeEmptyDir(projectDir);
|
|
107
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"esModuleInterop": true,
|
|
7
|
+
"strict": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"outDir": "dist",
|
|
10
|
+
"rootDir": ".",
|
|
11
|
+
"declaration": true,
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"forceConsistentCasingInFileNames": true
|
|
14
|
+
},
|
|
15
|
+
"include": ["src/**/*", "scripts/**/*"],
|
|
16
|
+
"exclude": ["node_modules", "dist"]
|
|
17
|
+
}
|
package/tsup.config.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { defineConfig } from 'tsup';
|
|
2
|
+
|
|
3
|
+
export default defineConfig([
|
|
4
|
+
{
|
|
5
|
+
entry: ['src/index.ts'],
|
|
6
|
+
format: ['esm'],
|
|
7
|
+
target: 'node18',
|
|
8
|
+
outDir: 'dist',
|
|
9
|
+
clean: true,
|
|
10
|
+
banner: {
|
|
11
|
+
js: [
|
|
12
|
+
'#!/usr/bin/env node',
|
|
13
|
+
'import { createRequire as __clawt_createRequire } from "module";',
|
|
14
|
+
'const require = __clawt_createRequire(import.meta.url);',
|
|
15
|
+
].join('\n'),
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
entry: ['scripts/postinstall.ts'],
|
|
20
|
+
format: ['esm'],
|
|
21
|
+
target: 'node18',
|
|
22
|
+
outDir: 'dist',
|
|
23
|
+
clean: false,
|
|
24
|
+
},
|
|
25
|
+
]);
|