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.
Files changed (79) hide show
  1. package/.vwt.json +12 -0
  2. package/LICENSE +21 -0
  3. package/README.md +444 -0
  4. package/dist/commands/doctor.d.ts +7 -0
  5. package/dist/commands/doctor.d.ts.map +1 -0
  6. package/dist/commands/doctor.js +198 -0
  7. package/dist/commands/doctor.js.map +1 -0
  8. package/dist/commands/init.d.ts +11 -0
  9. package/dist/commands/init.d.ts.map +1 -0
  10. package/dist/commands/init.js +90 -0
  11. package/dist/commands/init.js.map +1 -0
  12. package/dist/commands/list.d.ts +11 -0
  13. package/dist/commands/list.d.ts.map +1 -0
  14. package/dist/commands/list.js +106 -0
  15. package/dist/commands/list.js.map +1 -0
  16. package/dist/commands/open.d.ts +11 -0
  17. package/dist/commands/open.d.ts.map +1 -0
  18. package/dist/commands/open.js +52 -0
  19. package/dist/commands/open.js.map +1 -0
  20. package/dist/commands/prune.d.ts +7 -0
  21. package/dist/commands/prune.d.ts.map +1 -0
  22. package/dist/commands/prune.js +33 -0
  23. package/dist/commands/prune.js.map +1 -0
  24. package/dist/commands/rm.d.ts +13 -0
  25. package/dist/commands/rm.d.ts.map +1 -0
  26. package/dist/commands/rm.js +99 -0
  27. package/dist/commands/rm.js.map +1 -0
  28. package/dist/commands/spawn.d.ts +17 -0
  29. package/dist/commands/spawn.d.ts.map +1 -0
  30. package/dist/commands/spawn.js +127 -0
  31. package/dist/commands/spawn.js.map +1 -0
  32. package/dist/index.d.ts +8 -0
  33. package/dist/index.d.ts.map +1 -0
  34. package/dist/index.js +101 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/lib/config.d.ts +44 -0
  37. package/dist/lib/config.d.ts.map +1 -0
  38. package/dist/lib/config.js +109 -0
  39. package/dist/lib/config.js.map +1 -0
  40. package/dist/lib/git.d.ts +73 -0
  41. package/dist/lib/git.d.ts.map +1 -0
  42. package/dist/lib/git.js +225 -0
  43. package/dist/lib/git.js.map +1 -0
  44. package/dist/lib/output.d.ts +33 -0
  45. package/dist/lib/output.d.ts.map +1 -0
  46. package/dist/lib/output.js +83 -0
  47. package/dist/lib/output.js.map +1 -0
  48. package/dist/lib/paths.d.ts +36 -0
  49. package/dist/lib/paths.d.ts.map +1 -0
  50. package/dist/lib/paths.js +84 -0
  51. package/dist/lib/paths.js.map +1 -0
  52. package/dist/lib/secrets.d.ts +50 -0
  53. package/dist/lib/secrets.d.ts.map +1 -0
  54. package/dist/lib/secrets.js +146 -0
  55. package/dist/lib/secrets.js.map +1 -0
  56. package/dist/lib/types.d.ts +63 -0
  57. package/dist/lib/types.d.ts.map +1 -0
  58. package/dist/lib/types.js +5 -0
  59. package/dist/lib/types.js.map +1 -0
  60. package/package.json +41 -0
  61. package/src/commands/doctor.ts +222 -0
  62. package/src/commands/init.ts +120 -0
  63. package/src/commands/list.ts +133 -0
  64. package/src/commands/open.ts +70 -0
  65. package/src/commands/prune.ts +36 -0
  66. package/src/commands/rm.ts +125 -0
  67. package/src/commands/spawn.ts +169 -0
  68. package/src/index.ts +112 -0
  69. package/src/lib/config.ts +120 -0
  70. package/src/lib/git.ts +243 -0
  71. package/src/lib/output.ts +102 -0
  72. package/src/lib/paths.ts +108 -0
  73. package/src/lib/secrets.ts +193 -0
  74. package/src/lib/types.ts +69 -0
  75. package/tests/config.test.ts +102 -0
  76. package/tests/paths.test.ts +155 -0
  77. package/tests/secrets.test.ts +150 -0
  78. package/tsconfig.json +20 -0
  79. package/vitest.config.ts +15 -0
