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.
@@ -0,0 +1,7 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "mcp__tavily__tavily-search"
5
+ ]
6
+ }
7
+ }
package/README.md CHANGED
@@ -74,8 +74,8 @@ cry init [--force]
74
74
  ```
75
75
 
76
76
  Creates:
77
- - `.vwt.json` — tracked config with defaults
78
- - `.vwt.local.json` — gitignored local overrides
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
- ### `.vwt.json` (tracked)
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
- ### `.vwt.local.json` (gitignored)
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 `.vwt.json` to include your secret files:
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
- .vwt.json # Tracked config
348
- .vwt.local.json # Local overrides (gitignored)
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 .vwt.local.json
393
+ # Or override in .cry.local.json
394
394
  {
395
395
  "agentCommand": "your-agent-command"
396
396
  }
@@ -5,6 +5,7 @@
5
5
  */
6
6
  interface OpenOptions {
7
7
  cmd?: string;
8
+ pathOnly?: boolean;
8
9
  }
9
10
  export declare function open(branchOrPath: string, options: OpenOptions): Promise<void>;
10
11
  export {};
@@ -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;CACd;AAED,wBAAsB,IAAI,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAkDpF"}
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"}
@@ -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: Use command substitution in your shell:'));
50
- out.log(out.fmt.dim(` cd "$(vwt open ${branchOrPath} 2>/dev/null | grep "^Path:" | cut -d' ' -f2-)"`));
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":"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"}
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":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -1,22 +1,22 @@
1
1
  /**
2
- * Configuration management for VWT
2
+ * Configuration management for cry
3
3
  */
4
- import type { MergedConfig, VwtConfig, VwtLocalConfig } from './types.js';
5
- export declare const CONFIG_FILE = ".vwt.json";
6
- export declare const LOCAL_CONFIG_FILE = ".vwt.local.json";
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): VwtConfig | null;
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): VwtLocalConfig | null;
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: VwtConfig | null, localConfig: VwtLocalConfig | null): MergedConfig;
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: VwtConfig): void;
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: VwtLocalConfig): void;
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(): VwtConfig;
39
+ export declare function getDefaultConfig(): CryConfig;
40
40
  /**
41
41
  * Create default local config
42
42
  */
43
- export declare function getDefaultLocalConfig(): VwtLocalConfig;
43
+ export declare function getDefaultLocalConfig(): CryLocalConfig;
44
44
  //# sourceMappingURL=config.d.ts.map
@@ -1,10 +1,10 @@
1
1
  /**
2
- * Configuration management for VWT
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 = '.vwt.json';
7
- export const LOCAL_CONFIG_FILE = '.vwt.local.json';
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
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Git operations for VWT
2
+ * Git operations for cry
3
3
  */
4
4
  import type { WorktreeInfo } from './types.js';
5
5
  /**
package/dist/lib/git.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Git operations for VWT
2
+ * Git operations for cry
3
3
  */
4
4
  import { execSync, spawn } from 'node:child_process';
5
5
  import path from 'node:path';
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Output utilities for VWT
2
+ * Output utilities for cry
3
3
  *
4
4
  * Provides consistent, colorful terminal output without external dependencies.
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Output utilities for VWT
2
+ * Output utilities for cry
3
3
  *
4
4
  * Provides consistent, colorful terminal output without external dependencies.
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Path utilities for VWT
2
+ * Path utilities for cry
3
3
  */
4
4
  /**
5
5
  * Sanitize a branch name for use in filesystem paths
package/dist/lib/paths.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Path utilities for VWT
2
+ * Path utilities for cry
3
3
  */
4
4
  import path from 'node:path';
5
5
  /**
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Secret file handling for VWT
2
+ * Secret file handling for cry
3
3
  *
4
4
  * This module ensures that only git-ignored files are ever copied or symlinked.
5
5
  * It provides a safety layer to prevent accidentally exposing tracked files.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Secret file handling for VWT
2
+ * Secret file handling for cry
3
3
  *
4
4
  * This module ensures that only git-ignored files are ever copied or symlinked.
5
5
  * It provides a safety layer to prevent accidentally exposing tracked files.
@@ -1,7 +1,7 @@
1
1
  /**
2
- * VWT Configuration Types
2
+ * Cry Configuration Types
3
3
  */
4
- export interface VwtConfig {
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 VwtLocalConfig {
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
@@ -1,5 +1,5 @@
1
1
  /**
2
- * VWT Configuration Types
2
+ * Cry Configuration Types
3
3
  */
4
4
  export {};
5
5
  //# sourceMappingURL=types.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cluttry",
3
- "version": "1.0.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": ["git", "worktree", "cli", "ai", "agent", "claude", "vibe", "bun"],
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",
@@ -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: Use command substitution in your shell:'));
69
- out.log(out.fmt.dim(` cd "$(vwt open ${branchOrPath} 2>/dev/null | grep "^Path:" | cut -d' ' -f2-)"`));
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 VWT
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, VwtConfig, VwtLocalConfig } from './types.js';
7
+ import type { MergedConfig, CryConfig, CryLocalConfig } from './types.js';
8
8
 
9
- export const CONFIG_FILE = '.vwt.json';
10
- export const LOCAL_CONFIG_FILE = '.vwt.local.json';
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: VwtConfig = {
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): VwtConfig | null {
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 VwtConfig;
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): VwtLocalConfig | null {
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 VwtLocalConfig;
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: VwtConfig | null, localConfig: VwtLocalConfig | null): MergedConfig {
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: VwtConfig): void {
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: VwtLocalConfig): void {
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(): VwtConfig {
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(): VwtLocalConfig {
116
+ export function getDefaultLocalConfig(): CryLocalConfig {
117
117
  return {
118
118
  include: [],
119
119
  };
package/src/lib/git.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Git operations for VWT
2
+ * Git operations for cry
3
3
  */
4
4
 
5
5
  import { execSync, spawn } from 'node:child_process';
package/src/lib/output.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Output utilities for VWT
2
+ * Output utilities for cry
3
3
  *
4
4
  * Provides consistent, colorful terminal output without external dependencies.
5
5
  */
package/src/lib/paths.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Path utilities for VWT
2
+ * Path utilities for cry
3
3
  */
4
4
 
5
5
  import path from 'node:path';
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Secret file handling for VWT
2
+ * Secret file handling for cry
3
3
  *
4
4
  * This module ensures that only git-ignored files are ever copied or symlinked.
5
5
  * It provides a safety layer to prevent accidentally exposing tracked files.
package/src/lib/types.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  /**
2
- * VWT Configuration Types
2
+ * Cry Configuration Types
3
3
  */
4
4
 
5
- export interface VwtConfig {
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 VwtLocalConfig {
20
+ export interface CryLocalConfig {
21
21
  /** Machine-specific base directory override */
22
22
  worktreeBaseDir?: string;
23
23
  /** Additional include paths for this machine */
@@ -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 { VwtConfig, VwtLocalConfig } from '../src/lib/types.js';
7
+ import type { CryConfig, CryLocalConfig } from '../src/lib/types.js';
8
8
 
9
9
  describe('mergeConfig', () => {
10
- const baseConfig: VwtConfig = {
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: VwtLocalConfig = {
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: VwtLocalConfig = {
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: VwtLocalConfig = {
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: VwtLocalConfig = {
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: VwtConfig = {
71
+ const config: CryConfig = {
72
72
  defaultMode: 'none',
73
73
  include: [],
74
74
  };
75
- const localConfig: VwtLocalConfig = {
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: VwtConfig = {
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: VwtConfig = {
92
+ const config: CryConfig = {
93
93
  defaultMode: 'symlink',
94
94
  include: [],
95
95
  };
96
- const localConfig: VwtLocalConfig = {
96
+ const localConfig: CryLocalConfig = {
97
97
  include: ['.env'],
98
98
  };
99
99
  const result = mergeConfig(config, localConfig);
package/.vwt.json DELETED
@@ -1,12 +0,0 @@
1
- {
2
- "defaultMode": "copy",
3
- "include": [
4
- ".env",
5
- ".env.*",
6
- ".env.local"
7
- ],
8
- "hooks": {
9
- "postCreate": []
10
- },
11
- "agentCommand": "claude"
12
- }