lshed 0.1.0 → 0.3.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 +39 -0
- package/README.md +65 -6
- package/dist/cli.js +806 -162
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,44 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.0 — 2026-09-02
|
|
4
|
+
|
|
5
|
+
Claude Code plugins are packages now. On the machine this was built against, the five installed plugins were the only thing a fresh `restore` still left out, and two of them carry MCP servers.
|
|
6
|
+
|
|
7
|
+
- `init` records each user-scope plugin as `claude-plugin:<name>@<marketplace>` and each GitHub-backed marketplace as `claude-marketplace:<owner/repo>`. Project-scope plugins belong to their project and are skipped.
|
|
8
|
+
- `restore` adds missing marketplaces first, then installs missing plugins through `claude plugin install`. Both are the agent's own package manager, so they run without `--yes`; `--yes` is forwarded as `-y` to accept a marketplace-declared install command.
|
|
9
|
+
- Plugins cannot be pinned. `lshed.lock` records the version that actually got installed and `status` shows when it differs from what another machine had. `update` runs `claude plugin update`.
|
|
10
|
+
- Installers are an interface now. `github:`/`git:` live in core; an adapter contributes its own (`ClaudeCodeAdapter` provides the two above). Install order follows installer priority, then manifest order.
|
|
11
|
+
- Lock entries use `rev` instead of `commit`. Old locks still read.
|
|
12
|
+
|
|
13
|
+
## 0.2.1 — 2026-09-02
|
|
14
|
+
|
|
15
|
+
- `lshed list [--unused]` shows everything in the shed and which profiles use it.
|
|
16
|
+
- `lshed remove <key>` deletes a component or package from the shed. Refused while any profile still references it. Packages leave the manifest and lock only; the local clone stays.
|
|
17
|
+
- `lshed prune [--yes]` removes everything no profile uses. Lists without `--yes`.
|
|
18
|
+
- Manifest edits preserve your comments. Empty `packages:` is no longer written.
|
|
19
|
+
|
|
20
|
+
## 0.2.0 — 2026-09-02
|
|
21
|
+
|
|
22
|
+
A harness holds three kinds of things, and 0.1 treated them all the same. Running against a real `~/.claude` showed that 55 of 62 "skills" were files generated by one toolkit's installer, and the toolkit itself was a git clone.
|
|
23
|
+
|
|
24
|
+
- **Packages.** A `packages:` list in `lshed.yaml` records things you *installed* by source and version instead of copying them: `source: github:owner/repo@ref` (or `git:<url>#ref`), `into: <path under the agent root>`, optional `install: <command>`. `restore` clones a missing package at the commit pinned in `lshed.lock`; a package already present is never touched.
|
|
25
|
+
- **Generated files are skipped.** `init` recognises a directory as a package when it contains a `.git` with a remote, and recognises a stub as generated when one of its symlinks points inside a package. Both are left out of the shed and the managed set. Aliases that an installer creates without symlinks are not detected; use `init --exclude`.
|
|
26
|
+
- **`lshed.lock`** pins each package to a commit. Written by `init` from the existing clone, by `restore` on first clone, and by `update`.
|
|
27
|
+
- **`lshed update [ids...]`** fast-forwards packages and refreshes the lock.
|
|
28
|
+
- **Install commands run only with `--yes`.** Without it, `restore` and `update` print the commands and stop. A shed can be cloned from anywhere; running its shell commands should be a deliberate act.
|
|
29
|
+
- `git:` source scheme for non-GitHub remotes.
|
|
30
|
+
|
|
31
|
+
Packages are additive: switching to a profile that does not list one leaves it on disk. Removing a clone with a backup would mean copying a repository, which is the wrong tool for that job.
|
|
32
|
+
|
|
33
|
+
## 0.1.1 — 2026-09-02
|
|
34
|
+
|
|
35
|
+
Both fixes came from running 0.1.0 against a real 62-skill `~/.claude`.
|
|
36
|
+
|
|
37
|
+
- Skip regenerable directories when copying: `node_modules`, `.git`, `__pycache__`, `.venv`, cache dirs, `*.log`. A real harness went from 1.6 GB to 6.2 MB. Build output such as `dist/` is **not** ignored by default, because for some skills it is the deliverable.
|
|
38
|
+
- Extend the list with `ignore:` in `lshed.yaml`; the same list applies to `diff`, `save` and backups, so ignored files never show up as drift.
|
|
39
|
+
- Follow symlinks. A skill symlinked into `~/.claude/skills` used to be skipped silently; it is now captured and copied by content. Broken links are skipped.
|
|
40
|
+
- `init --exclude <id...>` leaves out components that do not belong in a shed, such as a toolkit with its own installer.
|
|
41
|
+
|
|
3
42
|
## 0.1.0 — 2026-09-02
|
|
4
43
|
|
|
5
44
|
First working release. Claude Code only.
|
package/README.md
CHANGED
|
@@ -76,24 +76,82 @@ profiles:
|
|
|
76
76
|
instructions: [base]
|
|
77
77
|
```
|
|
78
78
|
|
|
79
|
-
- `source` accepts `file:<path relative to the shed>`. `github:owner/repo@ref`
|
|
79
|
+
- Component `source` accepts `file:<path relative to the shed>`. Package `source` accepts `github:owner/repo@ref` or `git:<url>#ref`.
|
|
80
80
|
- Category names come from the adapter. For Claude Code: `skills`, `agents`, `commands`, `instructions`.
|
|
81
|
+
- `ignore:` at the top level adds to the built-in list of things never copied: `node_modules`, `.git`, `__pycache__`, `.venv`, cache directories, `*.log`. Build output like `dist/` is not ignored by default, since some skills ship it. Add it yourself if your parts rebuild from source.
|
|
81
82
|
- Instructions are not merged. `restore` writes a `CLAUDE.md` that `@`-imports each fragment in order, so a fragment edit shows up without re-running anything. Your original `CLAUDE.md` is backed up the first time.
|
|
82
83
|
|
|
84
|
+
## Three kinds of things
|
|
85
|
+
|
|
86
|
+
A real `~/.claude` mixes three kinds of content, and they need different handling:
|
|
87
|
+
|
|
88
|
+
| Kind | Example | What lshed does |
|
|
89
|
+
|---|---|---|
|
|
90
|
+
| **Authored** | a skill you wrote, your `CLAUDE.md` | copies it into the shed |
|
|
91
|
+
| **Installed** | a toolkit you `git clone`d, a plugin | records source + commit; `restore` clones it back |
|
|
92
|
+
| **Generated** | stub skills an installer wrote for you | skips them; they return when the installer runs |
|
|
93
|
+
|
|
94
|
+
`init` sorts this out for you. A directory with a `.git` and a remote becomes a **package**. A skill whose symlink points inside a package is treated as generated and skipped. Everything else is authored and copied.
|
|
95
|
+
|
|
96
|
+
```yaml
|
|
97
|
+
packages:
|
|
98
|
+
- id: gstack
|
|
99
|
+
source: github:garrytan/gstack@main # git:<url>#ref for other hosts
|
|
100
|
+
into: skills/gstack # where it lives under ~/.claude
|
|
101
|
+
install: ./setup # optional; run after clone, only with --yes
|
|
102
|
+
|
|
103
|
+
profiles:
|
|
104
|
+
default:
|
|
105
|
+
packages: [gstack]
|
|
106
|
+
skills: [add-drivers, domain-modeling]
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
`lshed.lock` pins each package to a commit, so a fresh machine gets the same version you had. `lshed update` moves it forward.
|
|
110
|
+
|
|
111
|
+
Claude Code plugins are packages too, with their own scheme. `init` finds them in `~/.claude/plugins`:
|
|
112
|
+
|
|
113
|
+
```yaml
|
|
114
|
+
packages:
|
|
115
|
+
- id: claude-plugins-official
|
|
116
|
+
source: claude-marketplace:anthropics/claude-plugins-official
|
|
117
|
+
- id: exa
|
|
118
|
+
source: claude-plugin:exa@claude-plugins-official
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
`restore` adds the marketplace, then runs `claude plugin install exa@claude-plugins-official`. Plugins cannot be pinned to a version, so the lock records whatever got installed and `status` tells you when it differs from the machine you came from. Plugins that bundle MCP servers bring them along.
|
|
122
|
+
|
|
123
|
+
Rules that keep this safe:
|
|
124
|
+
|
|
125
|
+
- A package that is already present is never touched by `restore`. Your local checkout is yours.
|
|
126
|
+
- `install:` is a shell command. `restore` and `update` **print it and stop** unless you pass `--yes`. Plugin installs go through Claude Code's own package manager and run without it; `--yes` is forwarded as `-y` for plugins that declare an install command.
|
|
127
|
+
- Packages are not part of the managed set. Switching profiles never deletes a clone.
|
|
128
|
+
- Installers sometimes create aliases without symlinks, which `init` cannot tell from authored skills. Leave those out with `--exclude`:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
lshed init --shed ~/harness --exclude _gstack-command connect-chrome
|
|
132
|
+
```
|
|
133
|
+
|
|
83
134
|
## Commands
|
|
84
135
|
|
|
85
136
|
```
|
|
86
|
-
lshed init [--shed <dir>] [--profile <name>]
|
|
87
|
-
lshed restore [profile] [--dry-run] [--no-backup]
|
|
88
|
-
lshed
|
|
137
|
+
lshed init [--shed <dir>] [--profile <name>] [--exclude <id...>]
|
|
138
|
+
lshed restore [profile] [--dry-run] [--no-backup] [--yes]
|
|
139
|
+
lshed update [ids...] [--dry-run] [--yes] pull packages forward, refresh lshed.lock
|
|
140
|
+
lshed status applied profile, managed paths, drift, packages
|
|
89
141
|
lshed diff files that differ between local and shed
|
|
90
142
|
lshed save [ids...] copy local edits back into the shed
|
|
143
|
+
lshed list [--unused] what is in the shed, and which profiles use it
|
|
144
|
+
lshed remove <key> drop a component or package from the shed
|
|
145
|
+
lshed prune [--yes] drop everything no profile uses
|
|
91
146
|
```
|
|
92
147
|
|
|
148
|
+
`remove` and `prune` delete from the shed without a backup. The shed is meant to live in git; commit before you prune. Both refuse to touch anything a profile still lists, so the way to retire a part is to take it out of the profiles first.
|
|
149
|
+
|
|
93
150
|
Global options: `--shed <dir>` (or `LSHED_HOME`; after the first restore lshed remembers it), `--root <dir>` (agent config root, default `~/.claude`).
|
|
94
151
|
|
|
95
152
|
### What `restore` does
|
|
96
153
|
|
|
154
|
+
0. Clones any package in the profile that is missing, at the commit in `lshed.lock`.
|
|
97
155
|
1. Removes paths that the **previous** profile placed and the new one doesn't need.
|
|
98
156
|
2. Copies every part of the new profile into place.
|
|
99
157
|
3. Regenerates the instructions file.
|
|
@@ -102,7 +160,7 @@ Anything it overwrites or removes is backed up first under `~/.claude/lshed/back
|
|
|
102
160
|
|
|
103
161
|
### Ownership
|
|
104
162
|
|
|
105
|
-
The shed is the source of truth
|
|
163
|
+
The shed is the source of truth for authored parts: `save` copies local edits back for `file:` components. Packages are owned by their upstream: `update` pulls them, `save` ignores them.
|
|
106
164
|
|
|
107
165
|
## Where things live
|
|
108
166
|
|
|
@@ -124,7 +182,8 @@ The shed is the source of truth. `save` copies local edits back for `file:` part
|
|
|
124
182
|
|
|
125
183
|
- MCP servers and secrets. Planned: the manifest names the keys, values are injected locally, nothing secret enters the shed.
|
|
126
184
|
- `settings.json` merging (hooks, permissions).
|
|
127
|
-
-
|
|
185
|
+
- `sync` (a git pull/push wrapper). Use git in the shed directly for now.
|
|
186
|
+
- MCP servers configured by hand in `~/.claude.json`. Plugin-bundled ones are covered.
|
|
128
187
|
- Windows and macOS have not been tested. The code avoids platform-specific paths, but treat 0.1 as Linux/WSL.
|
|
129
188
|
|
|
130
189
|
## Troubleshooting
|