package/.vwt.json ADDED
@@ -0,0 +1,12 @@
1
+ {
2
+ "defaultMode": "copy",
3
+ "include": [
4
+ ".env",
5
+ ".env.*",
6
+ ".env.local"
7
+ ],
8
+ "hooks": {
9
+ "postCreate": []
10
+ },
11
+ "agentCommand": "claude"
12
+ }
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,444 @@
1
+ # cluttry
2
+
3
+ Git worktrees made painless for **vibecoders** running parallel AI-agent sessions.
4
+
5
+ **CLI command:** `cry`
6
+
7
+ ## Why This Exists
8
+
9
+ When working with AI coding assistants like Claude, you often want to run multiple parallel sessions on different branches. Git worktrees are perfect for this—each worktree is a separate checkout where an agent can work independently.
10
+
11
+ But managing worktrees manually is tedious:
12
+ - You have to remember the `git worktree` commands
13
+ - You need to copy your `.env` files and secrets to each worktree
14
+ - You want to run setup commands like `npm install` automatically
15
+ - You want to launch your AI agent in the new worktree
16
+
17
+ **cry** solves all of this with one command.
18
+
19
+ ## Installation
20
+
21
+ ### Using Bun (recommended)
22
+
23
+ ```bash
24
+ # Install globally with Bun
25
+ bun add -g cluttry
26
+
27
+ # Or clone and link
28
+ git clone https://github.com/your-username/cluttry.git
29
+ cd cluttry
30
+ bun install
31
+ bun link
32
+ ```
33
+
34
+ ### Using npm
35
+
36
+ ```bash
37
+ # Install globally with npm
38
+ npm install -g cluttry
39
+
40
+ # Or clone and link
41
+ git clone https://github.com/your-username/cluttry.git
42
+ cd cluttry
43
+ npm install
44
+ npm link
45
+ ```
46
+
47
+ **Requirements:** Bun 1.0+ or Node.js 18+, Git 2.5+
48
+
49
+ ## Quick Start
50
+
51
+ ```bash
52
+ # Initialize cry in your repository
53
+ cd your-repo
54
+ cry init
55
+
56
+ # Spawn a new worktree for a feature branch
57
+ cry spawn feature-auth --new
58
+
59
+ # List all worktrees
60
+ cry list
61
+
62
+ # Remove a worktree when done
63
+ cry rm feature-auth --with-branch
64
+ ```
65
+
66
+ ## Commands
67
+
68
+ ### `cry init`
69
+
70
+ Initialize cry configuration in your repository.
71
+
72
+ ```bash
73
+ cry init [--force]
74
+ ```
75
+
76
+ Creates:
77
+ - `.vwt.json` — tracked config with defaults
78
+ - `.vwt.local.json` — gitignored local overrides
79
+ - Updates `.gitignore` to ignore local config and `.worktrees/`
80
+
81
+ ### `cry spawn <branch>`
82
+
83
+ Create a worktree for a branch with automatic secrets handling.
84
+
85
+ ```bash
86
+ cry spawn <branch> [options]
87
+
88
+ Options:
89
+ -n, --new Create a new branch
90
+ -p, --path <dir> Explicit worktree path
91
+ -b, --base <dir> Base directory for worktrees
92
+ -m, --mode <mode> Secret handling: copy, symlink, or none (default: copy)
93
+ -r, --run <cmd> Command to run after creation
94
+ -a, --agent <agent> Launch agent: claude or none (default: none)
95
+ ```
96
+
97
+ **Examples:**
98
+
99
+ ```bash
100
+ # Create worktree for existing branch
101
+ cry spawn feature-auth
102
+
103
+ # Create new branch and worktree
104
+ cry spawn feature-oauth --new
105
+
106
+ # Spawn with npm install and launch Claude
107
+ cry spawn feature-api --new --run "npm install" --agent claude
108
+
109
+ # Use symlinks instead of copying secrets
110
+ cry spawn bugfix-123 --mode symlink
111
+
112
+ # Custom worktree location
113
+ cry spawn hotfix --path ~/worktrees/myrepo-hotfix
114
+ ```
115
+
116
+ ### `cry list`
117
+
118
+ List all worktrees with their status.
119
+
120
+ ```bash
121
+ cry list [--json]
122
+ ```
123
+
124
+ Shows: branch name, commit SHA, dirty status, last modified time, and path.
125
+
126
+ ### `cry open <branch-or-path>`
127
+
128
+ Navigate to or run a command in a worktree.
129
+
130
+ ```bash
131
+ cry open <branch-or-path> [--cmd <cmd>]
132
+ ```
133
+
134
+ **Examples:**
135
+
136
+ ```bash
137
+ # Show path and cd instructions
138
+ cry open feature-auth
139
+
140
+ # Run a command in the worktree
141
+ cry open feature-auth --cmd "npm test"
142
+
143
+ # Open in VS Code
144
+ cry open feature-auth --cmd "code ."
145
+ ```
146
+
147
+ ### `cry rm <branch-or-path>`
148
+
149
+ Remove a worktree safely.
150
+
151
+ ```bash
152
+ cry rm <branch-or-path> [options]
153
+
154
+ Options:
155
+ -b, --with-branch Also delete the branch
156
+ -f, --force Force removal even if dirty
157
+ -y, --yes Skip confirmation prompts
158
+ ```
159
+
160
+ **Examples:**
161
+
162
+ ```bash
163
+ # Remove worktree only
164
+ cry rm feature-auth
165
+
166
+ # Remove worktree and delete branch
167
+ cry rm feature-auth --with-branch
168
+
169
+ # Force remove dirty worktree
170
+ cry rm feature-auth --force --yes
171
+ ```
172
+
173
+ ### `cry prune`
174
+
175
+ Clean up stale worktree references.
176
+
177
+ ```bash
178
+ cry prune
179
+ ```
180
+
181
+ Runs `git worktree prune` and shows what was cleaned.
182
+
183
+ ### `cry doctor`
184
+
185
+ Check your cry configuration for issues.
186
+
187
+ ```bash
188
+ cry doctor
189
+ ```
190
+
191
+ Checks:
192
+ - Config file exists
193
+ - Local config is gitignored
194
+ - `.worktrees/` is gitignored
195
+ - Include files are safely gitignored
196
+ - Agent command is available
197
+
198
+ ## Configuration
199
+
200
+ ### `.vwt.json` (tracked)
201
+
202
+ ```json
203
+ {
204
+ "defaultMode": "copy",
205
+ "include": [".env", ".env.*", ".env.local", "config/secrets/*.json"],
206
+ "worktreeBaseDir": null,
207
+ "hooks": {
208
+ "postCreate": ["npm install"]
209
+ },
210
+ "agentCommand": "claude"
211
+ }
212
+ ```
213
+
214
+ | Option | Description |
215
+ |--------|-------------|
216
+ | `defaultMode` | How to handle secrets: `copy`, `symlink`, or `none` |
217
+ | `include` | Glob patterns for files to copy/symlink |
218
+ | `worktreeBaseDir` | Base directory for worktrees (default: `.worktrees/`) |
219
+ | `hooks.postCreate` | Commands to run after spawning |
220
+ | `agentCommand` | Command to launch AI agent |
221
+
222
+ ### `.vwt.local.json` (gitignored)
223
+
224
+ Machine-specific overrides:
225
+
226
+ ```json
227
+ {
228
+ "worktreeBaseDir": "/home/user/worktrees",
229
+ "include": ["config/local-secrets.json"],
230
+ "hooks": {
231
+ "postCreate": ["npm install", "./setup-dev.sh"]
232
+ },
233
+ "agentCommand": "cursor"
234
+ }
235
+ ```
236
+
237
+ Local config merges with tracked config:
238
+ - `include` arrays are concatenated
239
+ - `hooks.postCreate` arrays are concatenated
240
+ - Other values override
241
+
242
+ ## Security Model
243
+
244
+ **cry is safe by default.** It enforces strict rules about which files can be copied or symlinked:
245
+
246
+ ### Rule 1: Never Copy Tracked Files
247
+
248
+ Files that are tracked by git are **never** copied or symlinked. This prevents accidentally exposing source code or committing secrets that should stay local.
249
+
250
+ ```bash
251
+ # Checked with: git ls-files --error-unmatch <file>
252
+ # If file is tracked → REFUSED
253
+ ```
254
+
255
+ ### Rule 2: Only Copy Ignored Files
256
+
257
+ Files must be explicitly ignored by git (in `.gitignore`) to be eligible for copy/symlink.
258
+
259
+ ```bash
260
+ # Checked with: git check-ignore -q <file>
261
+ # If file is NOT ignored → REFUSED
262
+ ```
263
+
264
+ ### Implications
265
+
266
+ - Your `.env` files must be in `.gitignore` ✓
267
+ - Your OAuth JSON files must be in `.gitignore` ✓
268
+ - Source files can never be in `include` patterns ✗
269
+
270
+ ### Copy vs Symlink Tradeoffs
271
+
272
+ | Mode | Pros | Cons |
273
+ |------|------|------|
274
+ | `copy` | Independent copies, safe if original changes | Takes disk space, copies can drift |
275
+ | `symlink` | Always in sync, saves space | Changes affect all worktrees |
276
+ | `none` | No secrets copied | Must set up secrets manually |
277
+
278
+ **Recommendation:** Use `copy` (default) for most cases. Use `symlink` if you frequently update secrets and want all worktrees to stay in sync.
279
+
280
+ ## Using with AI Agents
281
+
282
+ ### Recommended Pattern
283
+
284
+ 1. **Initialize once per repo:**
285
+ ```bash
286
+ cry init
287
+ ```
288
+
289
+ 2. **Configure your secrets:**
290
+ Edit `.vwt.json` to include your secret files:
291
+ ```json
292
+ {
293
+ "include": [".env", ".env.local", "config/oauth*.json"]
294
+ }
295
+ ```
296
+
297
+ 3. **Spawn a worktree for each task:**
298
+ ```bash
299
+ cry spawn fix-auth-bug --new --run "npm install" --agent claude
300
+ ```
301
+
302
+ 4. **Work with your AI agent in the worktree**
303
+
304
+ 5. **Clean up when done:**
305
+ ```bash
306
+ cry rm fix-auth-bug --with-branch
307
+ ```
308
+
309
+ ### Denying AI Access to Secrets
310
+
311
+ If you want to prevent AI agents from reading your secret files:
312
+
313
+ **For Claude Code:** Add to your `.clauderc`:
314
+ ```json
315
+ {
316
+ "deny": [".env", ".env.*", "config/secrets/**"]
317
+ }
318
+ ```
319
+
320
+ **For other agents:** Check their documentation for file access controls.
321
+
322
+ ### Multiple Parallel Sessions
323
+
324
+ Run multiple agents on different features simultaneously:
325
+
326
+ ```bash
327
+ # Terminal 1
328
+ cry spawn feature-auth --new --agent claude
329
+
330
+ # Terminal 2
331
+ cry spawn feature-payments --new --agent claude
332
+
333
+ # Terminal 3
334
+ cry spawn bugfix-123 --agent claude
335
+ ```
336
+
337
+ Each agent works in an isolated worktree with its own copy of secrets.
338
+
339
+ ## Project Structure
340
+
341
+ ```
342
+ .worktrees/ # Default worktree location (gitignored)
343
+ ├── feature-auth/ # Worktree for feature-auth branch
344
+ ├── feature-payments/ # Worktree for feature-payments branch
345
+ └── bugfix-123/ # Worktree for bugfix-123 branch
346
+
347
+ .vwt.json # Tracked config
348
+ .vwt.local.json # Local overrides (gitignored)
349
+ ```
350
+
351
+ ## Troubleshooting
352
+
353
+ ### "Not a git repository"
354
+
355
+ Run cry commands from within a git repository.
356
+
357
+ ### "Worktree already exists for branch"
358
+
359
+ A worktree already exists for that branch. Remove it first:
360
+ ```bash
361
+ cry rm <branch>
362
+ ```
363
+
364
+ ### "Destination already exists"
365
+
366
+ The target directory exists. Either remove it or specify a different path:
367
+ ```bash
368
+ cry spawn feature --path ./different-path
369
+ ```
370
+
371
+ ### "File is tracked by git"
372
+
373
+ A file in your `include` patterns is tracked by git. Remove it from tracking:
374
+ ```bash
375
+ git rm --cached <file>
376
+ echo "<file>" >> .gitignore
377
+ ```
378
+
379
+ ### "File is not ignored by git"
380
+
381
+ A file in your `include` patterns isn't in `.gitignore`. Add it:
382
+ ```bash
383
+ echo "<file>" >> .gitignore
384
+ ```
385
+
386
+ ### Agent command not found
387
+
388
+ Install the AI agent CLI or update `agentCommand` in your config:
389
+ ```bash
390
+ # For Claude
391
+ npm install -g @anthropic-ai/claude-code
392
+
393
+ # Or override in .vwt.local.json
394
+ {
395
+ "agentCommand": "your-agent-command"
396
+ }
397
+ ```
398
+
399
+ ## Development
400
+
401
+ ```bash
402
+ # Install dependencies
403
+ npm install
404
+
405
+ # Build
406
+ npm run build
407
+
408
+ # Run tests
409
+ npm test
410
+
411
+ # Watch mode
412
+ npm run dev
413
+ ```
414
+
415
+ ## Tech Stack
416
+
417
+ - **Language:** TypeScript (Node.js)
418
+ - **CLI Framework:** Commander.js
419
+ - **Testing:** Vitest
420
+ - **Dependencies:** Minimal (commander, glob)
421
+
422
+ ### Why TypeScript/Node.js?
423
+
424
+ 1. **Accessible:** Most developers working with web projects have Node.js installed
425
+ 2. **Cross-platform:** Works on macOS, Linux, and Windows
426
+ 3. **Contribution-friendly:** TypeScript is widely known and well-typed
427
+ 4. **Rich ecosystem:** Excellent CLI tooling available
428
+
429
+ ## License
430
+
431
+ MIT
432
+
433
+ ## Contributing
434
+
435
+ Contributions welcome! Please:
436
+
437
+ 1. Fork the repository
438
+ 2. Create a feature branch
439
+ 3. Write tests for new functionality
440
+ 4. Submit a pull request
441
+
442
+ ## Acknowledgments
443
+
444
+ Inspired by the need to run parallel AI coding sessions efficiently. Built for vibecoders everywhere.
@@ -0,0 +1,7 @@
1
+ /**
2
+ * cry doctor command
3
+ *
4
+ * Check and diagnose cry configuration and setup.
5
+ */
6
+ export declare function doctor(): Promise<void>;
7
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA4BH,wBAAsB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CA6L5C"}
@@ -0,0 +1,198 @@
1
+ /**
2
+ * cry doctor command
3
+ *
4
+ * Check and diagnose cry configuration and setup.
5
+ */
6
+ import { existsSync } from 'node:fs';
7
+ import path from 'node:path';
8
+ import { isGitRepo, getRepoRoot, isTracked, isIgnored, commandExists, } from '../lib/git.js';
9
+ import { CONFIG_FILE, LOCAL_CONFIG_FILE, configExists, getMergedConfig, } from '../lib/config.js';
10
+ import { expandIncludePatterns, checkFileSafety } from '../lib/secrets.js';
11
+ import * as out from '../lib/output.js';
12
+ export async function doctor() {
13
+ // Check if we're in a git repo
14
+ if (!isGitRepo()) {
15
+ out.error('Not a git repository. Run this command from within a git repo.');
16
+ process.exit(1);
17
+ }
18
+ const repoRoot = getRepoRoot();
19
+ const checks = [];
20
+ out.header('cry Doctor');
21
+ out.log('Checking your cry configuration...');
22
+ out.newline();
23
+ // Check 1: Config file exists
24
+ if (configExists(repoRoot)) {
25
+ checks.push({
26
+ name: 'Config file',
27
+ status: 'pass',
28
+ message: `${CONFIG_FILE} exists`,
29
+ });
30
+ }
31
+ else {
32
+ checks.push({
33
+ name: 'Config file',
34
+ status: 'warn',
35
+ message: `${CONFIG_FILE} not found. Run 'cry init' to create one.`,
36
+ });
37
+ }
38
+ // Check 2: Local config is gitignored
39
+ const localConfigPath = path.join(repoRoot, LOCAL_CONFIG_FILE);
40
+ if (existsSync(localConfigPath)) {
41
+ if (isIgnored(LOCAL_CONFIG_FILE, repoRoot)) {
42
+ checks.push({
43
+ name: 'Local config ignored',
44
+ status: 'pass',
45
+ message: `${LOCAL_CONFIG_FILE} is properly gitignored`,
46
+ });
47
+ }
48
+ else if (isTracked(LOCAL_CONFIG_FILE, repoRoot)) {
49
+ checks.push({
50
+ name: 'Local config ignored',
51
+ status: 'fail',
52
+ message: `${LOCAL_CONFIG_FILE} is TRACKED by git! Remove it from tracking.`,
53
+ });
54
+ }
55
+ else {
56
+ checks.push({
57
+ name: 'Local config ignored',
58
+ status: 'warn',
59
+ message: `${LOCAL_CONFIG_FILE} exists but is not in .gitignore`,
60
+ });
61
+ }
62
+ }
63
+ else {
64
+ checks.push({
65
+ name: 'Local config',
66
+ status: 'pass',
67
+ message: `${LOCAL_CONFIG_FILE} not present (optional)`,
68
+ });
69
+ }
70
+ // Check 3: .worktrees directory is gitignored
71
+ const worktreesDir = '.worktrees';
72
+ const worktreesDirPath = path.join(repoRoot, worktreesDir);
73
+ if (existsSync(worktreesDirPath)) {
74
+ if (isIgnored(worktreesDir, repoRoot) || isIgnored(worktreesDir + '/', repoRoot)) {
75
+ checks.push({
76
+ name: 'Worktrees dir ignored',
77
+ status: 'pass',
78
+ message: `${worktreesDir}/ is properly gitignored`,
79
+ });
80
+ }
81
+ else {
82
+ checks.push({
83
+ name: 'Worktrees dir ignored',
84
+ status: 'fail',
85
+ message: `${worktreesDir}/ is NOT gitignored! Add it to .gitignore.`,
86
+ });
87
+ }
88
+ }
89
+ else {
90
+ if (isIgnored(worktreesDir, repoRoot) || isIgnored(worktreesDir + '/', repoRoot)) {
91
+ checks.push({
92
+ name: 'Worktrees dir ignored',
93
+ status: 'pass',
94
+ message: `${worktreesDir}/ will be gitignored when created`,
95
+ });
96
+ }
97
+ else {
98
+ checks.push({
99
+ name: 'Worktrees dir ignored',
100
+ status: 'warn',
101
+ message: `${worktreesDir}/ not in .gitignore (add it before spawning)`,
102
+ });
103
+ }
104
+ }
105
+ // Check 4: Include files are safe
106
+ if (configExists(repoRoot)) {
107
+ const config = getMergedConfig(repoRoot);
108
+ const files = await expandIncludePatterns(config.include, repoRoot);
109
+ let allSafe = true;
110
+ const problems = [];
111
+ for (const file of files) {
112
+ const result = checkFileSafety(file, repoRoot);
113
+ if (!result.safe && result.exists) {
114
+ allSafe = false;
115
+ problems.push(`${file}: ${result.reason}`);
116
+ }
117
+ }
118
+ if (files.length === 0) {
119
+ checks.push({
120
+ name: 'Include patterns',
121
+ status: 'pass',
122
+ message: 'No files matched include patterns (this is fine)',
123
+ });
124
+ }
125
+ else if (allSafe) {
126
+ checks.push({
127
+ name: 'Include files safety',
128
+ status: 'pass',
129
+ message: `All ${files.length} matched file(s) are safely gitignored`,
130
+ });
131
+ }
132
+ else {
133
+ checks.push({
134
+ name: 'Include files safety',
135
+ status: 'fail',
136
+ message: `Some include files are NOT safe:\n ${problems.join('\n ')}`,
137
+ });
138
+ }
139
+ }
140
+ // Check 5: Agent command exists
141
+ if (configExists(repoRoot)) {
142
+ const config = getMergedConfig(repoRoot);
143
+ const agentCmd = config.agentCommand;
144
+ if (commandExists(agentCmd)) {
145
+ checks.push({
146
+ name: 'Agent command',
147
+ status: 'pass',
148
+ message: `'${agentCmd}' is available`,
149
+ });
150
+ }
151
+ else {
152
+ checks.push({
153
+ name: 'Agent command',
154
+ status: 'warn',
155
+ message: `'${agentCmd}' not found (optional, but --agent won't work)`,
156
+ });
157
+ }
158
+ }
159
+ // Print results
160
+ let hasFailures = false;
161
+ let hasWarnings = false;
162
+ for (const check of checks) {
163
+ let icon;
164
+ let colorFn;
165
+ switch (check.status) {
166
+ case 'pass':
167
+ icon = '✓';
168
+ colorFn = out.fmt.green;
169
+ break;
170
+ case 'warn':
171
+ icon = '⚠';
172
+ colorFn = out.fmt.yellow;
173
+ hasWarnings = true;
174
+ break;
175
+ case 'fail':
176
+ icon = '✗';
177
+ colorFn = out.fmt.red;
178
+ hasFailures = true;
179
+ break;
180
+ }
181
+ out.log(`${colorFn(icon)} ${out.fmt.bold(check.name)}`);
182
+ out.log(` ${check.message}`);
183
+ out.newline();
184
+ }
185
+ // Summary
186
+ out.log('─'.repeat(50));
187
+ if (hasFailures) {
188
+ out.error('Some checks failed. Please fix the issues above.');
189
+ process.exit(1);
190
+ }
191
+ else if (hasWarnings) {
192
+ out.warn('Some warnings detected. Consider addressing them.');
193
+ }
194
+ else {
195
+ out.success('All checks passed!');
196
+ }
197
+ }
198
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * cry init command
3
+ *
4
+ * Create or update repo-level config files for cry.
5
+ */
6
+ interface InitOptions {
7
+ force?: boolean;
8
+ }
9
+ export declare function init(options: InitOptions): Promise<void>;
10
+ export {};
11
+ //# sourceMappingURL=init.d.ts.map