loadout-ai 0.5.5 → 0.5.7
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 +33 -0
- package/MASTER_PLAN.md +84 -10
- package/README.md +284 -81
- package/dist/src/cli.js +5 -4
- package/dist/src/core/adopt.js +1 -0
- package/dist/src/core/cli-guide.js +4 -0
- package/dist/src/core/reconcile.js +1 -0
- package/dist/src/core/remove.js +23 -6
- package/dist/src/core/source.js +30 -0
- package/dist/src/core/state.js +14 -9
- package/dist/src/core/uninstall.js +17 -5
- package/dist/src/core/update.js +30 -5
- package/dist/src/shared/schemas.js +1 -0
- package/docs/DEMO_SCRIPT.md +155 -0
- package/docs/USER_TEST_GUIDE.md +1 -1
- package/docs/assets/loadout-workflow.png +0 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,39 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.5.7 - 2026-07-21
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
|
|
9
|
+
- Explain that `setup --mode custom` reconciles the complete selected profile, while
|
|
10
|
+
`install --mode custom --package <id>` adds a package without retiring the current
|
|
11
|
+
managed profile.
|
|
12
|
+
- Show package-by-package progress during complete uninstall and stop calling an
|
|
13
|
+
approved `uninstall --yes` operation a dry run.
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- Preserve pre-existing skill trees that users explicitly adopted into Loadout when
|
|
18
|
+
removing one package or completely uninstalling Loadout. Removal now forgets
|
|
19
|
+
ownership and leaves adopted bytes in place, including legacy `adopted-*` records.
|
|
20
|
+
|
|
21
|
+
## 0.5.6 - 2026-07-21
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
|
|
25
|
+
- Resolve each repository's default-branch commit with a lightweight Git metadata
|
|
26
|
+
request before downloading files, deduplicate shared sources, and reuse exact
|
|
27
|
+
cached changed revisions for safety review.
|
|
28
|
+
- Give changed repositories a bounded 120-second review window while keeping remote
|
|
29
|
+
commit checks at 30 seconds, so large reviewed sources do not produce permanent
|
|
30
|
+
false connectivity warnings under four-way concurrency.
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
|
|
34
|
+
- Complete update checks for large sources such as Scientific Agent Skills and
|
|
35
|
+
Awesome Copilot without weakening static diff analysis, activating disabled skills,
|
|
36
|
+
or treating a timed-out clone as a GitHub outage.
|
|
37
|
+
|
|
5
38
|
## 0.5.5 - 2026-07-21
|
|
6
39
|
|
|
7
40
|
### Changed
|
package/MASTER_PLAN.md
CHANGED
|
@@ -6,12 +6,78 @@ Category: Developer Tools
|
|
|
6
6
|
Team size: 3
|
|
7
7
|
Target submission: July 21, 2026 at 5:00 PM Pacific / July 22 at 4:00 AM Dubai
|
|
8
8
|
|
|
9
|
-
##
|
|
10
|
-
|
|
11
|
-
This is the
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
9
|
+
## Launch finish line (authoritative, July 21, 2026)
|
|
10
|
+
|
|
11
|
+
This is the only active checklist. Everything under **Archived implementation
|
|
12
|
+
history** is evidence of how the product was built, not unfinished launch scope.
|
|
13
|
+
|
|
14
|
+
### Product complete
|
|
15
|
+
|
|
16
|
+
- [x] Publish the CLI as `loadout-ai@0.5.6`; keep the product usable without cloning
|
|
17
|
+
this repository or providing an OpenAI/Anthropic API key.
|
|
18
|
+
- [x] Ship Stable, Power, Maximum, and Custom profiles with preview-first apply,
|
|
19
|
+
snapshots, drift protection, explicit rollback, removal, and complete uninstall.
|
|
20
|
+
- [x] Detect and manage skills across supported agent adapters while preserving
|
|
21
|
+
unrelated and unmanaged files.
|
|
22
|
+
- [x] Ship a 53-source pinned catalog, daily read-only discovery/update checks,
|
|
23
|
+
existing-skill reconciliation, and project-aware recommendation/optimization.
|
|
24
|
+
- [x] Credit and support the MIT Humanizer and Obsidian Skills sources. Humanizer is
|
|
25
|
+
available through Custom mode; Obsidian is recommended for detected vaults.
|
|
26
|
+
- [x] Ship three explicit MCP recipes for Playwright, Chrome DevTools, and read-only
|
|
27
|
+
GitHub, plus the separately reviewed Graphify runtime-tool recipe.
|
|
28
|
+
- [x] Remove the conflicting dashboard and make the CLI the only product surface.
|
|
29
|
+
- [x] Publish clear npm setup, testing, upstream attribution, trust boundaries, and a
|
|
30
|
+
detailed account of how Codex and GPT-5.6 were used in the README.
|
|
31
|
+
- [x] Pass the complete local release gate and the latest hosted CI run on `main`.
|
|
32
|
+
- [x] Preserve pre-existing adopted skills during removal and complete uninstall;
|
|
33
|
+
distinguish additive Custom installation from whole-profile Custom setup, and
|
|
34
|
+
show truthful progress during large approved uninstalls.
|
|
35
|
+
|
|
36
|
+
### Final founder acceptance
|
|
37
|
+
|
|
38
|
+
- [ ] Install the exact public npm release in a fresh terminal and run the final short
|
|
39
|
+
path: Humanizer Custom preview/apply/scan/rollback, read-only update/discovery,
|
|
40
|
+
complete uninstall, and clean reinstall. Stable, Power, Maximum, project
|
|
41
|
+
optimization, Graphify, and both-host Playwright MCP lifecycles have already
|
|
42
|
+
been exercised on the founder's real profiles.
|
|
43
|
+
- [ ] Decide whether to rename the GitHub repository from `loadout` to `loadout-ai`.
|
|
44
|
+
If approved, rename it before recording and update canonical links; keep the
|
|
45
|
+
product name **Loadout** and npm package/CLI identity `loadout-ai` / `loadout`.
|
|
46
|
+
- [ ] Make the six unresolved upstream-license decisions explicit. Do not silently
|
|
47
|
+
convert `NOASSERTION` into a license claim because a repository is popular.
|
|
48
|
+
|
|
49
|
+
### Submission work
|
|
50
|
+
|
|
51
|
+
- [ ] Record the real CLI demo using `docs/DEMO_SCRIPT.md`; keep it under three
|
|
52
|
+
minutes, include a voiceover, upload it publicly to YouTube, and verify the URL.
|
|
53
|
+
- [ ] Replace the README demo placeholder with the final YouTube link.
|
|
54
|
+
- [ ] In the voiceover, explain what Loadout does and how Codex and GPT-5.6 were used.
|
|
55
|
+
- [ ] Run `/feedback` in Codex, copy the resulting session ID, and enter it in Devpost.
|
|
56
|
+
- [ ] Confirm the repository URL is accessible to Devpost and OpenAI.
|
|
57
|
+
- [ ] Confirm all team invitations are accepted, select **Developer Tools**, complete
|
|
58
|
+
the edited Devpost description, and submit rather than leaving a draft.
|
|
59
|
+
|
|
60
|
+
### Deliberately not part of this submission
|
|
61
|
+
|
|
62
|
+
These are not launch blockers and should not be rebuilt before submission:
|
|
63
|
+
|
|
64
|
+
- A dashboard or second frontend surface.
|
|
65
|
+
- Hosted accounts, GitHub OAuth, cloud sync, analytics, or enterprise administration.
|
|
66
|
+
- Automatic installation of newly discovered projects or arbitrary third-party
|
|
67
|
+
installer execution.
|
|
68
|
+
- A universal quality score, fabricated benchmark results, or automatic claims that
|
|
69
|
+
stars prove safety or usefulness.
|
|
70
|
+
- A production-hosted signed intelligence service, a second executable runtime tool,
|
|
71
|
+
speculative adapter features without user demand, or ten external user studies.
|
|
72
|
+
- Restoring GitHub-hosted Actions capacity before submission; the full gate can run
|
|
73
|
+
locally, and the latest completed `main` CI is already passing.
|
|
74
|
+
|
|
75
|
+
## Archived current-status diary (historical, not active scope)
|
|
76
|
+
|
|
77
|
+
This section preserves the chronological implementation and founder-testing record.
|
|
78
|
+
Its unchecked boxes may describe older release numbers, superseded acceptance paths,
|
|
79
|
+
external research, or intentionally deferred work. They are not active launch tasks;
|
|
80
|
+
use the launch finish line above.
|
|
15
81
|
|
|
16
82
|
### Implemented product work
|
|
17
83
|
|
|
@@ -328,6 +394,14 @@ merged `codex/relatable-readme-hero` remote branch remains safe to delete after
|
|
|
328
394
|
managed drift, and no active adopted-skill update. Release this correction
|
|
329
395
|
before the remaining Graphify removal, discovery, uninstall, and reinstall
|
|
330
396
|
acceptance steps.
|
|
397
|
+
- [x] `P18-46 [TERRA]` Eliminate the repeated large-repository timeout exposed by the
|
|
398
|
+
published `0.5.5` founder check. Resolve remote HEAD metadata before fetching
|
|
399
|
+
content, download only changed revisions that require static safety analysis,
|
|
400
|
+
reuse immutable cached snapshots, and allow those bounded reviews 120 seconds.
|
|
401
|
+
The real 40-record Maximum state now completes with 19 disabled-library
|
|
402
|
+
changes, 21 current packages, zero active updates, and zero unavailable checks;
|
|
403
|
+
both previously failing large repositories complete without changing or
|
|
404
|
+
activating any agent-visible skill.
|
|
331
405
|
|
|
332
406
|
### Release 0.3 lifecycle hardening
|
|
333
407
|
|
|
@@ -2127,7 +2201,7 @@ small PRs, no long-lived branches.
|
|
|
2127
2201
|
|
|
2128
2202
|
## 25. Immediate next tasks
|
|
2129
2203
|
|
|
2130
|
-
Use
|
|
2131
|
-
|
|
2132
|
-
service, provider dependency, or
|
|
2133
|
-
|
|
2204
|
+
Use **Launch finish line** at the top of this document. The next actions are the short
|
|
2205
|
+
founder acceptance remainder, the recorded demo, `/feedback`, and Devpost submission.
|
|
2206
|
+
Do not add a hosted service, provider dependency, dashboard, or speculative feature
|
|
2207
|
+
before the deadline.
|
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<img src="./docs/assets/loadout-workflow.png" alt="Loadout
|
|
2
|
+
<img src="./docs/assets/loadout-workflow.png" alt="Loadout discovers skills, tools, and MCP servers, keeps them in a screened library, matches an active set to each project, and manages them across AI coding agents." width="960">
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
5
|
<h1 align="center">Loadout</h1>
|
|
@@ -7,36 +7,50 @@
|
|
|
7
7
|
<p align="center"><strong>Agent extensions, under control.</strong></p>
|
|
8
8
|
|
|
9
9
|
<p align="center">
|
|
10
|
-
|
|
10
|
+
<strong>The package manager for your AI coding setup.</strong><br>
|
|
11
|
+
Discover broadly. Activate the right tools for each project. Stay current without starting over.
|
|
11
12
|
</p>
|
|
12
13
|
|
|
13
14
|
<p align="center">
|
|
14
15
|
<a href="https://github.com/VirajMishra1/loadout/actions/workflows/ci.yml"><img src="https://github.com/VirajMishra1/loadout/actions/workflows/ci.yml/badge.svg" alt="CI status"></a>
|
|
16
|
+
<a href="https://www.npmjs.com/package/loadout-ai"><img src="https://img.shields.io/npm/v/loadout-ai?color=cb3837&logo=npm" alt="npm version"></a>
|
|
17
|
+
<a href="https://www.npmjs.com/package/loadout-ai"><img src="https://img.shields.io/npm/dm/loadout-ai?color=cb3837&label=downloads" alt="npm downloads"></a>
|
|
18
|
+
<a href="https://github.com/VirajMishra1/loadout"><img src="https://img.shields.io/github/stars/VirajMishra1/loadout?style=flat&logo=github" alt="GitHub stars"></a>
|
|
15
19
|
<a href="./package.json"><img src="https://img.shields.io/badge/Node.js-%3E%3D20-339933?logo=node.js&logoColor=white" alt="Node.js 20 or newer"></a>
|
|
16
20
|
<a href="./LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="MIT License"></a>
|
|
17
21
|
</p>
|
|
18
22
|
|
|
19
23
|
<p align="center">
|
|
20
|
-
<a href="#how-it-works">How it works</a> ·
|
|
21
24
|
<a href="#install">Install</a> ·
|
|
25
|
+
<a href="#why-loadout">Why Loadout</a> ·
|
|
22
26
|
<a href="#profiles">Profiles</a> ·
|
|
27
|
+
<a href="#catalog-and-discovery">Discover</a> ·
|
|
23
28
|
<a href="#trust-and-limits">Trust</a> ·
|
|
24
|
-
<a href="#command-reference">Commands</a>
|
|
25
|
-
<a href="#development">Development</a>
|
|
29
|
+
<a href="#command-reference">Commands</a>
|
|
26
30
|
</p>
|
|
27
31
|
|
|
28
|
-
|
|
29
|
-
|
|
32
|
+
## Install
|
|
33
|
+
|
|
34
|
+
You need Node.js 20 or newer and Git.
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npm install --global loadout-ai@0.5.7
|
|
38
|
+
loadout setup --mode stable
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The second command detects your agents and previews the 30-skill Stable loadout.
|
|
42
|
+
Nothing changes until you approve it. If anything goes wrong, start with the
|
|
43
|
+
[user test guide](./docs/USER_TEST_GUIDE.md).
|
|
30
44
|
|
|
31
45
|
## How it works
|
|
32
46
|
|
|
33
47
|
**Choose -> Inspect -> Preview -> Apply -> Undo**
|
|
34
48
|
|
|
35
|
-
1. **Choose**
|
|
36
|
-
2. **Inspect**
|
|
37
|
-
3. **Preview**
|
|
38
|
-
4. **Apply**
|
|
39
|
-
5. **Undo**
|
|
49
|
+
1. **Choose** Stable, Power, Maximum, or your own package list.
|
|
50
|
+
2. **Inspect** where each extension comes from and what it can do.
|
|
51
|
+
3. **Preview** every planned change without changing agent files.
|
|
52
|
+
4. **Apply** with `--yes`; Loadout saves a rollback snapshot first.
|
|
53
|
+
5. **Undo** with `loadout rollback` if you change your mind.
|
|
40
54
|
|
|
41
55
|
### Abridged terminal transcript
|
|
42
56
|
|
|
@@ -61,47 +75,70 @@ Restored snapshot <snapshot-id>
|
|
|
61
75
|
|
|
62
76
|
The final preview sentence above is captured CLI wording. A later `--yes` invocation recomputes the plan from pinned sources and current agent and filesystem state; it does not persist or prove identity with the earlier preview.
|
|
63
77
|
|
|
64
|
-
Preview may
|
|
78
|
+
Preview may fill Loadout's private download cache, but it does not change your agent
|
|
79
|
+
files. Review the summary and warnings before approving an apply command.
|
|
65
80
|
|
|
66
81
|
## Why Loadout
|
|
67
82
|
|
|
68
|
-
|
|
83
|
+
Loadout started with a frustrating question: **why does improving an AI coding agent
|
|
84
|
+
still mean opening twenty GitHub tabs?**
|
|
69
85
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
86
|
+
Useful skills, plugins, MCP servers, and settings arrive one experiment at a time.
|
|
87
|
+
Soon it is hard to remember what is installed, where it came from, whether something
|
|
88
|
+
better launched yesterday, or how to undo a change. The name comes from games, where
|
|
89
|
+
your loadout is the set of tools you choose for the mission. This does the same for AI
|
|
90
|
+
coding agents—without making you rebuild the setup for every agent and every project.
|
|
73
91
|
|
|
74
|
-
|
|
92
|
+
Most extension tools begin with a repo you already know. Loadout begins one step
|
|
93
|
+
earlier—**what is actually worth knowing?**—and stays with you after installation.
|
|
75
94
|
|
|
76
|
-
|
|
95
|
+
Loadout watches a much wider catalog than it activates. You can keep thousands of
|
|
96
|
+
technically screened skill copies in the disabled Maximum library, discover new projects as
|
|
97
|
+
they appear, and let each codebase pull a focused active set instead of dumping
|
|
98
|
+
everything into every prompt.
|
|
77
99
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
100
|
+
| The usual workflow | The Loadout workflow |
|
|
101
|
+
| -------------------------------------------------------------- | ---------------------------------------------------------------- |
|
|
102
|
+
| Find recommendations across feeds and bookmarks | Watch one growing discovery catalog |
|
|
103
|
+
| Open every repo and guess whether to trust it | Inspect pinned sources, licenses, components, and risk findings |
|
|
104
|
+
| Copy skills separately into Claude, Codex, Cursor, and friends | Apply one reviewed selection across detected agents |
|
|
105
|
+
| Let every skill compete for context forever | Keep a bounded daily set or activate skills for this project |
|
|
106
|
+
| Hope updates do not break anything | Preview updates and protect every managed change with a snapshot |
|
|
107
|
+
| Manually remember what was changed | Scan, reconcile, remove, roll back, or completely uninstall |
|
|
83
108
|
|
|
84
|
-
|
|
109
|
+
Loadout is local, open source, and preview-first. It does not need an OpenAI or
|
|
110
|
+
Anthropic API key to manage skills. MCP servers and executable tools stay behind
|
|
111
|
+
their own explicit setup and permission steps.
|
|
85
112
|
|
|
86
|
-
|
|
87
|
-
git clone https://github.com/VirajMishra1/loadout.git
|
|
88
|
-
cd loadout
|
|
89
|
-
npm ci
|
|
90
|
-
npm run build
|
|
91
|
-
npm link
|
|
92
|
-
loadout --version
|
|
93
|
-
```
|
|
113
|
+
### Demo
|
|
94
114
|
|
|
95
|
-
|
|
115
|
+
**Demo video coming here.** The release walkthrough will show the real path—not a
|
|
116
|
+
mock UI: Stable install, cross-agent inventory, project optimization, update and
|
|
117
|
+
discovery checks, MCP setup, Graphify, rollback, and complete uninstall. The exact
|
|
118
|
+
under-three-minute [recording and voiceover script](./docs/DEMO_SCRIPT.md) is public.
|
|
96
119
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
Nothing is installed until you explicitly approve the preview. See the [user test guide](./docs/USER_TEST_GUIDE.md) if linking, `PATH`, networking, risk approval, or rollback needs attention.
|
|
120
|
+
For now, the [end-to-end acceptance guide](./docs/USER_TEST_GUIDE.md) contains the same
|
|
121
|
+
commands you can run yourself.
|
|
102
122
|
|
|
103
123
|
## Stable workflow
|
|
104
124
|
|
|
125
|
+
### Stable Boost — install the essentials and start building
|
|
126
|
+
|
|
127
|
+
Stable is the recommended daily driver: **30 selected skill directories from four
|
|
128
|
+
pinned public sources**, installed into each agent you choose. It covers planning,
|
|
129
|
+
implementation, debugging, testing, documentation, code review, frontend work,
|
|
130
|
+
performance, Git, shipping, and more without turning every discovered skill on.
|
|
131
|
+
|
|
132
|
+
| Included source | What Stable takes from it | GitHub |
|
|
133
|
+
| ---------------------------------------------------------------------- | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
134
|
+
| [Superpowers](https://github.com/obra/superpowers) | Planning, execution, testing, review, verification | [](https://github.com/obra/superpowers) |
|
|
135
|
+
| [Context7](https://github.com/upstash/context7) | Current documentation and MCP workflows | [](https://github.com/upstash/context7) |
|
|
136
|
+
| [Addy Osmani Agent Skills](https://github.com/addyosmani/agent-skills) | Engineering, frontend, debugging, performance, docs, shipping | [](https://github.com/addyosmani/agent-skills) |
|
|
137
|
+
| [Agent Skills Marketplace](https://github.com/wshobson/agents) | Architecture, review, error handling, JavaScript, Python | [](https://github.com/wshobson/agents) |
|
|
138
|
+
|
|
139
|
+
Every row links directly to the upstream project. Loadout does not claim ownership
|
|
140
|
+
or endorsement; it pins, credits, screens, and selects from their public work.
|
|
141
|
+
|
|
105
142
|
```bash
|
|
106
143
|
# Preview for detected agents
|
|
107
144
|
loadout setup --mode stable
|
|
@@ -109,18 +146,20 @@ loadout setup --mode stable
|
|
|
109
146
|
# Recompute from current state and apply after reviewing the preview
|
|
110
147
|
loadout setup --mode stable --yes
|
|
111
148
|
|
|
112
|
-
# Inspect managed state, then undo the
|
|
113
|
-
loadout
|
|
114
|
-
loadout
|
|
149
|
+
# Inspect managed state, then undo the install if needed
|
|
150
|
+
loadout status
|
|
151
|
+
loadout scan
|
|
115
152
|
loadout rollback
|
|
116
153
|
```
|
|
117
154
|
|
|
118
|
-
Stable
|
|
155
|
+
Stable is Loadout's strongest general starting point, not a claim that one setup is
|
|
156
|
+
best for every person or project. Run `loadout profiles stable --json` when you want
|
|
157
|
+
the machine-readable selection.
|
|
119
158
|
|
|
120
159
|
## Manage skills you already have
|
|
121
160
|
|
|
122
|
-
Loadout can compare
|
|
123
|
-
|
|
161
|
+
Already have skills? Loadout can compare them with exact catalog copies and manage
|
|
162
|
+
the ones it can identify confidently:
|
|
124
163
|
|
|
125
164
|
```bash
|
|
126
165
|
# Read-only inventory and source/update comparison
|
|
@@ -134,26 +173,84 @@ loadout reconcile --yes
|
|
|
134
173
|
loadout reconcile --replace-outdated
|
|
135
174
|
```
|
|
136
175
|
|
|
137
|
-
Unknown or ambiguous copies
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
exact upstream repository and skill unit while preserving the agent path already in
|
|
141
|
-
use.
|
|
176
|
+
Unknown or ambiguous copies stay untouched. Replacing an old copy is a separate,
|
|
177
|
+
previewed transaction with its own rollback snapshot. Managed copies can then be
|
|
178
|
+
checked by `loadout update` without moving them to a different agent path.
|
|
142
179
|
|
|
143
180
|
## Profiles
|
|
144
181
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
182
|
+
Loadout is opinionated when you want it to be and precise when you do not.
|
|
183
|
+
|
|
184
|
+
### Power Boost — a larger cross-project toolkit
|
|
185
|
+
|
|
186
|
+
Power draws a skill-level allowlist from eight major collections. The prepared set
|
|
187
|
+
is deduplicated and invalid units are quarantined, so the final count can be lower
|
|
188
|
+
than the raw allowlist. In current acceptance testing it prepared about 50 active
|
|
189
|
+
skills per agent.
|
|
190
|
+
|
|
191
|
+
| Included source | Focus | GitHub |
|
|
192
|
+
| ------------------------------------------------------------------------ | --------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
193
|
+
| [Anthropic Skills](https://github.com/anthropics/skills) | Documents, frontend, MCP building, web testing | [](https://github.com/anthropics/skills) |
|
|
194
|
+
| [OpenAI Skills](https://github.com/openai/skills) | CLI, docs, browser work, images, security | [](https://github.com/openai/skills) |
|
|
195
|
+
| [Vercel Agent Skills](https://github.com/vercel-labs/agent-skills) | React, web design, composition, deployment | [](https://github.com/vercel-labs/agent-skills) |
|
|
196
|
+
| [Superpowers](https://github.com/obra/superpowers) | Planning, debugging, testing, collaboration | [](https://github.com/obra/superpowers) |
|
|
197
|
+
| [UI UX Pro Max](https://github.com/nextlevelbuilder/ui-ux-pro-max-skill) | UI systems, slides, styling, product design | [](https://github.com/nextlevelbuilder/ui-ux-pro-max-skill) |
|
|
198
|
+
| [Context7](https://github.com/upstash/context7) | Current documentation and MCP workflows | [](https://github.com/upstash/context7) |
|
|
199
|
+
| [Agent Skills Marketplace](https://github.com/wshobson/agents) | Architecture, testing, APIs, TypeScript, Python | [](https://github.com/wshobson/agents) |
|
|
200
|
+
| [Awesome Copilot](https://github.com/github/awesome-copilot) | Codebase knowledge, plans, browser and security workflows | [](https://github.com/github/awesome-copilot) |
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
loadout setup --mode power
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Maximum Library — download broadly, activate intelligently
|
|
207
|
+
|
|
208
|
+
Maximum is for explorers. It downloads every non-archived, technically screened
|
|
209
|
+
skill component in the catalog into Loadout's **disabled local library**. Disabled
|
|
210
|
+
means cached and available—not injected into agent context. Then let the current
|
|
211
|
+
project choose a focused active set:
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
loadout setup --mode maximum
|
|
215
|
+
loadout recommend --project . --agent codex
|
|
216
|
+
loadout optimize --project . --agents codex,claude-code --limit 30
|
|
217
|
+
loadout optimize --project . --agents codex,claude-code --limit 30 --yes
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
This is the difference between “install everything” and “have everything ready.”
|
|
221
|
+
The first overloads agents; the second gives you a large library with a small,
|
|
222
|
+
relevant active loadout.
|
|
223
|
+
|
|
224
|
+
### Custom — take exact control
|
|
225
|
+
|
|
226
|
+
Use `setup` when the listed packages should become the complete managed profile for
|
|
227
|
+
the selected agents. Packages from the previous managed profile that are not listed
|
|
228
|
+
will be retired, and the preview names every retirement:
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
loadout setup --mode custom --package superpowers --package context7
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Use `install` when you only want to add a package without replacing the current
|
|
235
|
+
managed profile:
|
|
236
|
+
|
|
237
|
+
```bash
|
|
151
238
|
|
|
152
|
-
|
|
239
|
+
# Install the reviewed Humanizer writing skill into Codex
|
|
240
|
+
loadout install --mode custom --package humanizer --agents codex
|
|
241
|
+
|
|
242
|
+
# Install the reviewed Obsidian skills explicitly
|
|
243
|
+
loadout install --mode custom --package obsidian-skills --agents codex,claude-code
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
Run `loadout profiles` to compare every mode. MCP servers always use a separate
|
|
247
|
+
approval step. Obsidian skills are also proposed automatically when `recommend` or
|
|
248
|
+
`optimize` detects an Obsidian vault; they are not added to the universal Stable set.
|
|
153
249
|
|
|
154
250
|
## MCP integrations
|
|
155
251
|
|
|
156
|
-
MCP servers
|
|
252
|
+
Profiles never start MCP servers silently. First list the available recipes and see
|
|
253
|
+
which ones need credentials:
|
|
157
254
|
|
|
158
255
|
```bash
|
|
159
256
|
loadout mcp-recipe
|
|
@@ -171,14 +268,15 @@ loadout mcp-recipe playwright --agent claude-code
|
|
|
171
268
|
loadout mcp-recipe playwright --agent claude-code --yes
|
|
172
269
|
```
|
|
173
270
|
|
|
174
|
-
Configuration does not
|
|
271
|
+
Configuration alone does not start the server. Test a real connection separately
|
|
272
|
+
with `--connect --approve-risk`. Loadout can reference credentials from environment
|
|
273
|
+
variables or the OS keychain without printing their values.
|
|
175
274
|
|
|
176
275
|
## Optional runtime tools
|
|
177
276
|
|
|
178
|
-
[Graphify](https://github.com/Graphify-Labs/graphify) is
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
artifact, permissions, targets, and rollback scope before doing anything:
|
|
277
|
+
[Graphify](https://github.com/Graphify-Labs/graphify) is an optional codebase graph
|
|
278
|
+
tool. It installs both a command and an agent skill, so Loadout keeps it separate from
|
|
279
|
+
the normal profiles. It does not require an OpenAI or Anthropic API key:
|
|
182
280
|
|
|
183
281
|
```bash
|
|
184
282
|
loadout tool graphify --agents codex,claude-code
|
|
@@ -186,11 +284,38 @@ loadout tool graphify --agents codex,claude-code --yes --approve-risk
|
|
|
186
284
|
loadout tool graphify --remove --agents codex,claude-code --yes --approve-risk
|
|
187
285
|
```
|
|
188
286
|
|
|
189
|
-
|
|
190
|
-
tools always remain an explicit choice.
|
|
287
|
+
Executable tools remain an explicit choice instead of hiding inside a profile.
|
|
191
288
|
|
|
192
289
|
## Catalog and discovery
|
|
193
290
|
|
|
291
|
+
### GitHub moves every day. Your loadout should not stand still.
|
|
292
|
+
|
|
293
|
+
The catalog is not a frozen “top 50” list. Loadout separates **discovery** from
|
|
294
|
+
**installation** so a viral repo can be noticed quickly without being trusted
|
|
295
|
+
blindly. Candidates enter a review queue; catalog entries are pinned and inspected;
|
|
296
|
+
only the bounded Stable policy gets the strongest automatic recommendation.
|
|
297
|
+
|
|
298
|
+
```bash
|
|
299
|
+
# Find candidates across configured discovery sources
|
|
300
|
+
loadout discover --source all --queue
|
|
301
|
+
|
|
302
|
+
# Inspect the queue and one candidate before promotion
|
|
303
|
+
loadout review-queue
|
|
304
|
+
loadout candidate inspect owner/repository
|
|
305
|
+
|
|
306
|
+
# Check whether managed active or disabled-library sources changed
|
|
307
|
+
loadout update
|
|
308
|
+
loadout health --updates
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
Daily checks are opt-in and read-only. They tell you what changed; they do not
|
|
312
|
+
silently rewrite your agents:
|
|
313
|
+
|
|
314
|
+
```bash
|
|
315
|
+
loadout autopilot --yes
|
|
316
|
+
loadout autopilot --status
|
|
317
|
+
```
|
|
318
|
+
|
|
194
319
|
<!-- loadout:catalog-coverage:start -->
|
|
195
320
|
|
|
196
321
|
The bundled catalog currently contains **53 credited public repositories** across **39 categories**: **34 have skill components** and **19 are MCP-only**. All 53 are technically screened and pinned; 4 sources are selected by the bounded Stable policy. See every linked source, license status, component type, and pinned commit in **[Catalog and upstream credits](./docs/CATALOG.md)**.
|
|
@@ -250,20 +375,99 @@ Configured paths and disposable filesystem lifecycle tests do not prove that nat
|
|
|
250
375
|
|
|
251
376
|
## Command reference
|
|
252
377
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
|
256
|
-
|
|
|
257
|
-
|
|
|
258
|
-
|
|
|
259
|
-
|
|
|
260
|
-
|
|
|
261
|
-
|
|
|
262
|
-
|
|
|
263
|
-
|
|
|
264
|
-
|
|
|
265
|
-
|
|
|
266
|
-
|
|
|
378
|
+
Start at the top and stop whenever Loadout does everything you need.
|
|
379
|
+
|
|
380
|
+
| Priority | What it does | Command |
|
|
381
|
+
| -------: | --------------------------------------------------------------- | ------------------------------------------------------------------ |
|
|
382
|
+
| 1 | Opens the beginner-friendly guided path | `loadout guide` |
|
|
383
|
+
| 2 | Previews the recommended 30-skill daily setup | `loadout setup --mode stable` |
|
|
384
|
+
| 3 | Previews the broader Power setup | `loadout setup --mode power` |
|
|
385
|
+
| 4 | Downloads the broad screened library, disabled by default | `loadout setup --mode maximum` |
|
|
386
|
+
| 5 | Shows Loadout-managed packages and active skills | `loadout status`; `loadout library` |
|
|
387
|
+
| 6 | Inventories skills across detected agents without changing them | `loadout scan` |
|
|
388
|
+
| 7 | Explains what fits the current repository | `loadout recommend --project . --agent codex` |
|
|
389
|
+
| 8 | Previews a bounded project-specific active set | `loadout optimize --project . --limit 30` |
|
|
390
|
+
| 9 | Compares existing skills with reviewed catalog copies | `loadout reconcile --refresh` |
|
|
391
|
+
| 10 | Checks managed active and disabled-library sources for changes | `loadout update` |
|
|
392
|
+
| 11 | Finds newly launched or newly popular candidates | `loadout discover --source all --queue` |
|
|
393
|
+
| 12 | Shows candidates waiting for deeper review | `loadout review-queue` |
|
|
394
|
+
| 13 | Lists MCP recipes and credential needs | `loadout mcp-recipe`; `loadout mcp-recipe --credential-free` |
|
|
395
|
+
| 14 | Previews an MCP configuration | `loadout mcp-recipe playwright --agent codex` |
|
|
396
|
+
| 15 | Lists and installs isolated runtime tools such as Graphify | `loadout tool`; `loadout tool graphify --agents codex,claude-code` |
|
|
397
|
+
| 16 | Lists snapshots or restores the latest managed change | `loadout rollback --list`; `loadout rollback` |
|
|
398
|
+
| 17 | Previews removal of one managed package | `loadout remove <package-id>` |
|
|
399
|
+
| 18 | Previews complete removal of Loadout-managed state | `loadout uninstall` |
|
|
400
|
+
| 19 | Enables read-only daily discovery and update checks | `loadout autopilot --yes` |
|
|
401
|
+
| 20 | Shows the complete CLI | `loadout --help`; `loadout advanced` |
|
|
402
|
+
|
|
403
|
+
Most mutating commands are dry runs first. After reading the preview, add `--yes` to
|
|
404
|
+
apply. Commands with executable or connection risk require the additional approval
|
|
405
|
+
shown in their output.
|
|
406
|
+
|
|
407
|
+
## Built with Codex and GPT-5.6
|
|
408
|
+
|
|
409
|
+
Loadout was built during OpenAI Build Week by a three-person team working with Codex
|
|
410
|
+
and GPT-5.6. Codex was not a chat box bolted onto the finished project. It was the
|
|
411
|
+
engineering environment we used to plan, build, test, and repeatedly challenge the
|
|
412
|
+
product while it was taking shape.
|
|
413
|
+
|
|
414
|
+
### From a broad idea to a working product
|
|
415
|
+
|
|
416
|
+
The starting idea was simple: one install that gives every coding agent the best
|
|
417
|
+
extensions on GitHub. The difficult part was everything hidden inside that sentence.
|
|
418
|
+
What counts as “best”? How much should stay active? What happens to skills a user
|
|
419
|
+
already has? How do you update a repository without silently trusting new code? How
|
|
420
|
+
do you undo changes across several agents?
|
|
421
|
+
|
|
422
|
+
We used GPT-5.6 through Codex for the repo-wide reasoning behind those decisions.
|
|
423
|
+
Together, we turned the idea into three distinct modes: a bounded Stable daily
|
|
424
|
+
driver, a larger Power setup, and a Maximum library that keeps broad optionality
|
|
425
|
+
without loading thousands of skills into every prompt.
|
|
426
|
+
|
|
427
|
+
| Part of the build | How we used Codex and GPT-5.6 | What made it into Loadout |
|
|
428
|
+
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
|
|
429
|
+
| Product planning | Broke the original idea into testable user journeys and challenged unsafe assumptions | Stable, Power, Maximum, Custom, project optimization, discovery, updates, and complete uninstall |
|
|
430
|
+
| Architecture | Traced how catalogs, adapters, agent directories, manifests, and snapshots affect one another | A local TypeScript CLI with a shared catalog, 12 agent adapters, and snapshot-backed transactions |
|
|
431
|
+
| Ecosystem research | Compared repositories, checked source layouts and licenses, and separated popularity from evidence | 53 pinned catalog sources plus a discovery snapshot watching 240 repositories |
|
|
432
|
+
| Implementation | Wrote and refactored CLI commands, schemas, source fetchers, installers, active-set logic, and MCP configuration | The published `loadout-ai` package and the commands documented above |
|
|
433
|
+
| Safety work | Looked for scripts, hooks, binaries, credential references, target collisions, stale previews, and external edits | Preview-first changes, quarantined skill units, explicit risk approval, drift protection, and rollback |
|
|
434
|
+
| Testing | Generated adversarial cases, reproduced failures from real terminal sessions, and converted them into regression tests | 620 passing tests, CLI and README end-to-end flows, package smoke tests, and a 1,000-skill performance gate |
|
|
435
|
+
| Team integration | Audited teammate branches, compared them with `main`, prepared focused pull requests, and checked what was actually complete | One public history instead of three disconnected prototypes |
|
|
436
|
+
| Release work | Verified npm contents, version behavior, GitHub metadata, documentation claims, and public CI | A public npm package, credited upstream catalog, release evidence, and a reproducible verification command |
|
|
437
|
+
|
|
438
|
+
### Real testing changed the code
|
|
439
|
+
|
|
440
|
+
Codex was most useful when the neat plan met a messy laptop. A few examples:
|
|
441
|
+
|
|
442
|
+
- A Graphify install appeared in Claude Code but vanished from Codex inventory
|
|
443
|
+
because the generated runtime skill and the normal skill scanner used different
|
|
444
|
+
Codex paths. The scan now recognizes managed runtime-tool skills explicitly.
|
|
445
|
+
- Update checks repeatedly timed out on large repositories. We measured the real
|
|
446
|
+
clone cost, changed the update path to check remote commit metadata first, and only
|
|
447
|
+
fetch a full snapshot when a pinned source actually changed.
|
|
448
|
+
- Existing unmanaged skills could occupy the same target as a Stable install.
|
|
449
|
+
Instead of overwriting them, Loadout now stops, scans, compares, and offers a
|
|
450
|
+
separate reconciliation path for exact or unambiguous matches.
|
|
451
|
+
- ChatGPT and Claude subscriptions were easy to confuse with separately billed API
|
|
452
|
+
access. Setup now asks about API access explicitly, while credentialed MCP servers
|
|
453
|
+
remain separate from automatic skill installation.
|
|
454
|
+
|
|
455
|
+
Those fixes came from a loop we repeated throughout the week: run the real command,
|
|
456
|
+
paste the exact output into Codex, trace the behavior through the codebase, write a
|
|
457
|
+
regression test, fix the smallest responsible layer, and run the full release gate.
|
|
458
|
+
|
|
459
|
+
### What the team owned
|
|
460
|
+
|
|
461
|
+
The humans chose the product direction, selected the tradeoffs, reviewed upstream
|
|
462
|
+
projects, tested Loadout on real Codex and Claude Code profiles, approved risky
|
|
463
|
+
operations, and made every release decision. GPT-5.6 helped with high-context design,
|
|
464
|
+
debugging, and review; Codex handled the implementation loop and verification tools.
|
|
465
|
+
Neither replaced human judgment about what should be installed on someone else's
|
|
466
|
+
machine.
|
|
467
|
+
|
|
468
|
+
Loadout itself does **not** call GPT-5.6 and does not require an OpenAI API key to
|
|
469
|
+
manage skills. Codex and GPT-5.6 helped build the tool; they are not a hidden runtime
|
|
470
|
+
dependency.
|
|
267
471
|
|
|
268
472
|
## Development
|
|
269
473
|
|
|
@@ -291,8 +495,7 @@ The repository's mixed README product-flow test uses an isolated build, disposab
|
|
|
291
495
|
- [Daily discovery snapshot](./docs/DISCOVERED.md)
|
|
292
496
|
- [Candidate inspection and promotion](./docs/CANDIDATE_INTELLIGENCE.md)
|
|
293
497
|
- [Credential and update policy](./docs/CREDENTIAL_AND_UPDATE_POLICY.md)
|
|
294
|
-
- [
|
|
295
|
-
- [Engineering plan](./MASTER_PLAN.md) and [changelog](./CHANGELOG.md)
|
|
498
|
+
- [Changelog](./CHANGELOG.md)
|
|
296
499
|
|
|
297
500
|
## Contributing, security, and attribution
|
|
298
501
|
|
package/dist/src/cli.js
CHANGED
|
@@ -264,7 +264,7 @@ async function runSetup(options) {
|
|
|
264
264
|
reader?.close();
|
|
265
265
|
}
|
|
266
266
|
}
|
|
267
|
-
const LOADOUT_VERSION = "0.5.
|
|
267
|
+
const LOADOUT_VERSION = "0.5.7";
|
|
268
268
|
function durableSchedulerLauncher() {
|
|
269
269
|
return [
|
|
270
270
|
join(dirname(process.execPath), process.platform === "win32" ? "npx.cmd" : "npx"),
|
|
@@ -909,7 +909,7 @@ program
|
|
|
909
909
|
.option("--agents <ids>", "limit explained scores to selected agent ids")
|
|
910
910
|
.action(async (options) => {
|
|
911
911
|
if (options.updates && !options.json)
|
|
912
|
-
console.error("Checking
|
|
912
|
+
console.error("Checking repository commits (4 at a time; changed sources may take up to 120s for safety review)…");
|
|
913
913
|
const report = await buildHealthReport({
|
|
914
914
|
updates: options.updates
|
|
915
915
|
? () => buildUpdatePlan(undefined, {
|
|
@@ -1020,11 +1020,12 @@ program
|
|
|
1020
1020
|
.option("--remove-cli", "also uninstall the global loadout-ai npm command")
|
|
1021
1021
|
.action(async (options) => {
|
|
1022
1022
|
const plan = await buildUninstallPlan();
|
|
1023
|
-
console.log(formatUninstallPlan(plan));
|
|
1023
|
+
console.log(formatUninstallPlan(plan, { applying: Boolean(options.yes) }));
|
|
1024
1024
|
if (!options.yes)
|
|
1025
1025
|
return;
|
|
1026
1026
|
const result = await applyUninstall(plan, undefined, {
|
|
1027
1027
|
force: options.force,
|
|
1028
|
+
onProgress: (message) => console.log(`→ ${message}`),
|
|
1028
1029
|
});
|
|
1029
1030
|
console.log(`Removed ${result.removedPackages} managed package(s), ${result.removedRuntimeTools} runtime tool(s), daily jobs, cache, library, and Loadout state.`);
|
|
1030
1031
|
if (options.removeCli) {
|
|
@@ -2857,7 +2858,7 @@ program
|
|
|
2857
2858
|
profile = await evaluateInstalledProfile(catalog);
|
|
2858
2859
|
}
|
|
2859
2860
|
if (!options.json)
|
|
2860
|
-
console.error("Checking
|
|
2861
|
+
console.error("Checking repository commits (4 at a time; changed sources may take up to 120s for safety review)…");
|
|
2861
2862
|
let plans = await buildUpdatePlan(undefined, {
|
|
2862
2863
|
packageId: options.package,
|
|
2863
2864
|
onProgress: options.json
|
package/dist/src/core/adopt.js
CHANGED
|
@@ -195,6 +195,7 @@ export async function applySkillAdoption(plan, options = {}) {
|
|
|
195
195
|
}, async (freshPlan, snapshot) => {
|
|
196
196
|
await options.beforeRecord?.();
|
|
197
197
|
await recordInstall(freshPlan.installPlan, snapshot.id, {
|
|
198
|
+
ownershipOrigin: "adopted",
|
|
198
199
|
...(freshPlan.repository ? { repository: freshPlan.repository } : {}),
|
|
199
200
|
...(freshPlan.resolvedCommit
|
|
200
201
|
? { resolvedCommit: freshPlan.resolvedCommit }
|
|
@@ -31,6 +31,10 @@ snapshot before changing managed files. Recover with: loadout rollback
|
|
|
31
31
|
Reconcile is also read-only unless you add --yes. Exact matches can be managed
|
|
32
32
|
without rewriting them; outdated replacements remain a separate explicit choice.
|
|
33
33
|
|
|
34
|
+
Setup reconciles the complete selected profile. To add one catalog package without
|
|
35
|
+
retiring the current managed profile, use:
|
|
36
|
+
loadout install --mode custom --package <id>
|
|
37
|
+
|
|
34
38
|
Nothing above changes your agents. For the full maintainer/tooling surface, run:
|
|
35
39
|
loadout advanced
|
|
36
40
|
`.trim();
|
|
@@ -237,6 +237,7 @@ export async function applyReconcilePlan(plan, options = {}) {
|
|
|
237
237
|
const entries = selected.map((item) => ({
|
|
238
238
|
plan: installPlanFor(item, item.status === "outdated"),
|
|
239
239
|
metadata: {
|
|
240
|
+
ownershipOrigin: "adopted",
|
|
240
241
|
repository: item.candidate.repository,
|
|
241
242
|
resolvedCommit: item.candidate.commit,
|
|
242
243
|
reviewed: true,
|
package/dist/src/core/remove.js
CHANGED
|
@@ -11,6 +11,12 @@ export async function planRemove(packageId) {
|
|
|
11
11
|
const trackedMcp = (state.mcpInstalls ?? []).filter((entry) => entry.packageId === packageId);
|
|
12
12
|
if (!record && !trackedMcp.length)
|
|
13
13
|
throw new Error(`Package is not managed by Loadout: ${packageId}`);
|
|
14
|
+
// Older releases encoded reconciled/adopted ownership in the generated id.
|
|
15
|
+
// Preserve that compatibility so upgrading Loadout protects already-adopted
|
|
16
|
+
// user content even before the new explicit state field has been written.
|
|
17
|
+
const preserveFiles = Boolean(record &&
|
|
18
|
+
(record.ownershipOrigin === "adopted" ||
|
|
19
|
+
record.packageId.startsWith("adopted-")));
|
|
14
20
|
const files = await Promise.all((record?.files ?? []).map(async (file) => {
|
|
15
21
|
const managedPath = managedFileReadPath(packageId, file.path, state.activations ?? []);
|
|
16
22
|
try {
|
|
@@ -28,7 +34,9 @@ export async function planRemove(packageId) {
|
|
|
28
34
|
return { path: managedPath, status: "missing" };
|
|
29
35
|
}
|
|
30
36
|
}));
|
|
31
|
-
const modified =
|
|
37
|
+
const modified = preserveFiles
|
|
38
|
+
? []
|
|
39
|
+
: files.filter((file) => file.status === "modified");
|
|
32
40
|
const mcpServers = await Promise.all(trackedMcp.map(async (entry) => {
|
|
33
41
|
try {
|
|
34
42
|
if (entry.configFormat === "codex-toml") {
|
|
@@ -76,6 +84,11 @@ export async function planRemove(packageId) {
|
|
|
76
84
|
}));
|
|
77
85
|
const modifiedMcp = mcpServers.filter((entry) => entry.status === "modified");
|
|
78
86
|
const warnings = [
|
|
87
|
+
...(preserveFiles
|
|
88
|
+
? [
|
|
89
|
+
"This package adopted pre-existing files; removal will forget Loadout ownership and preserve those files in place.",
|
|
90
|
+
]
|
|
91
|
+
: []),
|
|
79
92
|
...(modified.length
|
|
80
93
|
? [`${modified.length} managed file(s) were modified outside Loadout.`]
|
|
81
94
|
: []),
|
|
@@ -89,6 +102,7 @@ export async function planRemove(packageId) {
|
|
|
89
102
|
warnings.push("Removal is blocked unless --force is used.");
|
|
90
103
|
return {
|
|
91
104
|
packageId,
|
|
105
|
+
preserveFiles,
|
|
92
106
|
files,
|
|
93
107
|
mcpServers,
|
|
94
108
|
blocked: modified.length > 0 || modifiedMcp.length > 0,
|
|
@@ -103,17 +117,18 @@ export async function applyRemove(plan, options = {}) {
|
|
|
103
117
|
const existing = fresh.files
|
|
104
118
|
.filter((file) => file.status !== "missing")
|
|
105
119
|
.map((file) => file.path);
|
|
120
|
+
const removableFiles = fresh.preserveFiles ? [] : existing;
|
|
106
121
|
const configPaths = [
|
|
107
122
|
...new Set(fresh.mcpServers
|
|
108
123
|
.filter((entry) => entry.status !== "missing")
|
|
109
124
|
.map((entry) => entry.configPath)),
|
|
110
125
|
];
|
|
111
126
|
return {
|
|
112
|
-
targets: [...
|
|
113
|
-
value: { fresh,
|
|
127
|
+
targets: [...removableFiles, ...configPaths, installStatePath()],
|
|
128
|
+
value: { fresh, removableFiles, configPaths },
|
|
114
129
|
};
|
|
115
|
-
}, async ({ fresh,
|
|
116
|
-
for (const file of
|
|
130
|
+
}, async ({ fresh, removableFiles, configPaths }) => {
|
|
131
|
+
for (const file of removableFiles)
|
|
117
132
|
await rm(file, { force: true });
|
|
118
133
|
for (const configPath of configPaths) {
|
|
119
134
|
const relevant = fresh.mcpServers.filter((entry) => entry.configPath === configPath && entry.status !== "missing");
|
|
@@ -143,7 +158,9 @@ export async function applyRemove(plan, options = {}) {
|
|
|
143
158
|
proposed: { ...current, mcpServers: servers },
|
|
144
159
|
});
|
|
145
160
|
}
|
|
146
|
-
await forgetInstall(plan.packageId
|
|
161
|
+
await forgetInstall(plan.packageId, {
|
|
162
|
+
dropActivations: fresh.preserveFiles,
|
|
163
|
+
});
|
|
147
164
|
}, { label: `remove ${plan.packageId}` });
|
|
148
165
|
return applied.snapshotId;
|
|
149
166
|
}
|
package/dist/src/core/source.js
CHANGED
|
@@ -144,6 +144,36 @@ export function normalizeRepository(input) {
|
|
|
144
144
|
}
|
|
145
145
|
return value;
|
|
146
146
|
}
|
|
147
|
+
export function parseRepositoryHead(repository, output) {
|
|
148
|
+
const commit = output
|
|
149
|
+
.split(/\r?\n/)
|
|
150
|
+
.map((line) => line.split(/\s+/))
|
|
151
|
+
.find((parts) => parts[1] === "HEAD" && /^[0-9a-f]{40}$/i.test(parts[0]))?.[0];
|
|
152
|
+
if (!commit)
|
|
153
|
+
throw new Error(`Git returned an invalid default-branch HEAD for ${repository}`);
|
|
154
|
+
return commit;
|
|
155
|
+
}
|
|
156
|
+
/** Resolve the public default-branch commit without downloading repository files. */
|
|
157
|
+
export async function resolveRepositoryHead(input, options = {}) {
|
|
158
|
+
const repository = normalizeRepository(input);
|
|
159
|
+
const gitEnvironment = await isolatedGitEnvironment(loadoutHome());
|
|
160
|
+
const url = `https://github.com/${repository}.git`;
|
|
161
|
+
try {
|
|
162
|
+
const { stdout } = await execFileAsync("git", ["ls-remote", "--symref", "--", url, "HEAD"], {
|
|
163
|
+
maxBuffer: 1024 * 1024,
|
|
164
|
+
timeout: options.timeoutMs,
|
|
165
|
+
env: gitEnvironment,
|
|
166
|
+
});
|
|
167
|
+
return {
|
|
168
|
+
repository,
|
|
169
|
+
commit: parseRepositoryHead(repository, stdout),
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
174
|
+
throw new Error(`Could not resolve ${repository}: ${message}`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
147
177
|
function normalizeRef(ref) {
|
|
148
178
|
if (!/^[A-Za-z0-9][A-Za-z0-9._/-]*$/.test(ref) ||
|
|
149
179
|
ref.includes("..") ||
|
package/dist/src/core/state.js
CHANGED
|
@@ -145,6 +145,9 @@ async function createInstallRecord(plan, snapshotId, metadata = {}) {
|
|
|
145
145
|
const files = (await Promise.all([...new Set(plan.files.map((file) => file.target))].map(hashDirectory))).flat();
|
|
146
146
|
return {
|
|
147
147
|
packageId: plan.packageId,
|
|
148
|
+
...(metadata.ownershipOrigin
|
|
149
|
+
? { ownershipOrigin: metadata.ownershipOrigin }
|
|
150
|
+
: {}),
|
|
148
151
|
...(metadata.repository ? { repository: metadata.repository } : {}),
|
|
149
152
|
...(metadata.resolvedCommit
|
|
150
153
|
? { resolvedCommit: metadata.resolvedCommit }
|
|
@@ -311,7 +314,7 @@ export async function recordMcpInstall(record) {
|
|
|
311
314
|
];
|
|
312
315
|
await writeInstallState(state);
|
|
313
316
|
}
|
|
314
|
-
export async function forgetInstall(packageId) {
|
|
317
|
+
export async function forgetInstall(packageId, options = {}) {
|
|
315
318
|
const state = await readInstallState();
|
|
316
319
|
const installs = state.installs.filter((entry) => entry.packageId !== packageId);
|
|
317
320
|
const mcpInstalls = (state.mcpInstalls ?? []).filter((entry) => entry.packageId !== packageId);
|
|
@@ -323,13 +326,15 @@ export async function forgetInstall(packageId) {
|
|
|
323
326
|
installs,
|
|
324
327
|
...(state.profile ? { profile: state.profile } : {}),
|
|
325
328
|
mcpInstalls,
|
|
326
|
-
activations:
|
|
327
|
-
?
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
329
|
+
activations: options.dropActivations
|
|
330
|
+
? (state.activations ?? []).filter((entry) => entry.packageId !== packageId)
|
|
331
|
+
: (state.activations ?? []).map((entry) => entry.packageId === packageId
|
|
332
|
+
? {
|
|
333
|
+
...entry,
|
|
334
|
+
installationState: "removed",
|
|
335
|
+
activationState: "disabled",
|
|
336
|
+
updatedAt: new Date().toISOString(),
|
|
337
|
+
}
|
|
338
|
+
: entry),
|
|
334
339
|
});
|
|
335
340
|
}
|
|
@@ -85,19 +85,25 @@ export async function applyUninstall(plan, dependencies = {}, options = {}) {
|
|
|
85
85
|
if (fresh.blocked && !options.force)
|
|
86
86
|
throw new Error(`Complete uninstall is blocked because managed files were modified. Review them, or re-run with --force. ${fresh.warnings.join(" ")}`);
|
|
87
87
|
for (const id of fresh.runtimeTools) {
|
|
88
|
+
options.onProgress?.(`Removing runtime tool: ${id}`);
|
|
88
89
|
const runtimePlan = await planRuntimeTool(id, {
|
|
89
90
|
action: "remove",
|
|
90
91
|
stateHome: fresh.stateHome,
|
|
91
92
|
});
|
|
92
93
|
await applyRuntimeToolPlan(runtimePlan, { approveRisk: true });
|
|
93
94
|
}
|
|
94
|
-
for (const packagePlan of fresh.packages)
|
|
95
|
+
for (const [index, packagePlan] of fresh.packages.entries()) {
|
|
96
|
+
options.onProgress?.(`${packagePlan.preserveFiles ? "Forgetting adopted ownership" : "Removing managed package"} [${index + 1}/${fresh.packages.length}]: ${packagePlan.packageId}`);
|
|
95
97
|
await applyRemove(packagePlan, { force: options.force });
|
|
98
|
+
}
|
|
96
99
|
await removeEmptyManagedDirectories(fresh.packages);
|
|
97
|
-
if (fresh.schedulers.length)
|
|
100
|
+
if (fresh.schedulers.length) {
|
|
101
|
+
options.onProgress?.("Removing daily read-only schedules");
|
|
98
102
|
await (dependencies.unschedule
|
|
99
103
|
? dependencies.unschedule(fresh.schedulers)
|
|
100
104
|
: applyNativeSchedulerBundle(fresh.schedulers));
|
|
105
|
+
}
|
|
106
|
+
options.onProgress?.("Deleting Loadout cache, library, history, and state");
|
|
101
107
|
await rm(fresh.stateHome, { recursive: true, force: true });
|
|
102
108
|
return {
|
|
103
109
|
removedPackages: fresh.packages.length,
|
|
@@ -112,7 +118,7 @@ export async function uninstallGlobalCli() {
|
|
|
112
118
|
windowsHide: true,
|
|
113
119
|
});
|
|
114
120
|
}
|
|
115
|
-
export function formatUninstallPlan(plan) {
|
|
121
|
+
export function formatUninstallPlan(plan, options = {}) {
|
|
116
122
|
const modifiedPaths = plan.packages.flatMap((entry) => entry.files
|
|
117
123
|
.filter((file) => file.status === "modified")
|
|
118
124
|
.map((file) => file.path));
|
|
@@ -137,7 +143,13 @@ export function formatUninstallPlan(plan) {
|
|
|
137
143
|
"",
|
|
138
144
|
...plan.warnings.map((warning) => `Warning: ${warning}`),
|
|
139
145
|
"",
|
|
140
|
-
|
|
141
|
-
|
|
146
|
+
...(options.applying
|
|
147
|
+
? [
|
|
148
|
+
"Approved removal is starting. Large libraries can take several minutes; progress will be shown below.",
|
|
149
|
+
]
|
|
150
|
+
: [
|
|
151
|
+
"Dry run only. Re-run with `loadout uninstall --yes` to remove Loadout-managed data.",
|
|
152
|
+
"Add `--remove-cli` to also uninstall the global npm command.",
|
|
153
|
+
]),
|
|
142
154
|
].join("\n");
|
|
143
155
|
}
|
package/dist/src/core/update.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
2
|
import { basename, join } from "node:path";
|
|
3
|
-
import { fetchRepositorySnapshot } from "./source.js";
|
|
3
|
+
import { fetchRepositorySnapshot, resolveRepositoryHead } from "./source.js";
|
|
4
4
|
import { repositoryCachePath } from "./source.js";
|
|
5
5
|
import { diffRepositorySnapshots } from "./diff.js";
|
|
6
6
|
import { hashDirectory, readInstallState } from "./state.js";
|
|
@@ -85,21 +85,39 @@ async function analyzeManagedUpdate(oldRoot, newRoot, unitIds) {
|
|
|
85
85
|
};
|
|
86
86
|
}
|
|
87
87
|
/** Builds a read-only update plan from persisted installs and live GitHub snapshots. */
|
|
88
|
-
export async function buildUpdatePlan(resolver
|
|
88
|
+
export async function buildUpdatePlan(resolver, options = {}) {
|
|
89
89
|
const state = await readInstallState();
|
|
90
90
|
const records = options.packageId
|
|
91
91
|
? state.installs.filter((record) => record.packageId === options.packageId)
|
|
92
92
|
: state.installs;
|
|
93
93
|
const results = new Array(records.length);
|
|
94
|
+
const lightweightResolver = resolver ??
|
|
95
|
+
options.resolveHead ??
|
|
96
|
+
((repository) => resolveRepositoryHead(repository, { timeoutMs: 30_000 }));
|
|
94
97
|
const resolutions = new Map();
|
|
95
98
|
const resolveOnce = (repository) => {
|
|
96
99
|
const existing = resolutions.get(repository);
|
|
97
100
|
if (existing)
|
|
98
101
|
return existing;
|
|
99
|
-
const pending =
|
|
102
|
+
const pending = lightweightResolver(repository);
|
|
100
103
|
resolutions.set(repository, pending);
|
|
101
104
|
return pending;
|
|
102
105
|
};
|
|
106
|
+
const changedSnapshots = new Map();
|
|
107
|
+
const fetchChangedOnce = (repository, commit) => {
|
|
108
|
+
const key = `${repository}\0${commit.toLowerCase()}`;
|
|
109
|
+
const existing = changedSnapshots.get(key);
|
|
110
|
+
if (existing)
|
|
111
|
+
return existing;
|
|
112
|
+
const pending = options.fetchChangedSnapshot
|
|
113
|
+
? options.fetchChangedSnapshot(repository)
|
|
114
|
+
: fetchRepositorySnapshot(repository, {
|
|
115
|
+
ref: commit,
|
|
116
|
+
timeoutMs: 120_000,
|
|
117
|
+
});
|
|
118
|
+
changedSnapshots.set(key, pending);
|
|
119
|
+
return pending;
|
|
120
|
+
};
|
|
103
121
|
let cursor = 0;
|
|
104
122
|
let completed = 0;
|
|
105
123
|
const workers = Array.from({
|
|
@@ -139,9 +157,16 @@ export async function buildUpdatePlan(resolver = async (repository) => fetchRepo
|
|
|
139
157
|
let diff;
|
|
140
158
|
let safetyFindings;
|
|
141
159
|
let approvalRequired = false;
|
|
142
|
-
|
|
160
|
+
let currentPath = current.path;
|
|
161
|
+
if (!same && !currentPath && !resolver) {
|
|
162
|
+
const fetched = await fetchChangedOnce(record.repository, current.commit);
|
|
163
|
+
if (fetched.commit.toLowerCase() !== current.commit.toLowerCase())
|
|
164
|
+
throw new Error(`Resolved ${current.commit}, but fetched ${fetched.commit} for safety review`);
|
|
165
|
+
currentPath = fetched.path;
|
|
166
|
+
}
|
|
167
|
+
if (!same && currentPath) {
|
|
143
168
|
const oldPath = repositoryCachePath(record.repository, record.resolvedCommit);
|
|
144
|
-
const analysis = await analyzeManagedUpdate(oldPath,
|
|
169
|
+
const analysis = await analyzeManagedUpdate(oldPath, currentPath, managedUnitIds(state, record.packageId));
|
|
145
170
|
diff = analysis.diff;
|
|
146
171
|
safetyFindings = analysis.safetyFindings;
|
|
147
172
|
approvalRequired = analysis.approvalRequired;
|
|
@@ -269,6 +269,7 @@ const fileHashSchema = z.object({ path: text, sha256 });
|
|
|
269
269
|
export const installRecordSchema = z
|
|
270
270
|
.object({
|
|
271
271
|
packageId: text,
|
|
272
|
+
ownershipOrigin: z.enum(["installed", "adopted"]).optional(),
|
|
272
273
|
repository: optionalText,
|
|
273
274
|
resolvedCommit: optionalText,
|
|
274
275
|
targetAgents: z.array(agentIdSchema),
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# Loadout demo and voiceover
|
|
2
|
+
|
|
3
|
+
Target length: **2:35–2:50**. Record the real CLI, cut fetch waits and typing, and do
|
|
4
|
+
not show the retired dashboard. The final YouTube upload must be public.
|
|
5
|
+
|
|
6
|
+
## Before recording
|
|
7
|
+
|
|
8
|
+
1. Close terminals that show tokens, private paths you do not want public, or unrelated
|
|
9
|
+
work. Increase terminal font size and use a window about 120 columns wide.
|
|
10
|
+
2. Confirm the release and product health:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install --global loadout-ai@0.5.7
|
|
14
|
+
hash -r
|
|
15
|
+
loadout --version
|
|
16
|
+
loadout health
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
3. Finish the remaining founder acceptance path before recording. Keep the useful
|
|
20
|
+
successful output in terminal history, but start the recording from a clean prompt.
|
|
21
|
+
4. Rehearse the voiceover once. Use macOS Screenshot (`Shift-Command-5`) with your
|
|
22
|
+
microphone, OBS, or another recorder. Record at normal speed; speed the final cut
|
|
23
|
+
to 1.1x only if necessary.
|
|
24
|
+
|
|
25
|
+
## Shot list and exact narration
|
|
26
|
+
|
|
27
|
+
### 0:00–0:15 — the problem
|
|
28
|
+
|
|
29
|
+
**Screen:** README hero, then a terminal showing `loadout --version`.
|
|
30
|
+
|
|
31
|
+
**Say:**
|
|
32
|
+
|
|
33
|
+
> AI coding extensions are scattered across GitHub. You find a skill on X, an MCP
|
|
34
|
+
> server on Reddit, copy it into one agent, and later have no idea where it came from
|
|
35
|
+
> or how to undo it. I built Loadout: one local CLI to discover, inspect, install,
|
|
36
|
+
> update, and roll back agent extensions across Codex, Claude Code, and other agents.
|
|
37
|
+
|
|
38
|
+
### 0:15–0:50 — one safe install
|
|
39
|
+
|
|
40
|
+
**Screen:** Run the preview, then apply. Cut the fetch wait, not the result.
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
loadout setup --mode stable --agents codex,claude-code --api-access none
|
|
44
|
+
loadout setup --mode stable --agents codex,claude-code --api-access none --yes
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**Say:**
|
|
48
|
+
|
|
49
|
+
> Stable selects thirty useful skill directories per agent from four pinned public
|
|
50
|
+
> sources. The first run is a preview: it shows the sources, targets, credentials, and
|
|
51
|
+
> safety findings without changing agent files. When I approve it, Loadout applies one
|
|
52
|
+
> transaction and gives me a rollback snapshot. My ChatGPT and Claude subscriptions
|
|
53
|
+
> are not treated as API keys, and normal skill setup does not need one.
|
|
54
|
+
|
|
55
|
+
### 0:50–1:12 — see what changed and undo it
|
|
56
|
+
|
|
57
|
+
**Screen:**
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
loadout scan
|
|
61
|
+
loadout status
|
|
62
|
+
loadout rollback --list
|
|
63
|
+
loadout rollback --snapshot <stable-snapshot-id>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Say:**
|
|
67
|
+
|
|
68
|
+
> Scan separates Loadout-managed skills from files I already had. Status keeps source
|
|
69
|
+
> and version ownership, and rollback restores the exact pre-install snapshot while
|
|
70
|
+
> preserving unrelated skills. I use the exact snapshot ID shown by the install, so
|
|
71
|
+
> there is no ambiguity. Complete uninstall is available too.
|
|
72
|
+
|
|
73
|
+
### 1:12–1:42 — broad library, focused project
|
|
74
|
+
|
|
75
|
+
**Screen:** Use the already downloaded Maximum library from the acceptance run. Show
|
|
76
|
+
the first part of `library`, then run the two read-only commands.
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
loadout library
|
|
80
|
+
loadout recommend --project . --agent codex
|
|
81
|
+
loadout optimize --project . --agents codex,claude-code --limit 30
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**Say:**
|
|
85
|
+
|
|
86
|
+
> Maximum does not dump thousands of skills into every prompt. It keeps the broad
|
|
87
|
+
> screened catalog disabled, detects this TypeScript CLI project, and proposes a
|
|
88
|
+
> focused active set for each agent. That is the core idea: discover broadly, activate
|
|
89
|
+
> narrowly, and keep every change reversible.
|
|
90
|
+
|
|
91
|
+
### 1:42–2:05 — MCP, tools, and custom skills
|
|
92
|
+
|
|
93
|
+
**Screen:**
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
loadout mcp-recipe --credential-free
|
|
97
|
+
loadout mcp-recipe playwright --agent codex
|
|
98
|
+
loadout tool graphify --agents codex,claude-code
|
|
99
|
+
loadout install --mode custom --package humanizer --agents codex
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**Say:**
|
|
103
|
+
|
|
104
|
+
> MCP servers and executable tools are never hidden inside a profile. Playwright is a
|
|
105
|
+
> separately previewed MCP recipe; Graphify is a pinned runtime tool; and a catalog
|
|
106
|
+
> skill such as Humanizer can be installed directly through Custom mode. Each path
|
|
107
|
+
> discloses permissions and credentials before approval.
|
|
108
|
+
|
|
109
|
+
### 2:05–2:25 — today and tomorrow
|
|
110
|
+
|
|
111
|
+
**Screen:**
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
loadout update
|
|
115
|
+
loadout discover --limit 5
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**Say:**
|
|
119
|
+
|
|
120
|
+
> Update checks managed pinned sources without silently changing them. Discovery
|
|
121
|
+
> watches a wider ecosystem and queues new projects for review, so something going
|
|
122
|
+
> viral can be noticed quickly without being trusted blindly.
|
|
123
|
+
|
|
124
|
+
### 2:25–2:48 — Codex, GPT-5.6, and close
|
|
125
|
+
|
|
126
|
+
**Screen:** README section “Built with Codex and GPT-5.6”, then return to the hero.
|
|
127
|
+
|
|
128
|
+
**Say:**
|
|
129
|
+
|
|
130
|
+
> We used Codex and GPT-5.6 throughout the build: architecture, threat modelling,
|
|
131
|
+
> cross-platform implementation, repo-wide debugging, tests, and the real founder
|
|
132
|
+
> acceptance loop. Those tests caught rollback, project-scope, inventory, and update
|
|
133
|
+
> bugs on my actual Codex and Claude profiles. Loadout itself stays local and does not
|
|
134
|
+
> require an OpenAI API key. One command gives your AI agents a loadout you can
|
|
135
|
+
> understand, improve, and undo.
|
|
136
|
+
|
|
137
|
+
## Final edit and upload
|
|
138
|
+
|
|
139
|
+
- Remove loading screens, typing pauses, repeated commands, notifications, and secrets.
|
|
140
|
+
- Keep terminal output readable at 1080p; do not use a synthetic dashboard or mock data.
|
|
141
|
+
- Add a small title card: **Loadout — Agent extensions, under control.**
|
|
142
|
+
- Export under three minutes and upload publicly to YouTube.
|
|
143
|
+
- Watch the uploaded video once, confirm audio and text are legible, then paste the
|
|
144
|
+
exact public URL into README and Devpost.
|
|
145
|
+
|
|
146
|
+
## Submission checklist
|
|
147
|
+
|
|
148
|
+
- [ ] Public YouTube video is under three minutes and its URL opens signed out.
|
|
149
|
+
- [ ] Voiceover explains the product, Codex usage, and GPT-5.6 usage.
|
|
150
|
+
- [ ] `/feedback` was run in Codex and the session ID is in Devpost.
|
|
151
|
+
- [ ] Repository URL is accessible to Devpost and OpenAI.
|
|
152
|
+
- [ ] README has npm setup and the judge testing path.
|
|
153
|
+
- [ ] Every teammate has accepted the Devpost invitation.
|
|
154
|
+
- [ ] Category is **Developer Tools**.
|
|
155
|
+
- [ ] Submission is submitted, not left as a draft.
|
package/docs/USER_TEST_GUIDE.md
CHANGED
|
@@ -211,7 +211,7 @@ cleanup deliberately deletes Loadout's snapshots, so it is the last lifecycle te
|
|
|
211
211
|
## Troubleshooting and recovery
|
|
212
212
|
|
|
213
213
|
- **`loadout` is not found after installation:** confirm `npm install --global
|
|
214
|
-
loadout-ai@0.5.
|
|
214
|
+
loadout-ai@0.5.7` completed, run `hash -r`, and confirm npm's global binary
|
|
215
215
|
directory is on `PATH`. For a source checkout, run `npm run build` and `npm link`.
|
|
216
216
|
- **A preview asks for `--approve-risk`:** read the reported scripts, domains,
|
|
217
217
|
credentials, binaries, or instruction findings. If you accept that specific plan,
|
|
Binary file
|