lshed 0.7.2 → 0.8.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/CHANGELOG.md +45 -0
- package/README.md +83 -8
- package/dist/cli.js +307 -1807
- package/package.json +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,50 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.8.0 — 2026-09-04
|
|
4
|
+
|
|
5
|
+
Pick what a machine gets instead of writing a profile by hand.
|
|
6
|
+
|
|
7
|
+
- `lshed restore --pick` walks the shed one category at a time — packages, then skills, agents, commands, instructions, MCP servers, settings keys — and shows a checklist for each. Categories the shed has nothing in are skipped, so a shed with no packages never asks about packages. The choice is saved to `lshed.yaml` as a profile (named after the machine by default, or whatever you type) and then applied like any other `restore`. Saving is not optional: the next bare `lshed restore` reapplies the same choice, and `lshed sync` carries it to your other machines.
|
|
8
|
+
- `lshed restore <profile> --pick` starts with that profile's parts checked, so you can trim or extend an existing profile instead of starting from nothing. With no argument, the last applied profile is the starting point.
|
|
9
|
+
- On a machine with no applied profile, a bare `lshed restore --shed <dir>` in a terminal opens the picker instead of failing. In a pipe or a script it still asks for a profile name.
|
|
10
|
+
- `--dry-run` shows the plan and writes neither `lshed.yaml` nor the agent root. Naming an existing profile asks before overwriting it. Ctrl+C at any screen leaves everything as it was.
|
|
11
|
+
- Prompts come from `@clack/prompts`, bundled like the other dependencies.
|
|
12
|
+
|
|
13
|
+
## 0.7.6 — 2026-09-03
|
|
14
|
+
|
|
15
|
+
Agents organised in subdirectories were silently left out of the shed.
|
|
16
|
+
|
|
17
|
+
- Claude Code reads `~/.claude/agents/` recursively (a subagent's name comes from its frontmatter, not its path), but `init` and `add` only looked at top-level `.md` files. A machine with `agents/team/reviewer.md` restored elsewhere without it, and nothing said so. File-kind categories (`agents`, `commands`) are now scanned recursively; the id keeps the path (`team/reviewer`), so your folder layout survives the round trip and two files with the same name in different folders do not collide. Skills stay one level deep, which is what Claude Code reads at the user root.
|
|
18
|
+
- Keys accept the path form everywhere: `lshed save team/reviewer`, `lshed add agents/team/newbie`, `lshed remove agents/team/reviewer`.
|
|
19
|
+
- Verified against the real binary that the generated `CLAUDE.md` import (`@lshed/instructions/main.md`) resolves relative to the file, so instruction fragments load. That had only ever been checked by reading the generated text.
|
|
20
|
+
|
|
21
|
+
## 0.7.5 — 2026-09-03
|
|
22
|
+
|
|
23
|
+
- `init` and `add` now list what they find in a fixed order. `fs.readdir` returns entries in filesystem order, which differs between machines, so two people running `init` on the same harness got manifests whose component lists were ordered differently. `lshed.yaml` is a file you commit, so that showed up as noise in diffs.
|
|
24
|
+
- The path-comparison regression test compared a resolved path against an unresolved one and failed on macOS and Windows for the wrong reason. It now compares resolved to resolved, the way the code it guards does.
|
|
25
|
+
|
|
26
|
+
0.7.4 fixed the three real bugs the first macOS and Windows CI run found; this release fixes the test that came with it.
|
|
27
|
+
|
|
28
|
+
## 0.7.4 — 2026-09-03
|
|
29
|
+
|
|
30
|
+
The first CI run on real macOS and Windows machines found three bugs. All of them were path comparisons that only hold on Linux.
|
|
31
|
+
|
|
32
|
+
- A stub whose symlink points into a package was not recognised as generated on **macOS or Windows**. The target of a broken link cannot be resolved, so it was compared unresolved: on macOS `/var/folders/...` never matches the package's real `/private/var/folders/...`. Paths are now resolved as far as they exist before being compared.
|
|
33
|
+
- The warning for a settings value pointing inside a package never fired on **Windows**, because it matched the raw path against JSON text where backslashes are escaped. It now walks the values and compares them as paths.
|
|
34
|
+
- Path comparison is one helper that strips the Windows `\\?\` prefix and ignores case there.
|
|
35
|
+
- The test that runs a package's `install:` script is skipped on Windows; `./setup` is a shell script and `cmd.exe` cannot run it.
|
|
36
|
+
|
|
37
|
+
## 0.7.3 — 2026-09-03
|
|
38
|
+
|
|
39
|
+
You no longer need Node to run lshed.
|
|
40
|
+
|
|
41
|
+
- **Standalone binaries** for Windows x64, macOS (arm64/x64) and Linux (x64/arm64), attached to every tagged release. They carry their own runtime (~60-85 MB) and need nothing installed. `npm run binaries` builds all five from one machine.
|
|
42
|
+
- **The npm package is self-contained.** `commander`, `yaml` and `zod` are bundled into `dist/cli.js` (627 KB) instead of being installed alongside it; `zod` alone was 7.9 MB. `npm install -g lshed` now downloads one file.
|
|
43
|
+
- The version is baked in at build time, so the binaries do not look for a `package.json` that is not there.
|
|
44
|
+
- The smoke script accepts `LSHED_CLI=<path>` and is run against the compiled binary in CI, so the binaries are tested, not just built.
|
|
45
|
+
|
|
46
|
+
The design assumed everyone using a coding agent already had Node, because Claude Code installs through npm. Claude Code also has a native installer, and that assumption cost a user their laptop.
|
|
47
|
+
|
|
3
48
|
## 0.7.2 — 2026-09-03
|
|
4
49
|
|
|
5
50
|
Joining a machine that already has a harness, found while preparing the Windows check.
|
package/README.md
CHANGED
|
@@ -11,25 +11,57 @@ The shed is a plain directory. Put it in a git repo, Dropbox, whatever. `lshed s
|
|
|
11
11
|
|
|
12
12
|
## Why
|
|
13
13
|
|
|
14
|
-
Every new laptop, server, container or WSL box means setting up `~/.claude` again.
|
|
14
|
+
Every new laptop, server, container or WSL box means setting up `~/.claude` again. The obvious fix is to put `~/.claude` itself in git, and for many people that is the right answer.
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
**When a `.gitignore` is enough.** You are one person, every machine gets the same setup, and everything in `~/.claude` is yours. Then this does the job and you should not install lshed:
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
cd ~/.claude && git init
|
|
20
|
+
printf 'projects/\ncache/\nsessions/\nshell-snapshots/\nhistory.jsonl\n*.bak*\n' > .gitignore
|
|
21
|
+
git add skills agents commands CLAUDE.md settings.json .gitignore && git commit -m init
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
No new concepts, no copy step: the directory you edit is the repository. Cloning it on the next machine is the whole restore.
|
|
25
|
+
|
|
26
|
+
**Where that stops working.** The repository above starts to hurt as soon as `~/.claude` is not just yours:
|
|
27
|
+
|
|
28
|
+
- **Toolkits you installed.** One cloned toolkit here is 1.6 GB and generated 53 alias skills next to the 4 you wrote. Raw git commits all of it, or you maintain the ignore list by hand.
|
|
29
|
+
- **Secrets inside one JSON file.** MCP servers and their tokens live in `~/.claude.json` together with unrelated state. File-level ignore cannot split them, so you either commit tokens or leave MCP out.
|
|
30
|
+
- **A machine that already has a setup.** `git clone` into a non-empty `~/.claude` is a merge you do by hand, and nothing tracks which files came from the repo and which were already there.
|
|
31
|
+
- **Different subsets per machine.** A headless server wants no browser toolkit and no MCP. Branches or templates can fake this, but nothing removes the parts you no longer want when you switch.
|
|
32
|
+
- **Choosing on the machine itself.** `git clone` is all or nothing. On a new box you want to look at what the shed has, category by category, and tick what this machine needs.
|
|
33
|
+
|
|
34
|
+
lshed exists for those five cases. It keeps the shed as a plain directory in git, and adds three ideas on top:
|
|
17
35
|
|
|
18
36
|
| Idea | What it gives you |
|
|
19
37
|
|---|---|
|
|
20
|
-
| **Components** | every skill / agent / command / instruction fragment / MCP server / settings key is one named part
|
|
21
|
-
| **Profiles** | named recipes — `research`, `work`, `minimal` — that pick a subset of parts |
|
|
22
|
-
| **Managed set** | lshed remembers what it placed, so switching profiles removes only its own files and never touches yours |
|
|
38
|
+
| **Components** | every skill / agent / command / instruction fragment / MCP server / settings key is one named part; toolkits you installed are recorded as a source and version, not copied |
|
|
39
|
+
| **Profiles** | named recipes — `research`, `work`, `minimal` — that pick a subset of parts; write them in `lshed.yaml`, or let `restore --pick` build one from a checklist |
|
|
40
|
+
| **Managed set** | lshed remembers what it placed, so switching profiles or restoring onto an existing machine removes only its own files and never touches yours |
|
|
41
|
+
|
|
42
|
+
The trade: you edit in `~/.claude` and run `lshed save` to copy changes into the shed, and lshed has to know Claude Code's layout, which the plain repository does not. If none of the five cases applies to you, the `.gitignore` wins.
|
|
23
43
|
|
|
24
44
|
Currently supports **Claude Code** (`~/.claude`). Other agents plug in through an adapter.
|
|
25
45
|
|
|
26
46
|
## Install
|
|
27
47
|
|
|
48
|
+
With Node 20 or newer:
|
|
49
|
+
|
|
28
50
|
```
|
|
29
|
-
npm install -g lshed
|
|
51
|
+
npm install -g lshed # or run it once: npx lshed status
|
|
30
52
|
```
|
|
31
53
|
|
|
32
|
-
Node
|
|
54
|
+
Without Node, download a standalone binary from the [latest release](https://github.com/LeeSongHeon-LSH/lshed/releases/latest) and put it on your PATH. It carries its own runtime, so it is ~80 MB.
|
|
55
|
+
|
|
56
|
+
| Platform | File |
|
|
57
|
+
|---|---|
|
|
58
|
+
| Windows x64 | `lshed-windows-x64.exe` → rename to `lshed.exe` |
|
|
59
|
+
| macOS Apple Silicon / Intel | `lshed-darwin-arm64` / `lshed-darwin-x64` |
|
|
60
|
+
| Linux x64 / arm64 | `lshed-linux-x64` / `lshed-linux-arm64` |
|
|
61
|
+
|
|
62
|
+
On macOS and Linux, `chmod +x` it first. The binaries are unsigned, so macOS warns on first run.
|
|
63
|
+
|
|
64
|
+
Either way you also need `git` on the PATH for packages and `sync`, and `claude` if your shed lists plugins.
|
|
33
65
|
|
|
34
66
|
## Quick start
|
|
35
67
|
|
|
@@ -44,6 +76,7 @@ lshed sync # commit + push
|
|
|
44
76
|
# 3. On any other machine
|
|
45
77
|
git clone <your private repo> ~/lshed
|
|
46
78
|
lshed restore research --shed ~/lshed # --shed only needed the first time
|
|
79
|
+
lshed restore --pick --shed ~/lshed # or tick what this machine gets, category by category
|
|
47
80
|
```
|
|
48
81
|
|
|
49
82
|
## How to use it
|
|
@@ -142,6 +175,46 @@ lshed restore default --shed ~/lshed
|
|
|
142
175
|
|
|
143
176
|
Two things need you afterwards. Package `install:` commands are shell commands from a repository you cloned, so `restore` shows them and stops; run them yourself or rerun with `--yes`. MCP servers reference secrets as `${VAR}`; export the variables in your shell and Claude Code fills them in. From then on `lshed restore` with no arguments reapplies the last profile, and the shed location is remembered.
|
|
144
177
|
|
|
178
|
+
### Picking instead of naming a profile
|
|
179
|
+
|
|
180
|
+
You do not have to know the profile names, or edit `lshed.yaml`, to set up a machine. `restore --pick` walks the shed one category at a time and asks what this machine should get:
|
|
181
|
+
|
|
182
|
+
```
|
|
183
|
+
$ lshed restore --pick --shed ~/lshed
|
|
184
|
+
창고: /home/me/lshed (packages (3), skills (4), instructions (1), mcp (1))
|
|
185
|
+
◆ packages (3) — 이 기기에 둘 것을 고르세요 (space 선택, a 전체, enter 다음)
|
|
186
|
+
│ ◼ gstack github:garrytan/gstack@main
|
|
187
|
+
│ ◻ claude-plugins-official claude-marketplace:anthropics/claude-plugins-official
|
|
188
|
+
│ ◻ exa claude-plugin:exa@claude-plugins-official
|
|
189
|
+
◆ skills (4) — 이 기기에 둘 것을 고르세요
|
|
190
|
+
│ ◼ add-drivers
|
|
191
|
+
│ ◼ domain-modeling
|
|
192
|
+
│ ◻ grilling
|
|
193
|
+
│ ◻ paper-review
|
|
194
|
+
◆ instructions (1)
|
|
195
|
+
│ ◼ main
|
|
196
|
+
◆ mcp (1)
|
|
197
|
+
│ ◻ notion
|
|
198
|
+
◆ 이 선택을 저장할 프로필 이름
|
|
199
|
+
│ lab-box
|
|
200
|
+
|
|
201
|
+
프로필 "lab-box" 을 lshed.yaml 에 저장했습니다. 다른 기기에서도 쓰려면 lshed sync 로 올리세요.
|
|
202
|
+
|
|
203
|
+
+ package gstack (clone https://github.com/garrytan/gstack.git @main → 253d1df)
|
|
204
|
+
+ skills/add-drivers
|
|
205
|
+
+ skills/domain-modeling
|
|
206
|
+
+ lshed/instructions/main.md
|
|
207
|
+
+ CLAUDE.md
|
|
208
|
+
|
|
209
|
+
프로필 "lab-box" 적용: 배치 4, 제거 0, 패키지 설치 1
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Categories the shed has nothing in (here `agents`, `commands`, `settings`) are skipped, not shown empty. The choice is always saved as a profile, named after the machine unless you type another name: that is what makes the next bare `lshed restore` reapply it, and what `lshed sync` carries to your other machines. If the shed already has a profile with that name, lshed asks before overwriting it.
|
|
213
|
+
|
|
214
|
+
`lshed restore default --pick` starts with `default`'s parts checked, so you can trim a profile for this machine instead of starting from nothing. With no argument the last applied profile is the starting point. `--dry-run` shows the plan and writes neither `lshed.yaml` nor `~/.claude`. Ctrl+C at any screen leaves everything untouched.
|
|
215
|
+
|
|
216
|
+
On a machine with no applied profile, a bare `lshed restore --shed ~/lshed` in a terminal opens the picker by itself. In a script or a pipe it asks for a profile name instead.
|
|
217
|
+
|
|
145
218
|
### Profiles
|
|
146
219
|
|
|
147
220
|
A profile is a list of ids per category. Add as many as you like to `lshed.yaml`:
|
|
@@ -337,7 +410,7 @@ $ lshed add
|
|
|
337
410
|
```
|
|
338
411
|
lshed init [--shed <dir>] [--profile <name>] [--exclude <id...>]
|
|
339
412
|
lshed add [keys...] [--all] put things that appeared since init into the shed
|
|
340
|
-
lshed restore [profile] [--dry-run] [--no-backup] [--yes]
|
|
413
|
+
lshed restore [profile] [--pick] [--dry-run] [--no-backup] [--yes]
|
|
341
414
|
lshed status applied profile, drift, packages, missing env, new things
|
|
342
415
|
lshed diff files (or JSON keys) that differ between local and shed
|
|
343
416
|
lshed save [ids...] copy local edits back into the shed
|
|
@@ -361,6 +434,8 @@ Global options: `--shed <dir>` (or `LSHED_HOME`; after the first restore lshed r
|
|
|
361
434
|
|
|
362
435
|
Anything it overwrites or removes is backed up first under `~/.claude/lshed/backups/<timestamp>/`, unless you pass `--no-backup`. Files lshed never placed are left alone. `--dry-run` prints the plan and writes nothing.
|
|
363
436
|
|
|
437
|
+
With `--pick`, a checklist per non-empty category comes first (packages, skills, agents, commands, instructions, MCP servers, settings keys). `[profile]` pre-checks that profile's parts. The result is written to `lshed.yaml` as a profile, and then steps 0–3 run for it.
|
|
438
|
+
|
|
364
439
|
### What `sync` does
|
|
365
440
|
|
|
366
441
|
1. Warns if `diff` shows local edits you have not saved.
|