cluttry 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/.vwt.json +12 -0
- package/LICENSE +21 -0
- package/README.md +444 -0
- package/dist/commands/doctor.d.ts +7 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +198 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/init.d.ts +11 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +90 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/list.d.ts +11 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +106 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/open.d.ts +11 -0
- package/dist/commands/open.d.ts.map +1 -0
- package/dist/commands/open.js +52 -0
- package/dist/commands/open.js.map +1 -0
- package/dist/commands/prune.d.ts +7 -0
- package/dist/commands/prune.d.ts.map +1 -0
- package/dist/commands/prune.js +33 -0
- package/dist/commands/prune.js.map +1 -0
- package/dist/commands/rm.d.ts +13 -0
- package/dist/commands/rm.d.ts.map +1 -0
- package/dist/commands/rm.js +99 -0
- package/dist/commands/rm.js.map +1 -0
- package/dist/commands/spawn.d.ts +17 -0
- package/dist/commands/spawn.d.ts.map +1 -0
- package/dist/commands/spawn.js +127 -0
- package/dist/commands/spawn.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +101 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/config.d.ts +44 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +109 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/git.d.ts +73 -0
- package/dist/lib/git.d.ts.map +1 -0
- package/dist/lib/git.js +225 -0
- package/dist/lib/git.js.map +1 -0
- package/dist/lib/output.d.ts +33 -0
- package/dist/lib/output.d.ts.map +1 -0
- package/dist/lib/output.js +83 -0
- package/dist/lib/output.js.map +1 -0
- package/dist/lib/paths.d.ts +36 -0
- package/dist/lib/paths.d.ts.map +1 -0
- package/dist/lib/paths.js +84 -0
- package/dist/lib/paths.js.map +1 -0
- package/dist/lib/secrets.d.ts +50 -0
- package/dist/lib/secrets.d.ts.map +1 -0
- package/dist/lib/secrets.js +146 -0
- package/dist/lib/secrets.js.map +1 -0
- package/dist/lib/types.d.ts +63 -0
- package/dist/lib/types.d.ts.map +1 -0
- package/dist/lib/types.js +5 -0
- package/dist/lib/types.js.map +1 -0
- package/package.json +41 -0
- package/src/commands/doctor.ts +222 -0
- package/src/commands/init.ts +120 -0
- package/src/commands/list.ts +133 -0
- package/src/commands/open.ts +70 -0
- package/src/commands/prune.ts +36 -0
- package/src/commands/rm.ts +125 -0
- package/src/commands/spawn.ts +169 -0
- package/src/index.ts +112 -0
- package/src/lib/config.ts +120 -0
- package/src/lib/git.ts +243 -0
- package/src/lib/output.ts +102 -0
- package/src/lib/paths.ts +108 -0
- package/src/lib/secrets.ts +193 -0
- package/src/lib/types.ts +69 -0
- package/tests/config.test.ts +102 -0
- package/tests/paths.test.ts +155 -0
- package/tests/secrets.test.ts +150 -0
- package/tsconfig.json +20 -0
- package/vitest.config.ts +15 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Output utilities for VWT
|
|
3
|
+
*
|
|
4
|
+
* Provides consistent, colorful terminal output without external dependencies.
|
|
5
|
+
*/
|
|
6
|
+
// ANSI color codes
|
|
7
|
+
const colors = {
|
|
8
|
+
reset: '\x1b[0m',
|
|
9
|
+
bold: '\x1b[1m',
|
|
10
|
+
dim: '\x1b[2m',
|
|
11
|
+
red: '\x1b[31m',
|
|
12
|
+
green: '\x1b[32m',
|
|
13
|
+
yellow: '\x1b[33m',
|
|
14
|
+
blue: '\x1b[34m',
|
|
15
|
+
magenta: '\x1b[35m',
|
|
16
|
+
cyan: '\x1b[36m',
|
|
17
|
+
white: '\x1b[37m',
|
|
18
|
+
gray: '\x1b[90m',
|
|
19
|
+
};
|
|
20
|
+
// Check if colors should be used
|
|
21
|
+
const useColors = process.stdout.isTTY && !process.env.NO_COLOR;
|
|
22
|
+
function colorize(text, ...codes) {
|
|
23
|
+
if (!useColors)
|
|
24
|
+
return text;
|
|
25
|
+
return codes.join('') + text + colors.reset;
|
|
26
|
+
}
|
|
27
|
+
export const fmt = {
|
|
28
|
+
bold: (text) => colorize(text, colors.bold),
|
|
29
|
+
dim: (text) => colorize(text, colors.dim),
|
|
30
|
+
red: (text) => colorize(text, colors.red),
|
|
31
|
+
green: (text) => colorize(text, colors.green),
|
|
32
|
+
yellow: (text) => colorize(text, colors.yellow),
|
|
33
|
+
blue: (text) => colorize(text, colors.blue),
|
|
34
|
+
magenta: (text) => colorize(text, colors.magenta),
|
|
35
|
+
cyan: (text) => colorize(text, colors.cyan),
|
|
36
|
+
gray: (text) => colorize(text, colors.gray),
|
|
37
|
+
success: (text) => colorize(text, colors.green),
|
|
38
|
+
error: (text) => colorize(text, colors.red),
|
|
39
|
+
warn: (text) => colorize(text, colors.yellow),
|
|
40
|
+
info: (text) => colorize(text, colors.cyan),
|
|
41
|
+
path: (text) => colorize(text, colors.blue),
|
|
42
|
+
branch: (text) => colorize(text, colors.magenta),
|
|
43
|
+
};
|
|
44
|
+
export function log(message) {
|
|
45
|
+
console.log(message);
|
|
46
|
+
}
|
|
47
|
+
export function success(message) {
|
|
48
|
+
console.log(fmt.green('✓') + ' ' + message);
|
|
49
|
+
}
|
|
50
|
+
export function error(message) {
|
|
51
|
+
console.error(fmt.red('✗') + ' ' + message);
|
|
52
|
+
}
|
|
53
|
+
export function warn(message) {
|
|
54
|
+
console.log(fmt.yellow('⚠') + ' ' + message);
|
|
55
|
+
}
|
|
56
|
+
export function info(message) {
|
|
57
|
+
console.log(fmt.cyan('ℹ') + ' ' + message);
|
|
58
|
+
}
|
|
59
|
+
export function header(message) {
|
|
60
|
+
console.log('\n' + fmt.bold(message));
|
|
61
|
+
}
|
|
62
|
+
export function list(items, prefix = ' ') {
|
|
63
|
+
for (const item of items) {
|
|
64
|
+
console.log(prefix + '• ' + item);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
export function table(rows, columnWidths) {
|
|
68
|
+
if (rows.length === 0)
|
|
69
|
+
return;
|
|
70
|
+
// Calculate column widths if not provided
|
|
71
|
+
const widths = columnWidths ?? rows[0].map((_, i) => Math.max(...rows.map(row => (row[i] ?? '').length)));
|
|
72
|
+
for (const row of rows) {
|
|
73
|
+
const paddedCells = row.map((cell, i) => (cell ?? '').padEnd(widths[i] ?? 0));
|
|
74
|
+
console.log(' ' + paddedCells.join(' '));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
export function json(data) {
|
|
78
|
+
console.log(JSON.stringify(data, null, 2));
|
|
79
|
+
}
|
|
80
|
+
export function newline() {
|
|
81
|
+
console.log();
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=output.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/lib/output.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path utilities for VWT
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Sanitize a branch name for use in filesystem paths
|
|
6
|
+
* - Replace slashes with double dashes
|
|
7
|
+
* - Remove or replace other problematic characters
|
|
8
|
+
*/
|
|
9
|
+
export declare function sanitizeBranchName(branch: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* Calculate the default worktree path
|
|
12
|
+
*/
|
|
13
|
+
export declare function getDefaultWorktreePath(repoRoot: string, branch: string, options?: {
|
|
14
|
+
explicitPath?: string;
|
|
15
|
+
baseDir?: string;
|
|
16
|
+
repoName?: string;
|
|
17
|
+
}): string;
|
|
18
|
+
/**
|
|
19
|
+
* Check if a path is inside the .worktrees directory
|
|
20
|
+
*/
|
|
21
|
+
export declare function isInsideWorktreesDir(targetPath: string, repoRoot: string): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Get relative path from repo root
|
|
24
|
+
*/
|
|
25
|
+
export declare function getRelativePath(absolutePath: string, repoRoot: string): string;
|
|
26
|
+
/**
|
|
27
|
+
* Resolve a branch-or-path argument to a worktree path
|
|
28
|
+
*/
|
|
29
|
+
export declare function resolveBranchOrPath(branchOrPath: string, worktrees: Array<{
|
|
30
|
+
branch: string | null;
|
|
31
|
+
path: string;
|
|
32
|
+
}>, repoRoot: string): {
|
|
33
|
+
path: string;
|
|
34
|
+
branch: string | null;
|
|
35
|
+
} | null;
|
|
36
|
+
//# sourceMappingURL=paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/lib/paths.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAUzD;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE;IACR,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GACA,MAAM,CAuBR;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAKlF;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE9E;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,KAAK,CAAC;IAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,EACzD,QAAQ,EAAE,MAAM,GACf;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAAG,IAAI,CAwBhD"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path utilities for VWT
|
|
3
|
+
*/
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
/**
|
|
6
|
+
* Sanitize a branch name for use in filesystem paths
|
|
7
|
+
* - Replace slashes with double dashes
|
|
8
|
+
* - Remove or replace other problematic characters
|
|
9
|
+
*/
|
|
10
|
+
export function sanitizeBranchName(branch) {
|
|
11
|
+
return branch
|
|
12
|
+
.replace(/\//g, '--') // Replace slashes with double dashes
|
|
13
|
+
.replace(/[<>:"|?*\\]/g, '-') // Replace Windows-forbidden chars
|
|
14
|
+
.replace(/\s+/g, '-') // Replace whitespace
|
|
15
|
+
.replace(/^\.+/, '') // Remove leading dots
|
|
16
|
+
.replace(/\.+$/, '') // Remove trailing dots
|
|
17
|
+
.replace(/-+/g, '-') // Collapse multiple dashes
|
|
18
|
+
.replace(/^-+/, '') // Remove leading dashes
|
|
19
|
+
.replace(/-+$/, ''); // Remove trailing dashes
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Calculate the default worktree path
|
|
23
|
+
*/
|
|
24
|
+
export function getDefaultWorktreePath(repoRoot, branch, options) {
|
|
25
|
+
// Explicit path wins
|
|
26
|
+
if (options?.explicitPath) {
|
|
27
|
+
// If it's relative, resolve against CWD
|
|
28
|
+
if (!path.isAbsolute(options.explicitPath)) {
|
|
29
|
+
return path.resolve(options.explicitPath);
|
|
30
|
+
}
|
|
31
|
+
return options.explicitPath;
|
|
32
|
+
}
|
|
33
|
+
const sanitizedBranch = sanitizeBranchName(branch);
|
|
34
|
+
// Base directory specified
|
|
35
|
+
if (options?.baseDir) {
|
|
36
|
+
const repoName = options.repoName ?? path.basename(repoRoot);
|
|
37
|
+
const baseDir = path.isAbsolute(options.baseDir)
|
|
38
|
+
? options.baseDir
|
|
39
|
+
: path.resolve(repoRoot, options.baseDir);
|
|
40
|
+
return path.join(baseDir, repoName, sanitizedBranch);
|
|
41
|
+
}
|
|
42
|
+
// Default: .worktrees/<branch> inside repo
|
|
43
|
+
return path.join(repoRoot, '.worktrees', sanitizedBranch);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Check if a path is inside the .worktrees directory
|
|
47
|
+
*/
|
|
48
|
+
export function isInsideWorktreesDir(targetPath, repoRoot) {
|
|
49
|
+
const worktreesDir = path.join(repoRoot, '.worktrees');
|
|
50
|
+
const normalizedTarget = path.normalize(targetPath);
|
|
51
|
+
const normalizedWorktrees = path.normalize(worktreesDir);
|
|
52
|
+
return normalizedTarget.startsWith(normalizedWorktrees);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Get relative path from repo root
|
|
56
|
+
*/
|
|
57
|
+
export function getRelativePath(absolutePath, repoRoot) {
|
|
58
|
+
return path.relative(repoRoot, absolutePath);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Resolve a branch-or-path argument to a worktree path
|
|
62
|
+
*/
|
|
63
|
+
export function resolveBranchOrPath(branchOrPath, worktrees, repoRoot) {
|
|
64
|
+
// First, try to match by branch name
|
|
65
|
+
const byBranch = worktrees.find((w) => w.branch === branchOrPath);
|
|
66
|
+
if (byBranch) {
|
|
67
|
+
return { path: byBranch.path, branch: byBranch.branch };
|
|
68
|
+
}
|
|
69
|
+
// Try to match by path (absolute or relative)
|
|
70
|
+
const absolutePath = path.isAbsolute(branchOrPath)
|
|
71
|
+
? branchOrPath
|
|
72
|
+
: path.resolve(repoRoot, branchOrPath);
|
|
73
|
+
const byPath = worktrees.find((w) => path.normalize(w.path) === path.normalize(absolutePath));
|
|
74
|
+
if (byPath) {
|
|
75
|
+
return { path: byPath.path, branch: byPath.branch };
|
|
76
|
+
}
|
|
77
|
+
// Try partial path match (end of path)
|
|
78
|
+
const byPartialPath = worktrees.find((w) => w.path.endsWith(branchOrPath));
|
|
79
|
+
if (byPartialPath) {
|
|
80
|
+
return { path: byPartialPath.path, branch: byPartialPath.branch };
|
|
81
|
+
}
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/lib/paths.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secret file handling for VWT
|
|
3
|
+
*
|
|
4
|
+
* This module ensures that only git-ignored files are ever copied or symlinked.
|
|
5
|
+
* It provides a safety layer to prevent accidentally exposing tracked files.
|
|
6
|
+
*/
|
|
7
|
+
import type { SecretMode } from './types.js';
|
|
8
|
+
export interface FileCheckResult {
|
|
9
|
+
path: string;
|
|
10
|
+
exists: boolean;
|
|
11
|
+
isTracked: boolean;
|
|
12
|
+
isIgnored: boolean;
|
|
13
|
+
safe: boolean;
|
|
14
|
+
reason?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Check if a file is safe to copy/symlink
|
|
18
|
+
* A file is safe if:
|
|
19
|
+
* 1. It exists
|
|
20
|
+
* 2. It is NOT tracked by git
|
|
21
|
+
* 3. It IS ignored by git
|
|
22
|
+
*/
|
|
23
|
+
export declare function checkFileSafety(filePath: string, repoRoot: string): FileCheckResult;
|
|
24
|
+
/**
|
|
25
|
+
* Expand glob patterns to actual file paths
|
|
26
|
+
*/
|
|
27
|
+
export declare function expandIncludePatterns(patterns: string[], repoRoot: string): Promise<string[]>;
|
|
28
|
+
/**
|
|
29
|
+
* Get all safe files from include patterns
|
|
30
|
+
*/
|
|
31
|
+
export declare function getSafeFiles(patterns: string[], repoRoot: string): Promise<{
|
|
32
|
+
safe: FileCheckResult[];
|
|
33
|
+
unsafe: FileCheckResult[];
|
|
34
|
+
}>;
|
|
35
|
+
/**
|
|
36
|
+
* Copy a file to the target directory, preserving relative path
|
|
37
|
+
*/
|
|
38
|
+
export declare function copyFile(relativePath: string, sourceRoot: string, targetRoot: string): void;
|
|
39
|
+
/**
|
|
40
|
+
* Create a symlink in the target directory pointing to source
|
|
41
|
+
*/
|
|
42
|
+
export declare function createSymlink(relativePath: string, sourceRoot: string, targetRoot: string): void;
|
|
43
|
+
/**
|
|
44
|
+
* Process files according to mode (copy or symlink)
|
|
45
|
+
*/
|
|
46
|
+
export declare function processSecrets(mode: SecretMode, patterns: string[], sourceRoot: string, targetRoot: string): Promise<{
|
|
47
|
+
processed: string[];
|
|
48
|
+
skipped: FileCheckResult[];
|
|
49
|
+
}>;
|
|
50
|
+
//# sourceMappingURL=secrets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secrets.d.ts","sourceRoot":"","sources":["../../src/lib/secrets.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,eAAe,CA+BnF;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,MAAM,EAAE,EAClB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,EAAE,CAAC,CAsBnB;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,QAAQ,EAAE,MAAM,EAAE,EAClB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;IAAE,IAAI,EAAE,eAAe,EAAE,CAAC;IAAC,MAAM,EAAE,eAAe,EAAE,CAAA;CAAE,CAAC,CAgBjE;AAED;;GAEG;AACH,wBAAgB,QAAQ,CACtB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB,IAAI,CAWN;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB,IAAI,CAYN;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,MAAM,EAAE,EAClB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,eAAe,EAAE,CAAA;CAAE,CAAC,CA2B9D"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secret file handling for VWT
|
|
3
|
+
*
|
|
4
|
+
* This module ensures that only git-ignored files are ever copied or symlinked.
|
|
5
|
+
* It provides a safety layer to prevent accidentally exposing tracked files.
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync, copyFileSync, symlinkSync, mkdirSync } from 'node:fs';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
import { glob } from 'glob';
|
|
10
|
+
import { isTracked, isIgnored } from './git.js';
|
|
11
|
+
/**
|
|
12
|
+
* Check if a file is safe to copy/symlink
|
|
13
|
+
* A file is safe if:
|
|
14
|
+
* 1. It exists
|
|
15
|
+
* 2. It is NOT tracked by git
|
|
16
|
+
* 3. It IS ignored by git
|
|
17
|
+
*/
|
|
18
|
+
export function checkFileSafety(filePath, repoRoot) {
|
|
19
|
+
const absolutePath = path.isAbsolute(filePath) ? filePath : path.join(repoRoot, filePath);
|
|
20
|
+
const relativePath = path.relative(repoRoot, absolutePath);
|
|
21
|
+
const result = {
|
|
22
|
+
path: relativePath,
|
|
23
|
+
exists: existsSync(absolutePath),
|
|
24
|
+
isTracked: false,
|
|
25
|
+
isIgnored: false,
|
|
26
|
+
safe: false,
|
|
27
|
+
};
|
|
28
|
+
if (!result.exists) {
|
|
29
|
+
result.reason = 'File does not exist';
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
32
|
+
result.isTracked = isTracked(relativePath, repoRoot);
|
|
33
|
+
if (result.isTracked) {
|
|
34
|
+
result.reason = 'File is tracked by git (would be committed)';
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
37
|
+
result.isIgnored = isIgnored(relativePath, repoRoot);
|
|
38
|
+
if (!result.isIgnored) {
|
|
39
|
+
result.reason = 'File is not ignored by git (could be accidentally committed)';
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
42
|
+
result.safe = true;
|
|
43
|
+
return result;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Expand glob patterns to actual file paths
|
|
47
|
+
*/
|
|
48
|
+
export async function expandIncludePatterns(patterns, repoRoot) {
|
|
49
|
+
const allFiles = new Set();
|
|
50
|
+
for (const pattern of patterns) {
|
|
51
|
+
try {
|
|
52
|
+
const matches = await glob(pattern, {
|
|
53
|
+
cwd: repoRoot,
|
|
54
|
+
dot: true,
|
|
55
|
+
nodir: true,
|
|
56
|
+
});
|
|
57
|
+
for (const match of matches) {
|
|
58
|
+
allFiles.add(match);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
// If glob fails, treat as literal path
|
|
63
|
+
if (existsSync(path.join(repoRoot, pattern))) {
|
|
64
|
+
allFiles.add(pattern);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return Array.from(allFiles).sort();
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Get all safe files from include patterns
|
|
72
|
+
*/
|
|
73
|
+
export async function getSafeFiles(patterns, repoRoot) {
|
|
74
|
+
const files = await expandIncludePatterns(patterns, repoRoot);
|
|
75
|
+
const safe = [];
|
|
76
|
+
const unsafe = [];
|
|
77
|
+
for (const file of files) {
|
|
78
|
+
const result = checkFileSafety(file, repoRoot);
|
|
79
|
+
if (result.safe) {
|
|
80
|
+
safe.push(result);
|
|
81
|
+
}
|
|
82
|
+
else if (result.exists) {
|
|
83
|
+
// Only report unsafe if file actually exists
|
|
84
|
+
unsafe.push(result);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return { safe, unsafe };
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Copy a file to the target directory, preserving relative path
|
|
91
|
+
*/
|
|
92
|
+
export function copyFile(relativePath, sourceRoot, targetRoot) {
|
|
93
|
+
const sourcePath = path.join(sourceRoot, relativePath);
|
|
94
|
+
const targetPath = path.join(targetRoot, relativePath);
|
|
95
|
+
// Create parent directories if needed
|
|
96
|
+
const targetDir = path.dirname(targetPath);
|
|
97
|
+
if (!existsSync(targetDir)) {
|
|
98
|
+
mkdirSync(targetDir, { recursive: true });
|
|
99
|
+
}
|
|
100
|
+
copyFileSync(sourcePath, targetPath);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Create a symlink in the target directory pointing to source
|
|
104
|
+
*/
|
|
105
|
+
export function createSymlink(relativePath, sourceRoot, targetRoot) {
|
|
106
|
+
const sourcePath = path.join(sourceRoot, relativePath);
|
|
107
|
+
const targetPath = path.join(targetRoot, relativePath);
|
|
108
|
+
// Create parent directories if needed
|
|
109
|
+
const targetDir = path.dirname(targetPath);
|
|
110
|
+
if (!existsSync(targetDir)) {
|
|
111
|
+
mkdirSync(targetDir, { recursive: true });
|
|
112
|
+
}
|
|
113
|
+
// Use absolute path for symlink target for reliability
|
|
114
|
+
symlinkSync(sourcePath, targetPath);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Process files according to mode (copy or symlink)
|
|
118
|
+
*/
|
|
119
|
+
export async function processSecrets(mode, patterns, sourceRoot, targetRoot) {
|
|
120
|
+
if (mode === 'none') {
|
|
121
|
+
return { processed: [], skipped: [] };
|
|
122
|
+
}
|
|
123
|
+
const { safe, unsafe } = await getSafeFiles(patterns, sourceRoot);
|
|
124
|
+
const processed = [];
|
|
125
|
+
for (const file of safe) {
|
|
126
|
+
try {
|
|
127
|
+
if (mode === 'copy') {
|
|
128
|
+
copyFile(file.path, sourceRoot, targetRoot);
|
|
129
|
+
}
|
|
130
|
+
else if (mode === 'symlink') {
|
|
131
|
+
createSymlink(file.path, sourceRoot, targetRoot);
|
|
132
|
+
}
|
|
133
|
+
processed.push(file.path);
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
// Add to skipped with error reason
|
|
137
|
+
unsafe.push({
|
|
138
|
+
...file,
|
|
139
|
+
safe: false,
|
|
140
|
+
reason: `Failed to ${mode}: ${error.message}`,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return { processed, skipped: unsafe };
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=secrets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secrets.js","sourceRoot":"","sources":["../../src/lib/secrets.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VWT Configuration Types
|
|
3
|
+
*/
|
|
4
|
+
export interface VwtConfig {
|
|
5
|
+
/** Base directory for worktrees (optional, defaults to .worktrees/) */
|
|
6
|
+
worktreeBaseDir?: string;
|
|
7
|
+
/** Default mode for secrets handling */
|
|
8
|
+
defaultMode: 'copy' | 'symlink' | 'none';
|
|
9
|
+
/** List of globs/paths to manage (e.g. [".env", ".env.*", "config/oauth*.json"]) */
|
|
10
|
+
include: string[];
|
|
11
|
+
/** Hook commands */
|
|
12
|
+
hooks?: {
|
|
13
|
+
postCreate?: string[];
|
|
14
|
+
};
|
|
15
|
+
/** Default agent command */
|
|
16
|
+
agentCommand?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface VwtLocalConfig {
|
|
19
|
+
/** Machine-specific base directory override */
|
|
20
|
+
worktreeBaseDir?: string;
|
|
21
|
+
/** Additional include paths for this machine */
|
|
22
|
+
include?: string[];
|
|
23
|
+
/** Additional hooks for this machine */
|
|
24
|
+
hooks?: {
|
|
25
|
+
postCreate?: string[];
|
|
26
|
+
};
|
|
27
|
+
/** Override agent command */
|
|
28
|
+
agentCommand?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface MergedConfig {
|
|
31
|
+
worktreeBaseDir?: string;
|
|
32
|
+
defaultMode: 'copy' | 'symlink' | 'none';
|
|
33
|
+
include: string[];
|
|
34
|
+
hooks: {
|
|
35
|
+
postCreate: string[];
|
|
36
|
+
};
|
|
37
|
+
agentCommand: string;
|
|
38
|
+
}
|
|
39
|
+
export interface WorktreeInfo {
|
|
40
|
+
worktree: string;
|
|
41
|
+
head: string;
|
|
42
|
+
branch?: string;
|
|
43
|
+
bare?: boolean;
|
|
44
|
+
detached?: boolean;
|
|
45
|
+
}
|
|
46
|
+
export interface WorktreeListItem {
|
|
47
|
+
branch: string | null;
|
|
48
|
+
path: string;
|
|
49
|
+
headShort: string;
|
|
50
|
+
dirty: boolean;
|
|
51
|
+
lastModified: Date | null;
|
|
52
|
+
}
|
|
53
|
+
export type SecretMode = 'copy' | 'symlink' | 'none';
|
|
54
|
+
export interface SpawnOptions {
|
|
55
|
+
branch: string;
|
|
56
|
+
isNew: boolean;
|
|
57
|
+
path?: string;
|
|
58
|
+
base?: string;
|
|
59
|
+
mode: SecretMode;
|
|
60
|
+
run?: string;
|
|
61
|
+
agent?: 'claude' | 'none';
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lib/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,SAAS;IACxB,uEAAuE;IACvE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,wCAAwC;IACxC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC;IACzC,oFAAoF;IACpF,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,oBAAoB;IACpB,KAAK,CAAC,EAAE;QACN,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;KACvB,CAAC;IACF,4BAA4B;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,+CAA+C;IAC/C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,wCAAwC;IACxC,KAAK,CAAC,EAAE;QACN,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;KACvB,CAAC;IACF,6BAA6B;IAC7B,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC;IACzC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,EAAE;QACL,UAAU,EAAE,MAAM,EAAE,CAAC;KACtB,CAAC;IACF,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,OAAO,CAAC;IACf,YAAY,EAAE,IAAI,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC;AAErD,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,UAAU,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;CAC3B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/lib/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "cluttry",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Cluttry - Git worktree management for parallel AI-agent sessions",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"cry": "./dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"build:bun": "bun build src/index.ts --outdir dist --target node",
|
|
13
|
+
"dev": "tsc --watch",
|
|
14
|
+
"start": "node dist/index.js",
|
|
15
|
+
"start:bun": "bun run src/index.ts",
|
|
16
|
+
"test": "vitest run",
|
|
17
|
+
"test:bun": "bun test",
|
|
18
|
+
"test:watch": "vitest",
|
|
19
|
+
"test:coverage": "vitest run --coverage",
|
|
20
|
+
"lint": "eslint src --ext .ts",
|
|
21
|
+
"format": "prettier --write 'src/**/*.ts'",
|
|
22
|
+
"prepare": "npm run build"
|
|
23
|
+
},
|
|
24
|
+
"keywords": ["git", "worktree", "cli", "ai", "agent", "claude", "vibe", "bun"],
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=18.0.0",
|
|
28
|
+
"bun": ">=1.0.0"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"commander": "^12.1.0",
|
|
32
|
+
"glob": "^10.3.0"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@types/node": "^20.10.0",
|
|
36
|
+
"@types/bun": "^1.1.0",
|
|
37
|
+
"typescript": "^5.3.0",
|
|
38
|
+
"vitest": "^1.0.0",
|
|
39
|
+
"prettier": "^3.1.0"
|
|
40
|
+
}
|
|
41
|
+
}
|