cluttry 1.0.0 → 1.0.3
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/settings.local.json +7 -0
- package/README.md +8 -8
- package/dist/commands/open.d.ts +1 -0
- package/dist/commands/open.d.ts.map +1 -1
- package/dist/commands/open.js +8 -2
- package/dist/commands/open.js.map +1 -1
- package/dist/commands/shell.d.ts +11 -0
- package/dist/commands/shell.d.ts.map +1 -0
- package/dist/commands/shell.js +89 -0
- package/dist/commands/shell.js.map +1 -0
- package/dist/index.js +11 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/config.d.ts +11 -11
- package/dist/lib/config.js +3 -3
- package/dist/lib/git.d.ts +1 -1
- package/dist/lib/git.js +1 -1
- package/dist/lib/output.d.ts +1 -1
- package/dist/lib/output.js +1 -1
- package/dist/lib/paths.d.ts +1 -1
- package/dist/lib/paths.js +1 -1
- package/dist/lib/secrets.d.ts +1 -1
- package/dist/lib/secrets.js +1 -1
- package/dist/lib/types.d.ts +3 -3
- package/dist/lib/types.js +1 -1
- package/package.json +11 -2
- package/src/commands/open.ts +10 -2
- package/src/commands/shell.ts +99 -0
- package/src/index.ts +12 -1
- package/src/lib/config.ts +14 -14
- package/src/lib/git.ts +1 -1
- package/src/lib/output.ts +1 -1
- package/src/lib/paths.ts +1 -1
- package/src/lib/secrets.ts +1 -1
- package/src/lib/types.ts +3 -3
- package/tests/config.test.ts +11 -11
- package/.vwt.json +0 -12
package/README.md
CHANGED
|
@@ -74,8 +74,8 @@ cry init [--force]
|
|
|
74
74
|
```
|
|
75
75
|
|
|
76
76
|
Creates:
|
|
77
|
-
- `.
|
|
78
|
-
- `.
|
|
77
|
+
- `.cry.json` — tracked config with defaults
|
|
78
|
+
- `.cry.local.json` — gitignored local overrides
|
|
79
79
|
- Updates `.gitignore` to ignore local config and `.worktrees/`
|
|
80
80
|
|
|
81
81
|
### `cry spawn <branch>`
|
|
@@ -197,7 +197,7 @@ Checks:
|
|
|
197
197
|
|
|
198
198
|
## Configuration
|
|
199
199
|
|
|
200
|
-
### `.
|
|
200
|
+
### `.cry.json` (tracked)
|
|
201
201
|
|
|
202
202
|
```json
|
|
203
203
|
{
|
|
@@ -219,7 +219,7 @@ Checks:
|
|
|
219
219
|
| `hooks.postCreate` | Commands to run after spawning |
|
|
220
220
|
| `agentCommand` | Command to launch AI agent |
|
|
221
221
|
|
|
222
|
-
### `.
|
|
222
|
+
### `.cry.local.json` (gitignored)
|
|
223
223
|
|
|
224
224
|
Machine-specific overrides:
|
|
225
225
|
|
|
@@ -287,7 +287,7 @@ Files must be explicitly ignored by git (in `.gitignore`) to be eligible for cop
|
|
|
287
287
|
```
|
|
288
288
|
|
|
289
289
|
2. **Configure your secrets:**
|
|
290
|
-
Edit `.
|
|
290
|
+
Edit `.cry.json` to include your secret files:
|
|
291
291
|
```json
|
|
292
292
|
{
|
|
293
293
|
"include": [".env", ".env.local", "config/oauth*.json"]
|
|
@@ -344,8 +344,8 @@ Each agent works in an isolated worktree with its own copy of secrets.
|
|
|
344
344
|
├── feature-payments/ # Worktree for feature-payments branch
|
|
345
345
|
└── bugfix-123/ # Worktree for bugfix-123 branch
|
|
346
346
|
|
|
347
|
-
.
|
|
348
|
-
.
|
|
347
|
+
.cry.json # Tracked config
|
|
348
|
+
.cry.local.json # Local overrides (gitignored)
|
|
349
349
|
```
|
|
350
350
|
|
|
351
351
|
## Troubleshooting
|
|
@@ -390,7 +390,7 @@ Install the AI agent CLI or update `agentCommand` in your config:
|
|
|
390
390
|
# For Claude
|
|
391
391
|
npm install -g @anthropic-ai/claude-code
|
|
392
392
|
|
|
393
|
-
# Or override in .
|
|
393
|
+
# Or override in .cry.local.json
|
|
394
394
|
{
|
|
395
395
|
"agentCommand": "your-agent-command"
|
|
396
396
|
}
|
package/dist/commands/open.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"open.d.ts","sourceRoot":"","sources":["../../src/commands/open.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAWH,UAAU,WAAW;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"open.d.ts","sourceRoot":"","sources":["../../src/commands/open.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAWH,UAAU,WAAW;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,wBAAsB,IAAI,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAyDpF"}
|
package/dist/commands/open.js
CHANGED
|
@@ -30,6 +30,11 @@ export async function open(branchOrPath, options) {
|
|
|
30
30
|
process.exit(1);
|
|
31
31
|
}
|
|
32
32
|
const { path: wtPath, branch } = resolved;
|
|
33
|
+
// If --path-only, just print the path (for scripting)
|
|
34
|
+
if (options.pathOnly) {
|
|
35
|
+
console.log(wtPath);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
33
38
|
// If --cmd is provided, run it
|
|
34
39
|
if (options.cmd) {
|
|
35
40
|
out.log(`Running in ${out.fmt.path(wtPath)}:`);
|
|
@@ -46,7 +51,8 @@ export async function open(branchOrPath, options) {
|
|
|
46
51
|
out.log(` ${out.fmt.cyan(`cd "${wtPath}"`)}`);
|
|
47
52
|
// For shell integration hint
|
|
48
53
|
out.newline();
|
|
49
|
-
out.log(out.fmt.dim('Tip:
|
|
50
|
-
out.log(out.fmt.dim(
|
|
54
|
+
out.log(out.fmt.dim('Tip: Add this to your shell profile for easy navigation:'));
|
|
55
|
+
out.log(out.fmt.dim(' crycd() { cd "$(cry open "$1" --path-only)"; }'));
|
|
56
|
+
out.log(out.fmt.dim(' # Then use: crycd feature/my-branch'));
|
|
51
57
|
}
|
|
52
58
|
//# sourceMappingURL=open.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"open.js","sourceRoot":"","sources":["../../src/commands/open.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,SAAS,EACT,WAAW,EACX,aAAa,EACb,UAAU,GACX,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,KAAK,GAAG,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"open.js","sourceRoot":"","sources":["../../src/commands/open.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cry shell command
|
|
3
|
+
*
|
|
4
|
+
* Output shell integration code for easy directory navigation.
|
|
5
|
+
*/
|
|
6
|
+
interface ShellOptions {
|
|
7
|
+
shell?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function shell(options: ShellOptions): Promise<void>;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=shell.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell.d.ts","sourceRoot":"","sources":["../../src/commands/shell.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAiEH,UAAU,YAAY;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAyBhE"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cry shell command
|
|
3
|
+
*
|
|
4
|
+
* Output shell integration code for easy directory navigation.
|
|
5
|
+
*/
|
|
6
|
+
import * as out from '../lib/output.js';
|
|
7
|
+
const SHELL_FUNCTIONS = {
|
|
8
|
+
bash: `# cry shell integration (add to ~/.bashrc)
|
|
9
|
+
crycd() {
|
|
10
|
+
local target
|
|
11
|
+
target="$(cry open "$1" --path-only 2>/dev/null)"
|
|
12
|
+
if [ -n "$target" ]; then
|
|
13
|
+
cd "$target"
|
|
14
|
+
else
|
|
15
|
+
echo "Worktree not found: $1" >&2
|
|
16
|
+
return 1
|
|
17
|
+
fi
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
# Auto-completion for crycd
|
|
21
|
+
_crycd_completions() {
|
|
22
|
+
local branches
|
|
23
|
+
branches=$(cry list --json 2>/dev/null | grep -o '"branch":"[^"]*"' | cut -d'"' -f4)
|
|
24
|
+
COMPREPLY=($(compgen -W "$branches" -- "\${COMP_WORDS[COMP_CWORD]}"))
|
|
25
|
+
}
|
|
26
|
+
complete -F _crycd_completions crycd
|
|
27
|
+
`,
|
|
28
|
+
zsh: `# cry shell integration (add to ~/.zshrc)
|
|
29
|
+
crycd() {
|
|
30
|
+
local target
|
|
31
|
+
target="$(cry open "$1" --path-only 2>/dev/null)"
|
|
32
|
+
if [[ -n "$target" ]]; then
|
|
33
|
+
cd "$target"
|
|
34
|
+
else
|
|
35
|
+
echo "Worktree not found: $1" >&2
|
|
36
|
+
return 1
|
|
37
|
+
fi
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
# Auto-completion for crycd
|
|
41
|
+
_crycd() {
|
|
42
|
+
local branches
|
|
43
|
+
branches=(\${(f)"$(cry list --json 2>/dev/null | grep -o '"branch":"[^"]*"' | cut -d'"' -f4)"})
|
|
44
|
+
_describe 'branch' branches
|
|
45
|
+
}
|
|
46
|
+
compdef _crycd crycd
|
|
47
|
+
`,
|
|
48
|
+
fish: `# cry shell integration (add to ~/.config/fish/config.fish)
|
|
49
|
+
function crycd
|
|
50
|
+
set -l target (cry open $argv[1] --path-only 2>/dev/null)
|
|
51
|
+
if test -n "$target"
|
|
52
|
+
cd $target
|
|
53
|
+
else
|
|
54
|
+
echo "Worktree not found: $argv[1]" >&2
|
|
55
|
+
return 1
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Auto-completion for crycd
|
|
60
|
+
complete -c crycd -f -a "(cry list --json 2>/dev/null | grep -o '\"branch\":\"[^\"]*\"' | cut -d'\"' -f4)"
|
|
61
|
+
`,
|
|
62
|
+
};
|
|
63
|
+
export async function shell(options) {
|
|
64
|
+
const shellEnv = process.env.SHELL ?? '';
|
|
65
|
+
let detectedShell = 'bash';
|
|
66
|
+
if (options.shell) {
|
|
67
|
+
if (options.shell === 'fish' || options.shell === 'zsh' || options.shell === 'bash') {
|
|
68
|
+
detectedShell = options.shell;
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
out.error(`Unsupported shell: ${options.shell}`);
|
|
72
|
+
out.info('Supported shells: bash, zsh, fish');
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
else if (shellEnv.includes('zsh')) {
|
|
77
|
+
detectedShell = 'zsh';
|
|
78
|
+
}
|
|
79
|
+
else if (shellEnv.includes('fish')) {
|
|
80
|
+
detectedShell = 'fish';
|
|
81
|
+
}
|
|
82
|
+
const script = SHELL_FUNCTIONS[detectedShell];
|
|
83
|
+
out.log(out.fmt.dim(`# Shell integration for ${detectedShell}`));
|
|
84
|
+
out.log(out.fmt.dim('# Copy and paste into your shell config, or run:'));
|
|
85
|
+
out.log(out.fmt.dim(`# cry shell >> ~/.${detectedShell === 'fish' ? 'config/fish/config.fish' : detectedShell + 'rc'}`));
|
|
86
|
+
out.newline();
|
|
87
|
+
console.log(script);
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=shell.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell.js","sourceRoot":"","sources":["../../src/commands/shell.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,GAAG,MAAM,kBAAkB,CAAC;AAIxC,MAAM,eAAe,GAA8B;IACjD,IAAI,EAAE;;;;;;;;;;;;;;;;;;;CAmBP;IAEC,GAAG,EAAE;;;;;;;;;;;;;;;;;;;CAmBN;IAEC,IAAI,EAAE;;;;;;;;;;;;;CAaP;CACA,CAAC;AAMF,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,OAAqB;IAC/C,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC;IACzC,IAAI,aAAa,GAAc,MAAM,CAAC;IAEtC,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,IAAI,OAAO,CAAC,KAAK,KAAK,MAAM,IAAI,OAAO,CAAC,KAAK,KAAK,KAAK,IAAI,OAAO,CAAC,KAAK,KAAK,MAAM,EAAE,CAAC;YACpF,aAAa,GAAG,OAAO,CAAC,KAAK,CAAC;QAChC,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,KAAK,CAAC,sBAAsB,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;YACjD,GAAG,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAAC;YAC9C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;SAAM,IAAI,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACpC,aAAa,GAAG,KAAK,CAAC;IACxB,CAAC;SAAM,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QACrC,aAAa,GAAG,MAAM,CAAC;IACzB,CAAC;IAED,MAAM,MAAM,GAAG,eAAe,CAAC,aAAa,CAAC,CAAC;IAE9C,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,2BAA2B,aAAa,EAAE,CAAC,CAAC,CAAC;IACjE,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,kDAAkD,CAAC,CAAC,CAAC;IACzE,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,uBAAuB,aAAa,KAAK,MAAM,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,aAAa,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC;IAC3H,GAAG,CAAC,OAAO,EAAE,CAAC;IACd,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AACtB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -12,6 +12,7 @@ import { open } from './commands/open.js';
|
|
|
12
12
|
import { rm } from './commands/rm.js';
|
|
13
13
|
import { prune } from './commands/prune.js';
|
|
14
14
|
import { doctor } from './commands/doctor.js';
|
|
15
|
+
import { shell } from './commands/shell.js';
|
|
15
16
|
const program = new Command();
|
|
16
17
|
program
|
|
17
18
|
.name('cry')
|
|
@@ -64,8 +65,9 @@ program
|
|
|
64
65
|
.command('open <branch-or-path>')
|
|
65
66
|
.description('Open or navigate to a worktree by branch name or path')
|
|
66
67
|
.option('-c, --cmd <cmd>', 'Command to execute in the worktree directory')
|
|
68
|
+
.option('-p, --path-only', 'Only print the path (for scripting)')
|
|
67
69
|
.action(async (branchOrPath, options) => {
|
|
68
|
-
await open(branchOrPath, { cmd: options.cmd });
|
|
70
|
+
await open(branchOrPath, { cmd: options.cmd, pathOnly: options.pathOnly });
|
|
69
71
|
});
|
|
70
72
|
// cry rm <branch-or-path>
|
|
71
73
|
program
|
|
@@ -96,6 +98,14 @@ program
|
|
|
96
98
|
.action(async () => {
|
|
97
99
|
await doctor();
|
|
98
100
|
});
|
|
101
|
+
// cry shell
|
|
102
|
+
program
|
|
103
|
+
.command('shell')
|
|
104
|
+
.description('Output shell integration code for crycd navigation function')
|
|
105
|
+
.option('-s, --shell <shell>', 'Shell type: bash, zsh, or fish (auto-detected)')
|
|
106
|
+
.action(async (options) => {
|
|
107
|
+
await shell({ shell: options.shell });
|
|
108
|
+
});
|
|
99
109
|
// Parse and execute
|
|
100
110
|
program.parse();
|
|
101
111
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;GAIG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAC1C,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAC1C,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAC1C,OAAO,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AACtC,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/config.d.ts
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Configuration management for
|
|
2
|
+
* Configuration management for cry
|
|
3
3
|
*/
|
|
4
|
-
import type { MergedConfig,
|
|
5
|
-
export declare const CONFIG_FILE = ".
|
|
6
|
-
export declare const LOCAL_CONFIG_FILE = ".
|
|
4
|
+
import type { MergedConfig, CryConfig, CryLocalConfig } from './types.js';
|
|
5
|
+
export declare const CONFIG_FILE = ".cry.json";
|
|
6
|
+
export declare const LOCAL_CONFIG_FILE = ".cry.local.json";
|
|
7
7
|
export declare const WORKTREE_INCLUDE_FILE = ".worktreeinclude";
|
|
8
8
|
/**
|
|
9
9
|
* Load the main config file
|
|
10
10
|
*/
|
|
11
|
-
export declare function loadConfig(repoRoot: string):
|
|
11
|
+
export declare function loadConfig(repoRoot: string): CryConfig | null;
|
|
12
12
|
/**
|
|
13
13
|
* Load the local config file
|
|
14
14
|
*/
|
|
15
|
-
export declare function loadLocalConfig(repoRoot: string):
|
|
15
|
+
export declare function loadLocalConfig(repoRoot: string): CryLocalConfig | null;
|
|
16
16
|
/**
|
|
17
17
|
* Merge main config with local overrides
|
|
18
18
|
*/
|
|
19
|
-
export declare function mergeConfig(config:
|
|
19
|
+
export declare function mergeConfig(config: CryConfig | null, localConfig: CryLocalConfig | null): MergedConfig;
|
|
20
20
|
/**
|
|
21
21
|
* Get merged configuration
|
|
22
22
|
*/
|
|
@@ -24,11 +24,11 @@ export declare function getMergedConfig(repoRoot: string): MergedConfig;
|
|
|
24
24
|
/**
|
|
25
25
|
* Save the main config file
|
|
26
26
|
*/
|
|
27
|
-
export declare function saveConfig(repoRoot: string, config:
|
|
27
|
+
export declare function saveConfig(repoRoot: string, config: CryConfig): void;
|
|
28
28
|
/**
|
|
29
29
|
* Save the local config file
|
|
30
30
|
*/
|
|
31
|
-
export declare function saveLocalConfig(repoRoot: string, config:
|
|
31
|
+
export declare function saveLocalConfig(repoRoot: string, config: CryLocalConfig): void;
|
|
32
32
|
/**
|
|
33
33
|
* Check if config exists
|
|
34
34
|
*/
|
|
@@ -36,9 +36,9 @@ export declare function configExists(repoRoot: string): boolean;
|
|
|
36
36
|
/**
|
|
37
37
|
* Get default config
|
|
38
38
|
*/
|
|
39
|
-
export declare function getDefaultConfig():
|
|
39
|
+
export declare function getDefaultConfig(): CryConfig;
|
|
40
40
|
/**
|
|
41
41
|
* Create default local config
|
|
42
42
|
*/
|
|
43
|
-
export declare function getDefaultLocalConfig():
|
|
43
|
+
export declare function getDefaultLocalConfig(): CryLocalConfig;
|
|
44
44
|
//# sourceMappingURL=config.d.ts.map
|
package/dist/lib/config.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Configuration management for
|
|
2
|
+
* Configuration management for cry
|
|
3
3
|
*/
|
|
4
4
|
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
5
5
|
import path from 'node:path';
|
|
6
|
-
export const CONFIG_FILE = '.
|
|
7
|
-
export const LOCAL_CONFIG_FILE = '.
|
|
6
|
+
export const CONFIG_FILE = '.cry.json';
|
|
7
|
+
export const LOCAL_CONFIG_FILE = '.cry.local.json';
|
|
8
8
|
export const WORKTREE_INCLUDE_FILE = '.worktreeinclude';
|
|
9
9
|
const DEFAULT_CONFIG = {
|
|
10
10
|
defaultMode: 'copy',
|
package/dist/lib/git.d.ts
CHANGED
package/dist/lib/git.js
CHANGED
package/dist/lib/output.d.ts
CHANGED
package/dist/lib/output.js
CHANGED
package/dist/lib/paths.d.ts
CHANGED
package/dist/lib/paths.js
CHANGED
package/dist/lib/secrets.d.ts
CHANGED
package/dist/lib/secrets.js
CHANGED
package/dist/lib/types.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Cry Configuration Types
|
|
3
3
|
*/
|
|
4
|
-
export interface
|
|
4
|
+
export interface CryConfig {
|
|
5
5
|
/** Base directory for worktrees (optional, defaults to .worktrees/) */
|
|
6
6
|
worktreeBaseDir?: string;
|
|
7
7
|
/** Default mode for secrets handling */
|
|
@@ -15,7 +15,7 @@ export interface VwtConfig {
|
|
|
15
15
|
/** Default agent command */
|
|
16
16
|
agentCommand?: string;
|
|
17
17
|
}
|
|
18
|
-
export interface
|
|
18
|
+
export interface CryLocalConfig {
|
|
19
19
|
/** Machine-specific base directory override */
|
|
20
20
|
worktreeBaseDir?: string;
|
|
21
21
|
/** Additional include paths for this machine */
|
package/dist/lib/types.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cluttry",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "Cluttry - Git worktree management for parallel AI-agent sessions",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -21,7 +21,16 @@
|
|
|
21
21
|
"format": "prettier --write 'src/**/*.ts'",
|
|
22
22
|
"prepare": "npm run build"
|
|
23
23
|
},
|
|
24
|
-
"keywords": [
|
|
24
|
+
"keywords": [
|
|
25
|
+
"git",
|
|
26
|
+
"worktree",
|
|
27
|
+
"cli",
|
|
28
|
+
"ai",
|
|
29
|
+
"agent",
|
|
30
|
+
"claude",
|
|
31
|
+
"vibe",
|
|
32
|
+
"bun"
|
|
33
|
+
],
|
|
25
34
|
"license": "MIT",
|
|
26
35
|
"engines": {
|
|
27
36
|
"node": ">=18.0.0",
|
package/src/commands/open.ts
CHANGED
|
@@ -15,6 +15,7 @@ import * as out from '../lib/output.js';
|
|
|
15
15
|
|
|
16
16
|
interface OpenOptions {
|
|
17
17
|
cmd?: string;
|
|
18
|
+
pathOnly?: boolean;
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
export async function open(branchOrPath: string, options: OpenOptions): Promise<void> {
|
|
@@ -47,6 +48,12 @@ export async function open(branchOrPath: string, options: OpenOptions): Promise<
|
|
|
47
48
|
|
|
48
49
|
const { path: wtPath, branch } = resolved;
|
|
49
50
|
|
|
51
|
+
// If --path-only, just print the path (for scripting)
|
|
52
|
+
if (options.pathOnly) {
|
|
53
|
+
console.log(wtPath);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
50
57
|
// If --cmd is provided, run it
|
|
51
58
|
if (options.cmd) {
|
|
52
59
|
out.log(`Running in ${out.fmt.path(wtPath)}:`);
|
|
@@ -65,6 +72,7 @@ export async function open(branchOrPath: string, options: OpenOptions): Promise<
|
|
|
65
72
|
|
|
66
73
|
// For shell integration hint
|
|
67
74
|
out.newline();
|
|
68
|
-
out.log(out.fmt.dim('Tip:
|
|
69
|
-
out.log(out.fmt.dim(
|
|
75
|
+
out.log(out.fmt.dim('Tip: Add this to your shell profile for easy navigation:'));
|
|
76
|
+
out.log(out.fmt.dim(' crycd() { cd "$(cry open "$1" --path-only)"; }'));
|
|
77
|
+
out.log(out.fmt.dim(' # Then use: crycd feature/my-branch'));
|
|
70
78
|
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cry shell command
|
|
3
|
+
*
|
|
4
|
+
* Output shell integration code for easy directory navigation.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import * as out from '../lib/output.js';
|
|
8
|
+
|
|
9
|
+
type ShellType = 'bash' | 'zsh' | 'fish';
|
|
10
|
+
|
|
11
|
+
const SHELL_FUNCTIONS: Record<ShellType, string> = {
|
|
12
|
+
bash: `# cry shell integration (add to ~/.bashrc)
|
|
13
|
+
crycd() {
|
|
14
|
+
local target
|
|
15
|
+
target="$(cry open "$1" --path-only 2>/dev/null)"
|
|
16
|
+
if [ -n "$target" ]; then
|
|
17
|
+
cd "$target"
|
|
18
|
+
else
|
|
19
|
+
echo "Worktree not found: $1" >&2
|
|
20
|
+
return 1
|
|
21
|
+
fi
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
# Auto-completion for crycd
|
|
25
|
+
_crycd_completions() {
|
|
26
|
+
local branches
|
|
27
|
+
branches=$(cry list --json 2>/dev/null | grep -o '"branch":"[^"]*"' | cut -d'"' -f4)
|
|
28
|
+
COMPREPLY=($(compgen -W "$branches" -- "\${COMP_WORDS[COMP_CWORD]}"))
|
|
29
|
+
}
|
|
30
|
+
complete -F _crycd_completions crycd
|
|
31
|
+
`,
|
|
32
|
+
|
|
33
|
+
zsh: `# cry shell integration (add to ~/.zshrc)
|
|
34
|
+
crycd() {
|
|
35
|
+
local target
|
|
36
|
+
target="$(cry open "$1" --path-only 2>/dev/null)"
|
|
37
|
+
if [[ -n "$target" ]]; then
|
|
38
|
+
cd "$target"
|
|
39
|
+
else
|
|
40
|
+
echo "Worktree not found: $1" >&2
|
|
41
|
+
return 1
|
|
42
|
+
fi
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
# Auto-completion for crycd
|
|
46
|
+
_crycd() {
|
|
47
|
+
local branches
|
|
48
|
+
branches=(\${(f)"$(cry list --json 2>/dev/null | grep -o '"branch":"[^"]*"' | cut -d'"' -f4)"})
|
|
49
|
+
_describe 'branch' branches
|
|
50
|
+
}
|
|
51
|
+
compdef _crycd crycd
|
|
52
|
+
`,
|
|
53
|
+
|
|
54
|
+
fish: `# cry shell integration (add to ~/.config/fish/config.fish)
|
|
55
|
+
function crycd
|
|
56
|
+
set -l target (cry open $argv[1] --path-only 2>/dev/null)
|
|
57
|
+
if test -n "$target"
|
|
58
|
+
cd $target
|
|
59
|
+
else
|
|
60
|
+
echo "Worktree not found: $argv[1]" >&2
|
|
61
|
+
return 1
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Auto-completion for crycd
|
|
66
|
+
complete -c crycd -f -a "(cry list --json 2>/dev/null | grep -o '\"branch\":\"[^\"]*\"' | cut -d'\"' -f4)"
|
|
67
|
+
`,
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
interface ShellOptions {
|
|
71
|
+
shell?: string;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export async function shell(options: ShellOptions): Promise<void> {
|
|
75
|
+
const shellEnv = process.env.SHELL ?? '';
|
|
76
|
+
let detectedShell: ShellType = 'bash';
|
|
77
|
+
|
|
78
|
+
if (options.shell) {
|
|
79
|
+
if (options.shell === 'fish' || options.shell === 'zsh' || options.shell === 'bash') {
|
|
80
|
+
detectedShell = options.shell;
|
|
81
|
+
} else {
|
|
82
|
+
out.error(`Unsupported shell: ${options.shell}`);
|
|
83
|
+
out.info('Supported shells: bash, zsh, fish');
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
} else if (shellEnv.includes('zsh')) {
|
|
87
|
+
detectedShell = 'zsh';
|
|
88
|
+
} else if (shellEnv.includes('fish')) {
|
|
89
|
+
detectedShell = 'fish';
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const script = SHELL_FUNCTIONS[detectedShell];
|
|
93
|
+
|
|
94
|
+
out.log(out.fmt.dim(`# Shell integration for ${detectedShell}`));
|
|
95
|
+
out.log(out.fmt.dim('# Copy and paste into your shell config, or run:'));
|
|
96
|
+
out.log(out.fmt.dim(`# cry shell >> ~/.${detectedShell === 'fish' ? 'config/fish/config.fish' : detectedShell + 'rc'}`));
|
|
97
|
+
out.newline();
|
|
98
|
+
console.log(script);
|
|
99
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -13,6 +13,7 @@ import { open } from './commands/open.js';
|
|
|
13
13
|
import { rm } from './commands/rm.js';
|
|
14
14
|
import { prune } from './commands/prune.js';
|
|
15
15
|
import { doctor } from './commands/doctor.js';
|
|
16
|
+
import { shell } from './commands/shell.js';
|
|
16
17
|
import type { SecretMode } from './lib/types.js';
|
|
17
18
|
|
|
18
19
|
const program = new Command();
|
|
@@ -72,8 +73,9 @@ program
|
|
|
72
73
|
.command('open <branch-or-path>')
|
|
73
74
|
.description('Open or navigate to a worktree by branch name or path')
|
|
74
75
|
.option('-c, --cmd <cmd>', 'Command to execute in the worktree directory')
|
|
76
|
+
.option('-p, --path-only', 'Only print the path (for scripting)')
|
|
75
77
|
.action(async (branchOrPath: string, options) => {
|
|
76
|
-
await open(branchOrPath, { cmd: options.cmd });
|
|
78
|
+
await open(branchOrPath, { cmd: options.cmd, pathOnly: options.pathOnly });
|
|
77
79
|
});
|
|
78
80
|
|
|
79
81
|
// cry rm <branch-or-path>
|
|
@@ -108,5 +110,14 @@ program
|
|
|
108
110
|
await doctor();
|
|
109
111
|
});
|
|
110
112
|
|
|
113
|
+
// cry shell
|
|
114
|
+
program
|
|
115
|
+
.command('shell')
|
|
116
|
+
.description('Output shell integration code for crycd navigation function')
|
|
117
|
+
.option('-s, --shell <shell>', 'Shell type: bash, zsh, or fish (auto-detected)')
|
|
118
|
+
.action(async (options) => {
|
|
119
|
+
await shell({ shell: options.shell });
|
|
120
|
+
});
|
|
121
|
+
|
|
111
122
|
// Parse and execute
|
|
112
123
|
program.parse();
|
package/src/lib/config.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Configuration management for
|
|
2
|
+
* Configuration management for cry
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
6
6
|
import path from 'node:path';
|
|
7
|
-
import type { MergedConfig,
|
|
7
|
+
import type { MergedConfig, CryConfig, CryLocalConfig } from './types.js';
|
|
8
8
|
|
|
9
|
-
export const CONFIG_FILE = '.
|
|
10
|
-
export const LOCAL_CONFIG_FILE = '.
|
|
9
|
+
export const CONFIG_FILE = '.cry.json';
|
|
10
|
+
export const LOCAL_CONFIG_FILE = '.cry.local.json';
|
|
11
11
|
export const WORKTREE_INCLUDE_FILE = '.worktreeinclude';
|
|
12
12
|
|
|
13
|
-
const DEFAULT_CONFIG:
|
|
13
|
+
const DEFAULT_CONFIG: CryConfig = {
|
|
14
14
|
defaultMode: 'copy',
|
|
15
15
|
include: ['.env', '.env.*', '.env.local'],
|
|
16
16
|
hooks: {
|
|
@@ -22,14 +22,14 @@ const DEFAULT_CONFIG: VwtConfig = {
|
|
|
22
22
|
/**
|
|
23
23
|
* Load the main config file
|
|
24
24
|
*/
|
|
25
|
-
export function loadConfig(repoRoot: string):
|
|
25
|
+
export function loadConfig(repoRoot: string): CryConfig | null {
|
|
26
26
|
const configPath = path.join(repoRoot, CONFIG_FILE);
|
|
27
27
|
if (!existsSync(configPath)) {
|
|
28
28
|
return null;
|
|
29
29
|
}
|
|
30
30
|
try {
|
|
31
31
|
const content = readFileSync(configPath, 'utf-8');
|
|
32
|
-
return JSON.parse(content) as
|
|
32
|
+
return JSON.parse(content) as CryConfig;
|
|
33
33
|
} catch (error) {
|
|
34
34
|
throw new Error(`Failed to parse ${CONFIG_FILE}: ${(error as Error).message}`);
|
|
35
35
|
}
|
|
@@ -38,14 +38,14 @@ export function loadConfig(repoRoot: string): VwtConfig | null {
|
|
|
38
38
|
/**
|
|
39
39
|
* Load the local config file
|
|
40
40
|
*/
|
|
41
|
-
export function loadLocalConfig(repoRoot: string):
|
|
41
|
+
export function loadLocalConfig(repoRoot: string): CryLocalConfig | null {
|
|
42
42
|
const configPath = path.join(repoRoot, LOCAL_CONFIG_FILE);
|
|
43
43
|
if (!existsSync(configPath)) {
|
|
44
44
|
return null;
|
|
45
45
|
}
|
|
46
46
|
try {
|
|
47
47
|
const content = readFileSync(configPath, 'utf-8');
|
|
48
|
-
return JSON.parse(content) as
|
|
48
|
+
return JSON.parse(content) as CryLocalConfig;
|
|
49
49
|
} catch (error) {
|
|
50
50
|
throw new Error(`Failed to parse ${LOCAL_CONFIG_FILE}: ${(error as Error).message}`);
|
|
51
51
|
}
|
|
@@ -54,7 +54,7 @@ export function loadLocalConfig(repoRoot: string): VwtLocalConfig | null {
|
|
|
54
54
|
/**
|
|
55
55
|
* Merge main config with local overrides
|
|
56
56
|
*/
|
|
57
|
-
export function mergeConfig(config:
|
|
57
|
+
export function mergeConfig(config: CryConfig | null, localConfig: CryLocalConfig | null): MergedConfig {
|
|
58
58
|
const base = config ?? DEFAULT_CONFIG;
|
|
59
59
|
|
|
60
60
|
return {
|
|
@@ -83,7 +83,7 @@ export function getMergedConfig(repoRoot: string): MergedConfig {
|
|
|
83
83
|
/**
|
|
84
84
|
* Save the main config file
|
|
85
85
|
*/
|
|
86
|
-
export function saveConfig(repoRoot: string, config:
|
|
86
|
+
export function saveConfig(repoRoot: string, config: CryConfig): void {
|
|
87
87
|
const configPath = path.join(repoRoot, CONFIG_FILE);
|
|
88
88
|
writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n');
|
|
89
89
|
}
|
|
@@ -91,7 +91,7 @@ export function saveConfig(repoRoot: string, config: VwtConfig): void {
|
|
|
91
91
|
/**
|
|
92
92
|
* Save the local config file
|
|
93
93
|
*/
|
|
94
|
-
export function saveLocalConfig(repoRoot: string, config:
|
|
94
|
+
export function saveLocalConfig(repoRoot: string, config: CryLocalConfig): void {
|
|
95
95
|
const configPath = path.join(repoRoot, LOCAL_CONFIG_FILE);
|
|
96
96
|
writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n');
|
|
97
97
|
}
|
|
@@ -106,14 +106,14 @@ export function configExists(repoRoot: string): boolean {
|
|
|
106
106
|
/**
|
|
107
107
|
* Get default config
|
|
108
108
|
*/
|
|
109
|
-
export function getDefaultConfig():
|
|
109
|
+
export function getDefaultConfig(): CryConfig {
|
|
110
110
|
return { ...DEFAULT_CONFIG };
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
/**
|
|
114
114
|
* Create default local config
|
|
115
115
|
*/
|
|
116
|
-
export function getDefaultLocalConfig():
|
|
116
|
+
export function getDefaultLocalConfig(): CryLocalConfig {
|
|
117
117
|
return {
|
|
118
118
|
include: [],
|
|
119
119
|
};
|
package/src/lib/git.ts
CHANGED
package/src/lib/output.ts
CHANGED
package/src/lib/paths.ts
CHANGED
package/src/lib/secrets.ts
CHANGED
package/src/lib/types.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Cry Configuration Types
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
export interface
|
|
5
|
+
export interface CryConfig {
|
|
6
6
|
/** Base directory for worktrees (optional, defaults to .worktrees/) */
|
|
7
7
|
worktreeBaseDir?: string;
|
|
8
8
|
/** Default mode for secrets handling */
|
|
@@ -17,7 +17,7 @@ export interface VwtConfig {
|
|
|
17
17
|
agentCommand?: string;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
export interface
|
|
20
|
+
export interface CryLocalConfig {
|
|
21
21
|
/** Machine-specific base directory override */
|
|
22
22
|
worktreeBaseDir?: string;
|
|
23
23
|
/** Additional include paths for this machine */
|
package/tests/config.test.ts
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
import { describe, it, expect } from 'vitest';
|
|
6
6
|
import { mergeConfig } from '../src/lib/config.js';
|
|
7
|
-
import type {
|
|
7
|
+
import type { CryConfig, CryLocalConfig } from '../src/lib/types.js';
|
|
8
8
|
|
|
9
9
|
describe('mergeConfig', () => {
|
|
10
|
-
const baseConfig:
|
|
10
|
+
const baseConfig: CryConfig = {
|
|
11
11
|
defaultMode: 'copy',
|
|
12
12
|
include: ['.env', '.env.local'],
|
|
13
13
|
hooks: {
|
|
@@ -34,7 +34,7 @@ describe('mergeConfig', () => {
|
|
|
34
34
|
});
|
|
35
35
|
|
|
36
36
|
it('merges include arrays from both configs', () => {
|
|
37
|
-
const localConfig:
|
|
37
|
+
const localConfig: CryLocalConfig = {
|
|
38
38
|
include: ['credentials.json', '.secrets'],
|
|
39
39
|
};
|
|
40
40
|
const result = mergeConfig(baseConfig, localConfig);
|
|
@@ -42,7 +42,7 @@ describe('mergeConfig', () => {
|
|
|
42
42
|
});
|
|
43
43
|
|
|
44
44
|
it('local worktreeBaseDir overrides base', () => {
|
|
45
|
-
const localConfig:
|
|
45
|
+
const localConfig: CryLocalConfig = {
|
|
46
46
|
worktreeBaseDir: '/custom/local/path',
|
|
47
47
|
};
|
|
48
48
|
const result = mergeConfig(baseConfig, localConfig);
|
|
@@ -50,7 +50,7 @@ describe('mergeConfig', () => {
|
|
|
50
50
|
});
|
|
51
51
|
|
|
52
52
|
it('local agentCommand overrides base', () => {
|
|
53
|
-
const localConfig:
|
|
53
|
+
const localConfig: CryLocalConfig = {
|
|
54
54
|
agentCommand: 'cursor',
|
|
55
55
|
};
|
|
56
56
|
const result = mergeConfig(baseConfig, localConfig);
|
|
@@ -58,7 +58,7 @@ describe('mergeConfig', () => {
|
|
|
58
58
|
});
|
|
59
59
|
|
|
60
60
|
it('merges postCreate hooks from both configs', () => {
|
|
61
|
-
const localConfig:
|
|
61
|
+
const localConfig: CryLocalConfig = {
|
|
62
62
|
hooks: {
|
|
63
63
|
postCreate: ['npm run dev', 'code .'],
|
|
64
64
|
},
|
|
@@ -68,11 +68,11 @@ describe('mergeConfig', () => {
|
|
|
68
68
|
});
|
|
69
69
|
|
|
70
70
|
it('handles empty include arrays', () => {
|
|
71
|
-
const config:
|
|
71
|
+
const config: CryConfig = {
|
|
72
72
|
defaultMode: 'none',
|
|
73
73
|
include: [],
|
|
74
74
|
};
|
|
75
|
-
const localConfig:
|
|
75
|
+
const localConfig: CryLocalConfig = {
|
|
76
76
|
include: [],
|
|
77
77
|
};
|
|
78
78
|
const result = mergeConfig(config, localConfig);
|
|
@@ -80,7 +80,7 @@ describe('mergeConfig', () => {
|
|
|
80
80
|
});
|
|
81
81
|
|
|
82
82
|
it('handles missing hooks in configs', () => {
|
|
83
|
-
const config:
|
|
83
|
+
const config: CryConfig = {
|
|
84
84
|
defaultMode: 'symlink',
|
|
85
85
|
include: ['.env'],
|
|
86
86
|
};
|
|
@@ -89,11 +89,11 @@ describe('mergeConfig', () => {
|
|
|
89
89
|
});
|
|
90
90
|
|
|
91
91
|
it('preserves defaultMode from base config', () => {
|
|
92
|
-
const config:
|
|
92
|
+
const config: CryConfig = {
|
|
93
93
|
defaultMode: 'symlink',
|
|
94
94
|
include: [],
|
|
95
95
|
};
|
|
96
|
-
const localConfig:
|
|
96
|
+
const localConfig: CryLocalConfig = {
|
|
97
97
|
include: ['.env'],
|
|
98
98
|
};
|
|
99
99
|
const result = mergeConfig(config, localConfig);
|