@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
package/dist/cli.js
ADDED
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { createTwoFilesPatch } from 'diff';
|
|
4
|
+
import { readFileSync, realpathSync } from 'node:fs';
|
|
5
|
+
import os from 'node:os';
|
|
6
|
+
import { discover } from './catalog.js';
|
|
7
|
+
import { initialize } from './init.js';
|
|
8
|
+
import { interactive, confirmApply, selectUpdates, confirmRetry, confirmAdoption, } from './interactive.js';
|
|
9
|
+
import { apply, applyAll, plan } from './storage.js';
|
|
10
|
+
import { renderWithExternal } from './external.js';
|
|
11
|
+
import { DownloadCancelledError } from './retry.js';
|
|
12
|
+
import { loadTarget } from './targets.js';
|
|
13
|
+
import { configure, disableKits, reasons, resolveKits, setAnswers, } from './resolve.js';
|
|
14
|
+
import { kitSource } from './schema.js';
|
|
15
|
+
import { availableUpdates, hasUpdate, updateDescription } from './updates.js';
|
|
16
|
+
const version = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version;
|
|
17
|
+
const program = new Command()
|
|
18
|
+
.name('loadout')
|
|
19
|
+
.description('Configure your repository’s agent tools.')
|
|
20
|
+
.version(version)
|
|
21
|
+
.option('-g, --global', 'use the Loadout catalog in your home directory')
|
|
22
|
+
.option('--offline', 'use saved external kits without network requests')
|
|
23
|
+
.option('-C, --cwd <directory>', 'run in a different directory', process.cwd())
|
|
24
|
+
.showHelpAfterError();
|
|
25
|
+
function targetRoot() {
|
|
26
|
+
const opts = program.opts();
|
|
27
|
+
const home = realpathSync(os.homedir());
|
|
28
|
+
const root = opts.global ? home : discover(opts.cwd);
|
|
29
|
+
return { root, global: root === home };
|
|
30
|
+
}
|
|
31
|
+
function context() {
|
|
32
|
+
const { root, global } = targetRoot();
|
|
33
|
+
const target = loadTarget(root, global);
|
|
34
|
+
if (!target.catalog || !target.state)
|
|
35
|
+
throw new Error(target.error ??
|
|
36
|
+
`Loadout is not initialized here. Run loadout ${global ? '--global ' : ''}init.`);
|
|
37
|
+
return { catalog: target.catalog, state: target.state };
|
|
38
|
+
}
|
|
39
|
+
function interactiveTargets() {
|
|
40
|
+
const { root, global } = targetRoot();
|
|
41
|
+
const home = realpathSync(os.homedir());
|
|
42
|
+
let local = root;
|
|
43
|
+
if (global) {
|
|
44
|
+
try {
|
|
45
|
+
local = discover(program.opts().cwd);
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
local = realpathSync(program.opts().cwd);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const targets = local === home
|
|
52
|
+
? [loadTarget(home, true)]
|
|
53
|
+
: [loadTarget(local, false), loadTarget(home, true)];
|
|
54
|
+
const initial = global ? targets.length - 1 : 0;
|
|
55
|
+
const current = targets[initial];
|
|
56
|
+
if (!current.catalog)
|
|
57
|
+
throw new Error(current.error ??
|
|
58
|
+
`Loadout is not initialized here. Run loadout ${global ? '--global ' : ''}init.`);
|
|
59
|
+
return { targets, initial };
|
|
60
|
+
}
|
|
61
|
+
function preview(result, diff = false) {
|
|
62
|
+
const changed = result.changes.filter((c) => c.kind !== 'unchanged' && c.path !== '.gitignore');
|
|
63
|
+
if (!changed.length) {
|
|
64
|
+
console.log(result.changes.some((c) => c.kind !== 'unchanged')
|
|
65
|
+
? 'Ignore rules will be refreshed.'
|
|
66
|
+
: 'Generated files are unchanged.');
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
console.log('\nPlanned changes:');
|
|
70
|
+
for (const change of changed)
|
|
71
|
+
console.log(` ${change.kind === 'create' ? '+' : change.kind === 'delete' ? '-' : '~'} ${change.path}`);
|
|
72
|
+
if (diff) {
|
|
73
|
+
for (const change of changed) {
|
|
74
|
+
if (change.path.startsWith('.loadout/') || change.path === '.gitignore')
|
|
75
|
+
continue;
|
|
76
|
+
const before = change.before?.content ?? Buffer.alloc(0), after = change.after?.content ?? Buffer.alloc(0);
|
|
77
|
+
if (before.equals(after))
|
|
78
|
+
continue;
|
|
79
|
+
if (before.length + after.length > 200_000 ||
|
|
80
|
+
before.includes(0) ||
|
|
81
|
+
after.includes(0)) {
|
|
82
|
+
console.log(` ${change.path}: binary or large content; inspect the source for details.`);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
console.log(createTwoFilesPatch(`a/${change.path}`, `b/${change.path}`, before.toString('utf8'), after.toString('utf8'), undefined, undefined, { context: 3 }));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function showDependencies(catalog, state) {
|
|
91
|
+
for (const id of resolveKits(catalog, state.selected))
|
|
92
|
+
if (!state.selected.includes(id))
|
|
93
|
+
console.log(`${id} required by ${reasons(catalog, state.selected, id).join(', ')}`);
|
|
94
|
+
}
|
|
95
|
+
function options(command) {
|
|
96
|
+
return command
|
|
97
|
+
.option('--answer <kit.question=value>', 'set an answer (repeatable)', (value, previous) => [...previous, value], [])
|
|
98
|
+
.option('--adopt', 'preserve existing instructions and adopt identical skills')
|
|
99
|
+
.option('--diff', 'show text changes in generated files')
|
|
100
|
+
.option('--dry-run', 'preview without writing files or saving selections');
|
|
101
|
+
}
|
|
102
|
+
async function generate(catalog, state, opts) {
|
|
103
|
+
setAnswers(catalog, state, opts.answer ?? []);
|
|
104
|
+
const configured = await configure(catalog, state);
|
|
105
|
+
showDependencies(catalog, configured);
|
|
106
|
+
const rendered = await renderWithExternal(catalog, configured, {
|
|
107
|
+
update: opts.update,
|
|
108
|
+
offline: program.opts().offline,
|
|
109
|
+
onRetry: (id) => console.log(`Retrying ${id}…`),
|
|
110
|
+
onFetch: (id, source) => console.log(`Fetching ${id} from ${source.repo}…`),
|
|
111
|
+
});
|
|
112
|
+
for (const id of resolveKits(catalog, configured.selected)) {
|
|
113
|
+
const kit = catalog.kits.get(id);
|
|
114
|
+
if (kit.external) {
|
|
115
|
+
const source = opts.update?.includes(id)
|
|
116
|
+
? kit.external
|
|
117
|
+
: (kit.pinned ?? kit.external);
|
|
118
|
+
console.log(`${id}: ${source.repo}@${source.ref.slice(0, 12)} · license: ${source.license}`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const result = plan(catalog, configured, rendered, { adopt: opts.adopt });
|
|
122
|
+
preview(result, opts.diff || !!opts.update?.length || !!result.adopted?.length);
|
|
123
|
+
if (opts.dryRun)
|
|
124
|
+
console.log('Dry run: no files or selections saved.');
|
|
125
|
+
else {
|
|
126
|
+
const count = apply(result);
|
|
127
|
+
if (count)
|
|
128
|
+
console.log(`\nLoadout applied (${count} files changed).`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
async function setup() {
|
|
132
|
+
const { targets, initial } = interactiveTargets();
|
|
133
|
+
const configured = await interactive(targets, initial);
|
|
134
|
+
const offline = program.opts().offline;
|
|
135
|
+
const plans = [];
|
|
136
|
+
for (const { target, state } of configured) {
|
|
137
|
+
const catalog = target.catalog;
|
|
138
|
+
console.log(`\n${target.label} · ${target.root}`);
|
|
139
|
+
const update = await selectUpdates(catalog, state, offline);
|
|
140
|
+
const rendered = await renderWithExternal(catalog, state, {
|
|
141
|
+
offline,
|
|
142
|
+
update,
|
|
143
|
+
retry: confirmRetry,
|
|
144
|
+
onRetry: (id) => console.log(`Retrying ${id}…`),
|
|
145
|
+
onFetch: (id, source) => console.log(`Fetching ${id} from ${source.repo}…`),
|
|
146
|
+
});
|
|
147
|
+
for (const id of resolveKits(catalog, state.selected)) {
|
|
148
|
+
const kit = catalog.kits.get(id);
|
|
149
|
+
if (kit.external) {
|
|
150
|
+
const source = update.includes(id)
|
|
151
|
+
? kit.external
|
|
152
|
+
: (kit.pinned ?? kit.external);
|
|
153
|
+
console.log(`${id}: ${source.repo}@${source.ref.slice(0, 12)} · license: ${source.license}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
const result = plan(catalog, state, rendered, { adopt: true });
|
|
157
|
+
preview(result, update.length > 0 || !!result.adopted?.length);
|
|
158
|
+
if (result.adopted?.length && !(await confirmAdoption(result.adopted)))
|
|
159
|
+
throw new DownloadCancelledError();
|
|
160
|
+
plans.push(result);
|
|
161
|
+
}
|
|
162
|
+
if (!plans.some((result) => result.changes.some((c) => c.kind !== 'unchanged')))
|
|
163
|
+
return;
|
|
164
|
+
if (await confirmApply()) {
|
|
165
|
+
applyAll(plans);
|
|
166
|
+
console.log('\nYour loadout is ready.');
|
|
167
|
+
}
|
|
168
|
+
else
|
|
169
|
+
console.log('Cancelled. No kit selections or agent outputs saved.');
|
|
170
|
+
}
|
|
171
|
+
program.action(setup);
|
|
172
|
+
program
|
|
173
|
+
.command('init')
|
|
174
|
+
.description('create a starter catalog and open setup in a terminal')
|
|
175
|
+
.action(async () => {
|
|
176
|
+
const opts = program.opts();
|
|
177
|
+
const root = opts.global ? os.homedir() : opts.cwd;
|
|
178
|
+
const global = !!opts.global || realpathSync(root) === realpathSync(os.homedir());
|
|
179
|
+
initialize(root, global);
|
|
180
|
+
console.log(`Initialized ${realpathSync(root)}/.loadout${global ? '. Choose kits from Browse.' : ' with an editable starter kit.'}`);
|
|
181
|
+
if (process.stdin.isTTY && process.stdout.isTTY)
|
|
182
|
+
await setup();
|
|
183
|
+
else
|
|
184
|
+
console.log(`Run loadout${global ? ' --global' : ''} in a terminal to choose your kits.`);
|
|
185
|
+
});
|
|
186
|
+
program
|
|
187
|
+
.command('list')
|
|
188
|
+
.description('show available kits and why they are enabled')
|
|
189
|
+
.action(() => {
|
|
190
|
+
const { catalog, state } = context();
|
|
191
|
+
const enabled = resolveKits(catalog, state.selected);
|
|
192
|
+
for (const kit of catalog.kits.values()) {
|
|
193
|
+
const status = kit.ready === false
|
|
194
|
+
? 'Needs setup'
|
|
195
|
+
: state.selected.includes(kit.id)
|
|
196
|
+
? 'selected'
|
|
197
|
+
: enabled.includes(kit.id)
|
|
198
|
+
? `required by ${reasons(catalog, state.selected, kit.id).join(', ')}`
|
|
199
|
+
: 'disabled';
|
|
200
|
+
console.log(`${kit.id} [${status}]\n ${kitSource(kit)} · ${kit.description}`);
|
|
201
|
+
}
|
|
202
|
+
if (!catalog.kits.size)
|
|
203
|
+
console.log('No kits found. Add .loadout/kits/<name>/kit.yaml.');
|
|
204
|
+
});
|
|
205
|
+
program
|
|
206
|
+
.command('explain <kit>')
|
|
207
|
+
.description('explain why a kit is enabled')
|
|
208
|
+
.action((id) => {
|
|
209
|
+
const { catalog, state } = context();
|
|
210
|
+
if (!catalog.kits.has(id))
|
|
211
|
+
throw new Error(`Unknown kit: ${id}`);
|
|
212
|
+
const kit = catalog.kits.get(id);
|
|
213
|
+
if (kit.external) {
|
|
214
|
+
const source = kit.pinned ?? kit.external;
|
|
215
|
+
console.log(`Source: https://github.com/${source.repo}/tree/${source.ref}`);
|
|
216
|
+
console.log(`Skills: ${source.skills.map((p) => p.split('/').at(-1)).join(', ')}`);
|
|
217
|
+
if (hasUpdate(kit))
|
|
218
|
+
console.log(`A different source revision is offered. Run loadout update ${id} --dry-run to preview it.`);
|
|
219
|
+
}
|
|
220
|
+
const enabled = resolveKits(catalog, state.selected);
|
|
221
|
+
if (!enabled.includes(id)) {
|
|
222
|
+
console.log(`${id} is disabled.`);
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
if (state.selected.includes(id))
|
|
226
|
+
console.log(`${id} is explicitly selected.`);
|
|
227
|
+
for (const dependent of reasons(catalog, state.selected, id))
|
|
228
|
+
console.log(`${id} is required by ${dependent} (directly or transitively).`);
|
|
229
|
+
});
|
|
230
|
+
options(program
|
|
231
|
+
.command('enable <kits...>')
|
|
232
|
+
.description('enable kits and their dependencies')).action(async (ids, opts) => {
|
|
233
|
+
const { catalog, state } = context();
|
|
234
|
+
state.selected = [...state.selected, ...ids];
|
|
235
|
+
await generate(catalog, state, opts);
|
|
236
|
+
});
|
|
237
|
+
options(program
|
|
238
|
+
.command('disable <kit>')
|
|
239
|
+
.description('disable a kit; preserve dependencies still in use')
|
|
240
|
+
.option('--cascade', 'also disable explicit selections that require this kit')).action(async (id, opts) => {
|
|
241
|
+
const { catalog, state } = context();
|
|
242
|
+
if (!catalog.kits.has(id) && !state.selected.includes(id))
|
|
243
|
+
throw new Error(`Unknown kit: ${id}`);
|
|
244
|
+
state.selected = disableKits(catalog, state.selected, id, opts.cascade ?? false);
|
|
245
|
+
await generate(catalog, state, opts);
|
|
246
|
+
});
|
|
247
|
+
options(program
|
|
248
|
+
.command('apply')
|
|
249
|
+
.description('regenerate using saved selections and answers')).action(async (opts) => {
|
|
250
|
+
const { catalog, state } = context();
|
|
251
|
+
await generate(catalog, state, opts);
|
|
252
|
+
});
|
|
253
|
+
program
|
|
254
|
+
.command('outdated')
|
|
255
|
+
.description('compare downloaded external kits with the current catalog (no network)')
|
|
256
|
+
.action(() => {
|
|
257
|
+
const { catalog, state } = context();
|
|
258
|
+
const enabled = resolveKits(catalog, state.selected);
|
|
259
|
+
const updates = availableUpdates(catalog);
|
|
260
|
+
for (const kit of updates)
|
|
261
|
+
console.log(`${kit.id}${enabled.includes(kit.id) ? '' : ' [disabled]'}\n ${updateDescription(kit)}`);
|
|
262
|
+
console.log(updates.length
|
|
263
|
+
? '\nRun loadout to review enabled kit updates, or loadout update --dry-run.'
|
|
264
|
+
: 'No catalog updates for downloaded external kits.');
|
|
265
|
+
console.log('Compared with this catalog; upstream branches were not checked.');
|
|
266
|
+
});
|
|
267
|
+
options(program
|
|
268
|
+
.command('update [kits...]')
|
|
269
|
+
.description('update enabled external kits to their catalog revisions')).action(async (ids, opts) => {
|
|
270
|
+
const { catalog, state } = context();
|
|
271
|
+
const update = ids.length
|
|
272
|
+
? ids
|
|
273
|
+
: availableUpdates(catalog, state.selected).map((kit) => kit.id);
|
|
274
|
+
if (!update.length) {
|
|
275
|
+
console.log('No catalog updates for enabled external kits.');
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
await generate(catalog, state, { ...opts, update });
|
|
279
|
+
});
|
|
280
|
+
try {
|
|
281
|
+
await program.parseAsync();
|
|
282
|
+
}
|
|
283
|
+
catch (error) {
|
|
284
|
+
if (error instanceof Error &&
|
|
285
|
+
['ExitPromptError', 'AbortPromptError', 'DownloadCancelledError'].includes(error.name)) {
|
|
286
|
+
console.log('\nCancelled. No kit selections or agent outputs saved.');
|
|
287
|
+
process.exitCode = 130;
|
|
288
|
+
}
|
|
289
|
+
else {
|
|
290
|
+
console.error(`loadout: ${error instanceof Error ? error.message : String(error)}`);
|
|
291
|
+
process.exitCode = 1;
|
|
292
|
+
}
|
|
293
|
+
}
|
package/dist/curated.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { externalKitSchema, parse } from './schema.js';
|
|
2
|
+
export const providerDescriptions = {
|
|
3
|
+
'mattpocock/skills': 'Test-driven development, debugging, planning, and agent workflows',
|
|
4
|
+
'anthropics/skills': 'Interface design, browser testing, MCP servers, and generative art',
|
|
5
|
+
};
|
|
6
|
+
// Definitions ship with Loadout; upstream content is fetched only when selected.
|
|
7
|
+
const matt = {
|
|
8
|
+
repo: 'mattpocock/skills',
|
|
9
|
+
ref: '3cca18b368ae95cdbdebbff572ccafa662551015',
|
|
10
|
+
license: 'LICENSE',
|
|
11
|
+
};
|
|
12
|
+
const engineering = [
|
|
13
|
+
[
|
|
14
|
+
'tdd',
|
|
15
|
+
'Build features test-first with behavior checks that survive refactors',
|
|
16
|
+
['codebase-design'],
|
|
17
|
+
],
|
|
18
|
+
[
|
|
19
|
+
'diagnosing-bugs',
|
|
20
|
+
'Reproduce a failure, isolate its cause, and verify the fix',
|
|
21
|
+
],
|
|
22
|
+
[
|
|
23
|
+
'domain-modeling',
|
|
24
|
+
'Define shared project terms and capture architecture decisions',
|
|
25
|
+
],
|
|
26
|
+
[
|
|
27
|
+
'prototype',
|
|
28
|
+
'Try an interface or state model before committing to a design',
|
|
29
|
+
],
|
|
30
|
+
[
|
|
31
|
+
'research',
|
|
32
|
+
'Investigate a question and save findings with source citations',
|
|
33
|
+
],
|
|
34
|
+
[
|
|
35
|
+
'resolving-merge-conflicts',
|
|
36
|
+
'Resolve conflicts, verify the result, and commit the merge',
|
|
37
|
+
],
|
|
38
|
+
['wizard', 'Create a step-by-step Bash wizard for setup only a human can do'],
|
|
39
|
+
];
|
|
40
|
+
const productivity = [
|
|
41
|
+
[
|
|
42
|
+
'grill-me',
|
|
43
|
+
'Challenge a plan until its assumptions and trade-offs are clear',
|
|
44
|
+
['grilling'],
|
|
45
|
+
],
|
|
46
|
+
[
|
|
47
|
+
'writing-for-agents',
|
|
48
|
+
'Write concise agent instructions with clear triggers and steps',
|
|
49
|
+
],
|
|
50
|
+
[
|
|
51
|
+
'handoff',
|
|
52
|
+
'Save decisions, progress, and next steps for a fresh agent session',
|
|
53
|
+
],
|
|
54
|
+
['teach', 'Learn a topic through guided lessons, practice, and saved notes'],
|
|
55
|
+
[
|
|
56
|
+
'to-questionnaire',
|
|
57
|
+
'Draft a questionnaire to get missing answers from someone else',
|
|
58
|
+
],
|
|
59
|
+
['wait-what', 'Re-explain the last answer with context and simpler language'],
|
|
60
|
+
];
|
|
61
|
+
const anthropic = [
|
|
62
|
+
[
|
|
63
|
+
'frontend-design',
|
|
64
|
+
'Build interfaces with a clear visual direction, layout, and typography',
|
|
65
|
+
],
|
|
66
|
+
[
|
|
67
|
+
'webapp-testing',
|
|
68
|
+
'Check UI behavior and capture screenshots with Python + Playwright',
|
|
69
|
+
],
|
|
70
|
+
['mcp-builder', 'Build and evaluate MCP tools that connect agents to APIs'],
|
|
71
|
+
[
|
|
72
|
+
'algorithmic-art',
|
|
73
|
+
'Create p5.js art with repeatable seeds and interactive controls',
|
|
74
|
+
],
|
|
75
|
+
];
|
|
76
|
+
export const curatedKits = [
|
|
77
|
+
...[
|
|
78
|
+
['engineering', engineering],
|
|
79
|
+
['productivity', productivity],
|
|
80
|
+
].flatMap(([group, kits]) => kits.map(([name, description, supporting = []]) => ({
|
|
81
|
+
id: `matt-pocock-${name}`,
|
|
82
|
+
description,
|
|
83
|
+
source: {
|
|
84
|
+
...matt,
|
|
85
|
+
skills: [name, ...supporting].map((skill) => `skills/${group}/${skill}`),
|
|
86
|
+
},
|
|
87
|
+
}))),
|
|
88
|
+
...anthropic.map(([name, description]) => ({
|
|
89
|
+
id: `anthropic-${name}`,
|
|
90
|
+
description,
|
|
91
|
+
source: {
|
|
92
|
+
repo: 'anthropics/skills',
|
|
93
|
+
ref: '34040c9c568585f6929bedeaad110ad08f079624',
|
|
94
|
+
skills: [`skills/${name}`],
|
|
95
|
+
license: `skills/${name}/LICENSE.txt`,
|
|
96
|
+
},
|
|
97
|
+
})),
|
|
98
|
+
].map((kit) => parse(externalKitSchema, kit, 'Curated kit'));
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { type Catalog, type State, type ExternalSource } from './schema.js';
|
|
3
|
+
import { type Rendered } from './render.js';
|
|
4
|
+
declare const snapshotSchema: z.ZodObject<{
|
|
5
|
+
integrity: z.ZodString;
|
|
6
|
+
source: z.ZodObject<{
|
|
7
|
+
repo: z.ZodString;
|
|
8
|
+
ref: z.ZodString;
|
|
9
|
+
skills: z.ZodArray<z.ZodString>;
|
|
10
|
+
license: z.ZodDefault<z.ZodString>;
|
|
11
|
+
}, z.core.$strict>;
|
|
12
|
+
files: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
13
|
+
data: z.ZodString;
|
|
14
|
+
sha: z.ZodString;
|
|
15
|
+
mode: z.ZodUnion<readonly [z.ZodLiteral<420>, z.ZodLiteral<493>]>;
|
|
16
|
+
}, z.core.$strict>>;
|
|
17
|
+
}, z.core.$strict>;
|
|
18
|
+
declare const storeSchema: z.ZodObject<{
|
|
19
|
+
schemaVersion: z.ZodLiteral<1>;
|
|
20
|
+
kits: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
21
|
+
integrity: z.ZodString;
|
|
22
|
+
source: z.ZodObject<{
|
|
23
|
+
repo: z.ZodString;
|
|
24
|
+
ref: z.ZodString;
|
|
25
|
+
skills: z.ZodArray<z.ZodString>;
|
|
26
|
+
license: z.ZodDefault<z.ZodString>;
|
|
27
|
+
}, z.core.$strict>;
|
|
28
|
+
files: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
29
|
+
data: z.ZodString;
|
|
30
|
+
sha: z.ZodString;
|
|
31
|
+
mode: z.ZodUnion<readonly [z.ZodLiteral<420>, z.ZodLiteral<493>]>;
|
|
32
|
+
}, z.core.$strict>>;
|
|
33
|
+
}, z.core.$strict>>;
|
|
34
|
+
}, z.core.$strict>;
|
|
35
|
+
export type Snapshot = z.infer<typeof snapshotSchema>;
|
|
36
|
+
export type ExternalStore = z.infer<typeof storeSchema>;
|
|
37
|
+
export type FetchBytes = (url: string, limit: number, signal?: AbortSignal) => Promise<Buffer>;
|
|
38
|
+
export declare function readExternal(root: string): {
|
|
39
|
+
raw?: Buffer;
|
|
40
|
+
store: ExternalStore;
|
|
41
|
+
};
|
|
42
|
+
export declare const fetchBytes: FetchBytes;
|
|
43
|
+
export declare function renderWithExternal(catalog: Catalog, state: State, options?: {
|
|
44
|
+
fetch?: FetchBytes;
|
|
45
|
+
update?: string[];
|
|
46
|
+
offline?: boolean;
|
|
47
|
+
onFetch?: (id: string, source: ExternalSource) => void;
|
|
48
|
+
onRetry?: (id: string) => void;
|
|
49
|
+
retry?: (id: string, error: Error) => Promise<boolean>;
|
|
50
|
+
}): Promise<Rendered>;
|
|
51
|
+
export {};
|