@lidtop/loadout 0.1.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/LICENSE +21 -0
- package/README.md +28 -0
- package/dist/adoption.d.ts +13 -0
- package/dist/adoption.js +169 -0
- package/dist/bundled.d.ts +1 -0
- package/dist/bundled.js +3 -0
- package/dist/catalog.d.ts +3 -0
- package/dist/catalog.js +149 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +293 -0
- package/dist/curated.d.ts +3 -0
- package/dist/curated.js +98 -0
- package/dist/external.d.ts +51 -0
- package/dist/external.js +285 -0
- package/dist/fs.d.ts +6 -0
- package/dist/fs.js +60 -0
- package/dist/init.d.ts +1 -0
- package/dist/init.js +51 -0
- package/dist/interactive.d.ts +10 -0
- package/dist/interactive.js +82 -0
- package/dist/output-path.d.ts +1 -0
- package/dist/output-path.js +15 -0
- package/dist/picker.d.ts +29 -0
- package/dist/picker.js +569 -0
- package/dist/render.d.ts +14 -0
- package/dist/render.js +64 -0
- package/dist/resolve.d.ts +6 -0
- package/dist/resolve.js +80 -0
- package/dist/retry.d.ts +4 -0
- package/dist/retry.js +26 -0
- package/dist/schema.d.ts +111 -0
- package/dist/schema.js +139 -0
- package/dist/storage.d.ts +27 -0
- package/dist/storage.js +298 -0
- package/dist/targets.d.ts +11 -0
- package/dist/targets.js +31 -0
- package/dist/terminal.d.ts +1 -0
- package/dist/terminal.js +41 -0
- package/dist/updates.d.ts +4 -0
- package/dist/updates.js +30 -0
- package/kits/greenfield/instructions.md +3 -0
- package/kits/greenfield/kit.yaml +6 -0
- package/kits/write-kit/kit.yaml +6 -0
- package/kits/write-kit/skills/loadout-write-kit/SKILL.md +55 -0
- package/package.json +64 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type Catalog, type State } from './schema.js';
|
|
2
|
+
export type Target = {
|
|
3
|
+
label: string;
|
|
4
|
+
root: string;
|
|
5
|
+
global: boolean;
|
|
6
|
+
catalog?: Catalog;
|
|
7
|
+
state?: State;
|
|
8
|
+
error?: string;
|
|
9
|
+
};
|
|
10
|
+
export declare function loadTarget(root: string, global: boolean): Target;
|
|
11
|
+
export declare function initializeTarget(target: Target): Target;
|
package/dist/targets.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { loadCatalog } from './catalog.js';
|
|
2
|
+
import { readExternal } from './external.js';
|
|
3
|
+
import { exists, safePath } from './fs.js';
|
|
4
|
+
import { initialize } from './init.js';
|
|
5
|
+
import { loadState } from './storage.js';
|
|
6
|
+
export function loadTarget(root, global) {
|
|
7
|
+
const target = {
|
|
8
|
+
root,
|
|
9
|
+
global,
|
|
10
|
+
label: global ? 'Global' : 'Repository',
|
|
11
|
+
};
|
|
12
|
+
try {
|
|
13
|
+
if (!exists(safePath(root, '.loadout/config.yaml')))
|
|
14
|
+
return target;
|
|
15
|
+
const catalog = loadCatalog(root, global);
|
|
16
|
+
const { store } = readExternal(root);
|
|
17
|
+
for (const [id, snapshot] of Object.entries(store.kits)) {
|
|
18
|
+
const kit = catalog.kits.get(id);
|
|
19
|
+
if (kit?.external)
|
|
20
|
+
kit.pinned = snapshot.source;
|
|
21
|
+
}
|
|
22
|
+
return { ...target, catalog, state: loadState(catalog) };
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
return { ...target, error: error.message };
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export function initializeTarget(target) {
|
|
29
|
+
initialize(target.root, target.global);
|
|
30
|
+
return loadTarget(target.root, target.global);
|
|
31
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function prepareInput(input: NodeJS.ReadableStream): void;
|
package/dist/terminal.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { createInterface } from 'node:readline';
|
|
2
|
+
import { Writable } from 'node:stream';
|
|
3
|
+
const prepared = new WeakSet();
|
|
4
|
+
export function prepareInput(input) {
|
|
5
|
+
if (prepared.has(input))
|
|
6
|
+
return;
|
|
7
|
+
// Inquirer doesn't expose escapeCodeTimeout. Node retains the input's key
|
|
8
|
+
// decoder after an interface closes, so seed it before Inquirer opens one.
|
|
9
|
+
const output = new Writable({ write: (_chunk, _encoding, done) => done() });
|
|
10
|
+
const decoder = createInterface({
|
|
11
|
+
input,
|
|
12
|
+
output,
|
|
13
|
+
terminal: true,
|
|
14
|
+
escapeCodeTimeout: 50,
|
|
15
|
+
});
|
|
16
|
+
decoder.close();
|
|
17
|
+
output.end();
|
|
18
|
+
let lastEscape;
|
|
19
|
+
input.on('keypress', (_text, key) => {
|
|
20
|
+
if (key.name !== 'escape') {
|
|
21
|
+
lastEscape = undefined;
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const now = performance.now();
|
|
25
|
+
if (key.sequence === '\u001b\u001b' ||
|
|
26
|
+
(lastEscape !== undefined && now - lastEscape <= 500)) {
|
|
27
|
+
lastEscape = undefined;
|
|
28
|
+
// Use the same cancellation path as Ctrl+C, including later prompts.
|
|
29
|
+
input.emit('keypress', '\u0003', {
|
|
30
|
+
name: 'c',
|
|
31
|
+
sequence: '\u0003',
|
|
32
|
+
ctrl: true,
|
|
33
|
+
meta: false,
|
|
34
|
+
shift: false,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
else
|
|
38
|
+
lastEscape = now;
|
|
39
|
+
});
|
|
40
|
+
prepared.add(input);
|
|
41
|
+
}
|
package/dist/updates.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { resolveKits } from './resolve.js';
|
|
2
|
+
import { sameSource } from './schema.js';
|
|
3
|
+
export function hasUpdate(kit) {
|
|
4
|
+
return !!(kit.pinned &&
|
|
5
|
+
kit.external &&
|
|
6
|
+
!sameSource(kit.pinned, kit.external));
|
|
7
|
+
}
|
|
8
|
+
// Without a selection, include downloaded kits that are currently disabled.
|
|
9
|
+
export function availableUpdates(catalog, selected) {
|
|
10
|
+
const enabled = selected
|
|
11
|
+
? new Set(resolveKits(catalog, selected))
|
|
12
|
+
: undefined;
|
|
13
|
+
return [...catalog.kits.values()]
|
|
14
|
+
.filter((kit) => hasUpdate(kit) && (!enabled || enabled.has(kit.id)))
|
|
15
|
+
.sort((a, b) => a.id.localeCompare(b.id));
|
|
16
|
+
}
|
|
17
|
+
export function updateDescription(kit) {
|
|
18
|
+
const before = kit.pinned;
|
|
19
|
+
const after = kit.external;
|
|
20
|
+
return [
|
|
21
|
+
`${before.repo}@${before.ref.slice(0, 12)} → ${after.repo}@${after.ref.slice(0, 12)}`,
|
|
22
|
+
...(before.license !== after.license
|
|
23
|
+
? [`License: ${before.license} → ${after.license}`]
|
|
24
|
+
: []),
|
|
25
|
+
...(JSON.stringify([...before.skills].sort()) !==
|
|
26
|
+
JSON.stringify([...after.skills].sort())
|
|
27
|
+
? [`Skills: ${before.skills.join(', ')} → ${after.skills.join(', ')}`]
|
|
28
|
+
: []),
|
|
29
|
+
].join('\n ');
|
|
30
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
This is a greenfield project that is not yet deployed and has no existing users to support. Make changes directly without backward-compatibility layers, legacy fallbacks, deprecation paths, or migrations for earlier versions. Update affected code, tests, and documentation together, and remove superseded implementations.
|
|
2
|
+
|
|
3
|
+
If a change affects existing local development data, ask whether to migrate it with a one-time script or wipe it, unless that choice is already established.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: loadout-write-kit
|
|
3
|
+
description: Create or edit Loadout kits in .loadout/kits/.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Adapt this example; drop unused questions, outputs, and files.
|
|
7
|
+
|
|
8
|
+
`.loadout/kits/review/kit.yaml`:
|
|
9
|
+
|
|
10
|
+
```yaml
|
|
11
|
+
schemaVersion: 1
|
|
12
|
+
id: review
|
|
13
|
+
description: Review changes
|
|
14
|
+
questions:
|
|
15
|
+
diagrams: { type: boolean, message: Include diagrams?, default: false }
|
|
16
|
+
detail: { type: choice, message: Review depth?, choices: [brief, detailed], default: brief }
|
|
17
|
+
outputs:
|
|
18
|
+
- type: skill
|
|
19
|
+
source: skills/review
|
|
20
|
+
- type: instructions
|
|
21
|
+
source: instructions.md
|
|
22
|
+
- type: instructions
|
|
23
|
+
source: diagrams.md
|
|
24
|
+
scope: src
|
|
25
|
+
when: { answer: diagrams, equals: true }
|
|
26
|
+
- type: instructions
|
|
27
|
+
source: detailed.md
|
|
28
|
+
when: { answer: detail, equals: detailed }
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
`.loadout/kits/review/skills/review/SKILL.md`:
|
|
32
|
+
|
|
33
|
+
```markdown
|
|
34
|
+
---
|
|
35
|
+
name: review
|
|
36
|
+
description: Review this repository's code changes.
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
Read the diff, then report defects with file, line, and a suggested fix.
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
- Use unique lowercase-hyphen IDs; question keys and skill names use the same format. Skill `name` matches its directory.
|
|
43
|
+
- Sources are relative to `kit.yaml`; create every referenced file/directory, including conditional ones. No traversal, globs, or symlinks. Edit sources, not generated files.
|
|
44
|
+
- `ready: false` blocks selection (**Needs setup**); omitted/true is ready; ready kits need at least one output. No `enabled` field: selection is personal state.
|
|
45
|
+
- Add `requires: [checks]` for an existing ready kit; no cycles. Shared/explicit dependencies survive dependent removal; `loadout disable checks --cascade` also removes selected dependents.
|
|
46
|
+
- Answers reuse saved values, then optional defaults; otherwise input is required. `when` matches one same-kit answer on either output type. No conditional questions or interpolation.
|
|
47
|
+
- Instructions create `AGENTS.md` + a `CLAUDE.md` import at `scope` (default `.`). Other scopes require existing repository directories; global allows only `.`. Skills have no scope.
|
|
48
|
+
- Skills copy to both agents with references, scripts, assets, binaries, and executable bits; scripts aren't run on install. Link supporting files from `SKILL.md`.
|
|
49
|
+
|
|
50
|
+
```sh
|
|
51
|
+
loadout enable review --answer review.diagrams=true --answer review.detail=detailed --dry-run --diff
|
|
52
|
+
loadout disable review
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Drop `--dry-run --diff` to apply, or select via `loadout` → Kits → Continue.
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lidtop/loadout",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Choose and manage agent instruction and skill kits for repositories and your home directory.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"loadout": "dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"kits",
|
|
12
|
+
"README.md",
|
|
13
|
+
"LICENSE"
|
|
14
|
+
],
|
|
15
|
+
"engines": {
|
|
16
|
+
"node": ">=22.13.0"
|
|
17
|
+
},
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/ZackarySantana/loadout.git"
|
|
21
|
+
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsc",
|
|
24
|
+
"dev": "tsx src/cli.ts",
|
|
25
|
+
"test": "npm run build && node scripts/test.mjs",
|
|
26
|
+
"check": "npm run format:check && tsc --noEmit && tsc -p tsconfig.test.json && npm test",
|
|
27
|
+
"prepare": "npm run build",
|
|
28
|
+
"prepack": "npm run build",
|
|
29
|
+
"format": "prettier --write src test scripts .github *.json README.md",
|
|
30
|
+
"format:check": "prettier --check src test scripts .github *.json README.md",
|
|
31
|
+
"test:package": "node scripts/package-smoke.mjs"
|
|
32
|
+
},
|
|
33
|
+
"publishConfig": {
|
|
34
|
+
"access": "public"
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@inquirer/core": "^12.0.3",
|
|
38
|
+
"@inquirer/prompts": "^8.7.2",
|
|
39
|
+
"commander": "^15.0.0",
|
|
40
|
+
"diff": "^9.0.0",
|
|
41
|
+
"string-width": "^8.2.2",
|
|
42
|
+
"yaml": "^2.9.1",
|
|
43
|
+
"zod": "^4.6.5"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@inquirer/testing": "^3.3.13",
|
|
47
|
+
"@types/node": "^26.5.1",
|
|
48
|
+
"prettier": "^3.9.6",
|
|
49
|
+
"tsx": "^4.23.13",
|
|
50
|
+
"typescript": "^7.0.2"
|
|
51
|
+
},
|
|
52
|
+
"license": "MIT",
|
|
53
|
+
"homepage": "https://github.com/ZackarySantana/loadout#readme",
|
|
54
|
+
"bugs": {
|
|
55
|
+
"url": "https://github.com/ZackarySantana/loadout/issues"
|
|
56
|
+
},
|
|
57
|
+
"keywords": [
|
|
58
|
+
"cli",
|
|
59
|
+
"skills",
|
|
60
|
+
"agents",
|
|
61
|
+
"codex",
|
|
62
|
+
"claude-code"
|
|
63
|
+
]
|
|
64
|
+
}
|