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
package/.vwt.json
ADDED
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 @@
|
|
|
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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"}
|