@wipcomputer/wip-ai-devops-toolbox 1.9.44 → 1.9.46
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/CHANGELOG.md +69 -0
- package/DEV-GUIDE-GENERAL-PUBLIC.md +29 -3
- package/SKILL.md +1 -1
- package/_trash/RELEASE-NOTES-v1-9-41.md +28 -0
- package/_trash/RELEASE-NOTES-v1-9-45.md +25 -0
- package/_trash/RELEASE-NOTES-v1-9-46.md +38 -0
- package/package.json +1 -1
- package/tools/deploy-public/package.json +1 -1
- package/tools/post-merge-rename/package.json +1 -1
- package/tools/wip-branch-guard/guard.mjs +56 -5
- package/tools/wip-branch-guard/package.json +1 -1
- package/tools/wip-file-guard/guard.mjs +28 -3
- package/tools/wip-file-guard/package.json +1 -1
- package/tools/wip-license-guard/package.json +1 -1
- package/tools/wip-license-hook/package.json +1 -1
- package/tools/wip-readme-format/package.json +1 -1
- package/tools/wip-release/core.mjs +33 -0
- package/tools/wip-release/package.json +1 -1
- package/tools/wip-repo-init/package.json +1 -1
- package/tools/wip-repo-permissions-hook/package.json +1 -1
- package/tools/wip-repos/package.json +1 -1
- package/tools/wip-universal-installer/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -31,6 +31,75 @@
|
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
|
|
34
|
+
|
|
35
|
+
## 1.9.46 (2026-03-18)
|
|
36
|
+
|
|
37
|
+
# Release Notes: wip-ai-devops-toolbox v1.9.46
|
|
38
|
+
|
|
39
|
+
**Centralized worktree management: guard rule, wip-release prune, Dev Guide convention.**
|
|
40
|
+
|
|
41
|
+
## What changed
|
|
42
|
+
|
|
43
|
+
### Guard: worktree path warning (#212)
|
|
44
|
+
Branch guard now warns when `git worktree add` creates a worktree outside `_worktrees/`. Shows the convention and suggests `ldm worktree add`. Warning only, not a hard block.
|
|
45
|
+
|
|
46
|
+
### wip-release: worktree prune (#212)
|
|
47
|
+
New step 12 in the release pipeline. After branch cleanup, prunes stale worktrees from `_worktrees/` whose branches are merged into main. Automatic cleanup after every release.
|
|
48
|
+
|
|
49
|
+
### Dev Guide: _worktrees/ convention (#212)
|
|
50
|
+
Documents the centralized worktree convention:
|
|
51
|
+
- All worktrees go in `_worktrees/<repo-name>--<branch-suffix>/`
|
|
52
|
+
- Use `ldm worktree add` (auto-detects repo, creates in the right place)
|
|
53
|
+
- Guard warns about worktrees outside the convention
|
|
54
|
+
- `wip-release` auto-prunes merged worktrees
|
|
55
|
+
|
|
56
|
+
## Why
|
|
57
|
+
|
|
58
|
+
Worktrees created as repo siblings confused iCloud sync, looked like real repos in directory listings, and were never cleaned up. This session alone created 10+ stale worktrees. The convention keeps them organized and the release pipeline cleans them automatically.
|
|
59
|
+
|
|
60
|
+
## Issues closed
|
|
61
|
+
|
|
62
|
+
- #212
|
|
63
|
+
- #213
|
|
64
|
+
|
|
65
|
+
## How to verify
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
# Guard warning:
|
|
69
|
+
cd /path/to/repo
|
|
70
|
+
git worktree add ../my-worktree -b test # should warn about _worktrees/
|
|
71
|
+
|
|
72
|
+
# Correct path:
|
|
73
|
+
ldm worktree add cc-mini/test # creates _worktrees/<repo>--cc-mini--test/
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## 1.9.45 (2026-03-18)
|
|
77
|
+
|
|
78
|
+
# Release Notes: wip-ai-devops-toolbox v1.9.45
|
|
79
|
+
|
|
80
|
+
**Guard now teaches the workflow instead of just blocking.**
|
|
81
|
+
|
|
82
|
+
## What changed
|
|
83
|
+
|
|
84
|
+
- **Branch guard error messages overhauled (#213).** When the guard blocks a write on main, it now shows the full 8-step process: worktree, branch, commit, push, PR, merge, wip-release, deploy-public. Includes the lesson that release notes go on the feature branch, not as a separate PR.
|
|
85
|
+
- **Separate error for "on branch but not in worktree."** Tells the agent to go back to main and create a worktree properly.
|
|
86
|
+
- **CLAUDE.md added to shared state allowlist.** Was patched in the deployed guard but missing from source. Now in sync.
|
|
87
|
+
|
|
88
|
+
## Why
|
|
89
|
+
|
|
90
|
+
Agents kept getting blocked by the guard and then trying workarounds instead of following the process. The error message said "Use a worktree" but didn't explain the full workflow. Today's session hit this 5+ times. The guard works. The gap was agent knowledge.
|
|
91
|
+
|
|
92
|
+
## Issues closed
|
|
93
|
+
|
|
94
|
+
- #213
|
|
95
|
+
- #256
|
|
96
|
+
|
|
97
|
+
## How to verify
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
# In any repo on main, try to edit a file. The error should show the full workflow.
|
|
101
|
+
# In any repo on a branch (not worktree), try to edit. Should show worktree instructions.
|
|
102
|
+
```
|
|
34
103
|
|
|
35
104
|
## 1.9.44 (2026-03-17)
|
|
36
105
|
|
|
@@ -524,16 +524,42 @@ gh api "repos/<org>/<repo>/branches/main/protection" -X PUT \
|
|
|
524
524
|
|
|
525
525
|
The main working tree stays on `main` and is read-only in practice. All development happens in git worktrees. This keeps the primary clone clean, prevents accidental commits to main, and enables parallel work within a single agent.
|
|
526
526
|
|
|
527
|
+
### Worktree Location Convention
|
|
528
|
+
|
|
529
|
+
**All worktrees go in `_worktrees/` as a sibling to the repos directory.** Never create worktrees as siblings to repos directly. They look like real repos, confuse iCloud sync, and are hard to find/clean.
|
|
530
|
+
|
|
531
|
+
**Convention:** `_worktrees/<repo-name>--<branch-suffix>/`
|
|
532
|
+
|
|
533
|
+
```
|
|
534
|
+
repos/
|
|
535
|
+
ldm-os/
|
|
536
|
+
components/
|
|
537
|
+
memory-crystal-private/ <- real repo
|
|
538
|
+
devops/
|
|
539
|
+
wip-ai-devops-toolbox-private/ <- real repo
|
|
540
|
+
_worktrees/
|
|
541
|
+
memory-crystal-private--cc-mini--fix-search/ <- worktree
|
|
542
|
+
wip-ai-devops-toolbox-private--cc-mini--guard/ <- worktree
|
|
543
|
+
```
|
|
544
|
+
|
|
527
545
|
### Starting a Worktree
|
|
528
546
|
|
|
529
|
-
|
|
547
|
+
**Preferred:** Use the `ldm worktree` command:
|
|
548
|
+
```bash
|
|
549
|
+
ldm worktree add cc-mini/fix-bug # auto-detects repo, creates in _worktrees/
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
**From Claude Code:**
|
|
530
553
|
```bash
|
|
531
554
|
claude --worktree <name>
|
|
532
555
|
```
|
|
533
556
|
|
|
534
|
-
|
|
557
|
+
**Manual:**
|
|
558
|
+
```bash
|
|
559
|
+
git worktree add ../_worktrees/<repo>--<branch> -b <branch>
|
|
560
|
+
```
|
|
535
561
|
|
|
536
|
-
|
|
562
|
+
The branch guard warns if you create worktrees outside `_worktrees/` or `.claude/worktrees/`.
|
|
537
563
|
|
|
538
564
|
### Branch Naming
|
|
539
565
|
|
package/SKILL.md
CHANGED
|
@@ -5,7 +5,7 @@ license: MIT
|
|
|
5
5
|
interface: [cli, module, mcp, skill, hook, plugin]
|
|
6
6
|
metadata:
|
|
7
7
|
display-name: "WIP AI DevOps Toolbox"
|
|
8
|
-
version: "1.9.
|
|
8
|
+
version: "1.9.46"
|
|
9
9
|
homepage: "https://github.com/wipcomputer/wip-ai-devops-toolbox"
|
|
10
10
|
author: "Parker Todd Brooks"
|
|
11
11
|
category: dev-tools
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Release Notes: wip-ai-devops-toolbox v1.9.41
|
|
2
|
+
|
|
3
|
+
**One-line summary of what this release does**
|
|
4
|
+
|
|
5
|
+
## What changed
|
|
6
|
+
|
|
7
|
+
Describe the changes. Not a commit list. Explain:
|
|
8
|
+
- What was built or fixed
|
|
9
|
+
- Why it matters
|
|
10
|
+
- What the user should know
|
|
11
|
+
|
|
12
|
+
## Why
|
|
13
|
+
|
|
14
|
+
What problem does this solve? What was broken or missing?
|
|
15
|
+
|
|
16
|
+
## Issues closed
|
|
17
|
+
|
|
18
|
+
- #251
|
|
19
|
+
- #117
|
|
20
|
+
- #128
|
|
21
|
+
- #250
|
|
22
|
+
- #73
|
|
23
|
+
|
|
24
|
+
## How to verify
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# Commands to test the changes
|
|
28
|
+
```
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Release Notes: wip-ai-devops-toolbox v1.9.45
|
|
2
|
+
|
|
3
|
+
**Guard now teaches the workflow instead of just blocking.**
|
|
4
|
+
|
|
5
|
+
## What changed
|
|
6
|
+
|
|
7
|
+
- **Branch guard error messages overhauled (#213).** When the guard blocks a write on main, it now shows the full 8-step process: worktree, branch, commit, push, PR, merge, wip-release, deploy-public. Includes the lesson that release notes go on the feature branch, not as a separate PR.
|
|
8
|
+
- **Separate error for "on branch but not in worktree."** Tells the agent to go back to main and create a worktree properly.
|
|
9
|
+
- **CLAUDE.md added to shared state allowlist.** Was patched in the deployed guard but missing from source. Now in sync.
|
|
10
|
+
|
|
11
|
+
## Why
|
|
12
|
+
|
|
13
|
+
Agents kept getting blocked by the guard and then trying workarounds instead of following the process. The error message said "Use a worktree" but didn't explain the full workflow. Today's session hit this 5+ times. The guard works. The gap was agent knowledge.
|
|
14
|
+
|
|
15
|
+
## Issues closed
|
|
16
|
+
|
|
17
|
+
- #213
|
|
18
|
+
- #256
|
|
19
|
+
|
|
20
|
+
## How to verify
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
# In any repo on main, try to edit a file. The error should show the full workflow.
|
|
24
|
+
# In any repo on a branch (not worktree), try to edit. Should show worktree instructions.
|
|
25
|
+
```
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Release Notes: wip-ai-devops-toolbox v1.9.46
|
|
2
|
+
|
|
3
|
+
**Centralized worktree management: guard rule, wip-release prune, Dev Guide convention.**
|
|
4
|
+
|
|
5
|
+
## What changed
|
|
6
|
+
|
|
7
|
+
### Guard: worktree path warning (#212)
|
|
8
|
+
Branch guard now warns when `git worktree add` creates a worktree outside `_worktrees/`. Shows the convention and suggests `ldm worktree add`. Warning only, not a hard block.
|
|
9
|
+
|
|
10
|
+
### wip-release: worktree prune (#212)
|
|
11
|
+
New step 12 in the release pipeline. After branch cleanup, prunes stale worktrees from `_worktrees/` whose branches are merged into main. Automatic cleanup after every release.
|
|
12
|
+
|
|
13
|
+
### Dev Guide: _worktrees/ convention (#212)
|
|
14
|
+
Documents the centralized worktree convention:
|
|
15
|
+
- All worktrees go in `_worktrees/<repo-name>--<branch-suffix>/`
|
|
16
|
+
- Use `ldm worktree add` (auto-detects repo, creates in the right place)
|
|
17
|
+
- Guard warns about worktrees outside the convention
|
|
18
|
+
- `wip-release` auto-prunes merged worktrees
|
|
19
|
+
|
|
20
|
+
## Why
|
|
21
|
+
|
|
22
|
+
Worktrees created as repo siblings confused iCloud sync, looked like real repos in directory listings, and were never cleaned up. This session alone created 10+ stale worktrees. The convention keeps them organized and the release pipeline cleans them automatically.
|
|
23
|
+
|
|
24
|
+
## Issues closed
|
|
25
|
+
|
|
26
|
+
- #212
|
|
27
|
+
- #213
|
|
28
|
+
|
|
29
|
+
## How to verify
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# Guard warning:
|
|
33
|
+
cd /path/to/repo
|
|
34
|
+
git worktree add ../my-worktree -b test # should warn about _worktrees/
|
|
35
|
+
|
|
36
|
+
# Correct path:
|
|
37
|
+
ldm worktree add cc-mini/test # creates _worktrees/<repo>--cc-mini--test/
|
|
38
|
+
```
|
package/package.json
CHANGED
|
@@ -91,6 +91,28 @@ const ALLOWED_BASH_PATTERNS = [
|
|
|
91
91
|
/\bclaude\s+mcp\b/, // MCP registration, not repo files
|
|
92
92
|
];
|
|
93
93
|
|
|
94
|
+
// Workflow steps for error messages (#213)
|
|
95
|
+
const WORKFLOW_ON_MAIN = `
|
|
96
|
+
The process: worktree -> branch -> commit -> push -> PR -> merge -> wip-release -> deploy-public.
|
|
97
|
+
|
|
98
|
+
Step 1: git worktree add ../my-worktree -b cc-mini/your-feature
|
|
99
|
+
Step 2: Edit files in the worktree
|
|
100
|
+
Step 3: git add + git commit (with co-authors)
|
|
101
|
+
Step 4: git push -u origin cc-mini/your-feature
|
|
102
|
+
Step 5: gh pr create, then gh pr merge --merge --delete-branch
|
|
103
|
+
Step 6: Back in main repo: git pull
|
|
104
|
+
Step 7: wip-release patch (with RELEASE-NOTES on the branch, not after)
|
|
105
|
+
Step 8: deploy-public.sh to sync public repo
|
|
106
|
+
|
|
107
|
+
Release notes go ON the feature branch, committed with the code. Not as a separate PR.`.trim();
|
|
108
|
+
|
|
109
|
+
const WORKFLOW_NOT_WORKTREE = `
|
|
110
|
+
You're on a branch but not in a worktree. Use a worktree so the main working tree stays clean.
|
|
111
|
+
|
|
112
|
+
Step 1: git checkout main (go back to main first)
|
|
113
|
+
Step 2: git worktree add ../my-worktree -b your-branch-name
|
|
114
|
+
Step 3: Edit files in the worktree directory`.trim();
|
|
115
|
+
|
|
94
116
|
function deny(reason) {
|
|
95
117
|
const output = {
|
|
96
118
|
hookSpecificOutput: {
|
|
@@ -203,6 +225,21 @@ async function main() {
|
|
|
203
225
|
}
|
|
204
226
|
} catch {}
|
|
205
227
|
}
|
|
228
|
+
|
|
229
|
+
// Warn when creating worktrees outside _worktrees/ (#212)
|
|
230
|
+
const wtMatch = cmd.match(/\bgit\s+worktree\s+add\s+["']?([^\s"']+)/);
|
|
231
|
+
if (wtMatch) {
|
|
232
|
+
const wtPath = wtMatch[1];
|
|
233
|
+
if (!wtPath.includes('_worktrees') && !wtPath.includes('.claude/worktrees')) {
|
|
234
|
+
deny(`WARNING: Creating worktree outside _worktrees/. Use: ldm worktree add <branch>
|
|
235
|
+
|
|
236
|
+
The convention is _worktrees/<repo>--<branch>/ so worktrees don't mix with real repos.
|
|
237
|
+
Manual equivalent: git worktree add ../_worktrees/<repo>--<branch> -b <branch>
|
|
238
|
+
|
|
239
|
+
This is a warning, not a block. If you need to create it here, retry.`);
|
|
240
|
+
process.exit(0);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
206
243
|
}
|
|
207
244
|
|
|
208
245
|
// Determine which repo to check.
|
|
@@ -265,17 +302,31 @@ async function main() {
|
|
|
265
302
|
BLOCKED_BASH_PATTERNS.some(p => p.test(command)) &&
|
|
266
303
|
!ALLOWED_BASH_PATTERNS.some(p => p.test(command)));
|
|
267
304
|
if (isWriteOp) {
|
|
268
|
-
deny(`BLOCKED: On branch "${branch}" but not in a worktree
|
|
305
|
+
deny(`BLOCKED: On branch "${branch}" but not in a worktree.\n\n${WORKFLOW_NOT_WORKTREE}`);
|
|
269
306
|
process.exit(0);
|
|
270
307
|
}
|
|
271
308
|
process.exit(0);
|
|
272
309
|
}
|
|
273
310
|
|
|
274
|
-
// We're on main. Check if this is a
|
|
311
|
+
// We're on main. Check if this is a shared state file (always writable).
|
|
312
|
+
// These are not code. They're shared context between agents.
|
|
313
|
+
const SHARED_STATE_PATTERNS = [
|
|
314
|
+
/CLAUDE\.md$/,
|
|
315
|
+
/workspace\/SHARED-CONTEXT\.md$/,
|
|
316
|
+
/workspace\/memory\/.*\.md$/,
|
|
317
|
+
/\.ldm\/agents\/.*\/memory\/daily\/.*\.md$/,
|
|
318
|
+
/\.ldm\/memory\/shared-log\.jsonl$/,
|
|
319
|
+
/\.ldm\/memory\/daily\/.*\.md$/,
|
|
320
|
+
/\.ldm\/logs\//,
|
|
321
|
+
];
|
|
322
|
+
|
|
323
|
+
if (filePath && SHARED_STATE_PATTERNS.some(p => p.test(filePath))) {
|
|
324
|
+
process.exit(0); // Shared state, always allow
|
|
325
|
+
}
|
|
275
326
|
|
|
276
327
|
// Block Write/Edit tools entirely on main
|
|
277
328
|
if (WRITE_TOOLS.has(toolName)) {
|
|
278
|
-
deny(`BLOCKED: Cannot ${toolName} while on main branch
|
|
329
|
+
deny(`BLOCKED: Cannot ${toolName} while on main branch.\n\n${WORKFLOW_ON_MAIN}`);
|
|
279
330
|
process.exit(0);
|
|
280
331
|
}
|
|
281
332
|
|
|
@@ -297,7 +348,7 @@ async function main() {
|
|
|
297
348
|
if (ap.test(command)) { isAllowed = true; break; }
|
|
298
349
|
}
|
|
299
350
|
if (!isAllowed) {
|
|
300
|
-
deny(`BLOCKED: Cannot run "${command.substring(0, 60)}..." on main branch
|
|
351
|
+
deny(`BLOCKED: Cannot run "${command.substring(0, 60)}..." on main branch.\n\n${WORKFLOW_ON_MAIN}`);
|
|
301
352
|
process.exit(0);
|
|
302
353
|
}
|
|
303
354
|
}
|
|
@@ -312,7 +363,7 @@ async function main() {
|
|
|
312
363
|
if (ap.test(command)) { isAllowed = true; break; }
|
|
313
364
|
}
|
|
314
365
|
if (!isAllowed) {
|
|
315
|
-
deny(`BLOCKED: Cannot run file-modifying command on main branch
|
|
366
|
+
deny(`BLOCKED: Cannot run file-modifying command on main branch.\n\n${WORKFLOW_ON_MAIN}`);
|
|
316
367
|
process.exit(0);
|
|
317
368
|
}
|
|
318
369
|
}
|
|
@@ -36,6 +36,26 @@ export const PROTECTED_PATTERNS = [
|
|
|
36
36
|
/daily.*log/i,
|
|
37
37
|
];
|
|
38
38
|
|
|
39
|
+
// Shared state files: protected from Write but allow larger Edit replacements.
|
|
40
|
+
// These are actively edited by both agents every session.
|
|
41
|
+
const SHARED_STATE_FILES = new Set([
|
|
42
|
+
'SHARED-CONTEXT.md',
|
|
43
|
+
]);
|
|
44
|
+
|
|
45
|
+
// Daily logs and workspace memory: allow creation and larger edits
|
|
46
|
+
const SHARED_STATE_PATHS = [
|
|
47
|
+
/workspace\/memory\/\d{4}-\d{2}-\d{2}\.md$/,
|
|
48
|
+
/\.ldm\/agents\/.*\/memory\/daily\/.*\.md$/,
|
|
49
|
+
/\.ldm\/memory\/daily\/.*\.md$/,
|
|
50
|
+
/\.ldm\/memory\/shared-log\.jsonl$/,
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
function isSharedState(filePath) {
|
|
54
|
+
const name = basename(filePath);
|
|
55
|
+
if (SHARED_STATE_FILES.has(name)) return true;
|
|
56
|
+
return SHARED_STATE_PATHS.some(p => p.test(filePath));
|
|
57
|
+
}
|
|
58
|
+
|
|
39
59
|
function isProtected(filePath) {
|
|
40
60
|
const name = basename(filePath);
|
|
41
61
|
if (PROTECTED.has(name)) return name;
|
|
@@ -116,14 +136,19 @@ async function main() {
|
|
|
116
136
|
const newLines = countLines(newString);
|
|
117
137
|
const removed = oldLines - newLines;
|
|
118
138
|
|
|
119
|
-
//
|
|
120
|
-
|
|
139
|
+
// Shared state files get higher limits (updated every session by both agents)
|
|
140
|
+
const isShared = isSharedState(filePath);
|
|
141
|
+
const maxRemoval = isShared ? 20 : 2;
|
|
142
|
+
const maxReplace = isShared ? 30 : 4;
|
|
143
|
+
|
|
144
|
+
// Block net removal beyond limit
|
|
145
|
+
if (removed > maxRemoval) {
|
|
121
146
|
deny(`BLOCKED: You are removing ${removed} lines from ${match} (old: ${oldLines} lines, new: ${newLines} lines). Re-read the file and add content instead of replacing it.`);
|
|
122
147
|
process.exit(0);
|
|
123
148
|
}
|
|
124
149
|
|
|
125
150
|
// Block large replacements (swapping big chunks even if line count is similar)
|
|
126
|
-
if (oldLines >
|
|
151
|
+
if (oldLines > maxReplace && oldString !== newString) {
|
|
127
152
|
deny(`BLOCKED: You are replacing ${oldLines} lines in ${match}. Edit smaller sections or append new content instead of replacing existing content.`);
|
|
128
153
|
process.exit(0);
|
|
129
154
|
}
|
|
@@ -1579,6 +1579,39 @@ export async function release({ repoPath, level, notes, notesSource, dryRun, noP
|
|
|
1579
1579
|
console.log(` ! Branch prune skipped: ${e.message}`);
|
|
1580
1580
|
}
|
|
1581
1581
|
|
|
1582
|
+
// 12. Prune stale worktrees (#212)
|
|
1583
|
+
try {
|
|
1584
|
+
execSync('git worktree prune', { cwd: repoPath, stdio: 'pipe' });
|
|
1585
|
+
// Also check _worktrees/ for dirs whose branches are now merged
|
|
1586
|
+
const worktreesDir = join(dirname(repoPath), '_worktrees');
|
|
1587
|
+
if (existsSync(worktreesDir)) {
|
|
1588
|
+
const repoBase = basename(repoPath);
|
|
1589
|
+
const wtDirs = readdirSync(worktreesDir, { withFileTypes: true })
|
|
1590
|
+
.filter(d => d.isDirectory() && d.name.startsWith(repoBase + '--'));
|
|
1591
|
+
let wtPruned = 0;
|
|
1592
|
+
for (const d of wtDirs) {
|
|
1593
|
+
const wtPath = join(worktreesDir, d.name);
|
|
1594
|
+
try {
|
|
1595
|
+
// Check if branch is merged into main
|
|
1596
|
+
const branch = execSync('git branch --show-current', {
|
|
1597
|
+
cwd: wtPath, encoding: 'utf8', timeout: 3000
|
|
1598
|
+
}).trim();
|
|
1599
|
+
if (branch) {
|
|
1600
|
+
execSync(`git merge-base --is-ancestor "${branch}" main`, {
|
|
1601
|
+
cwd: repoPath, stdio: 'pipe', timeout: 5000
|
|
1602
|
+
});
|
|
1603
|
+
// Branch is merged. Remove worktree.
|
|
1604
|
+
execSync(`git worktree remove "${wtPath}"`, { cwd: repoPath, stdio: 'pipe' });
|
|
1605
|
+
wtPruned++;
|
|
1606
|
+
}
|
|
1607
|
+
} catch {} // Branch not merged or other issue, leave it
|
|
1608
|
+
}
|
|
1609
|
+
if (wtPruned > 0) {
|
|
1610
|
+
console.log(` ✓ Pruned ${wtPruned} merged worktree(s) from _worktrees/`);
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
} catch {}
|
|
1614
|
+
|
|
1582
1615
|
// Write release marker so branch guard blocks immediate install (#73)
|
|
1583
1616
|
try {
|
|
1584
1617
|
const markerDir = join(process.env.HOME || '', '.ldm', 'state');
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wipcomputer/universal-installer",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.46",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "The Universal Interface specification for agent-native software. Teaches your AI how to build repos with every interface: CLI, Module, MCP Server, OpenClaw Plugin, Skill, Claude Code Hook.",
|
|
6
6
|
"main": "detect.mjs",
|