first commit
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
# `manifest-loader`
|
||||
|
||||
## Purpose
|
||||
|
||||
Loads and validates the bundled `assets/skills/manifest.json` produced by
|
||||
`scripts/build-skills-bundle.ts`. The loader is the runtime equivalent of
|
||||
the plugin's manifest schema — every entry must have a string `id`,
|
||||
semver `version`, non-empty `dir`, and array of relative `files`.
|
||||
Validation failures surface as
|
||||
`InstallSkillsError(INSTALL_SKILLS.MANIFEST_INVALID)` with the underlying
|
||||
Zod error attached as `cause`.
|
||||
|
||||
## Features
|
||||
|
||||
- Zod-validated `BundledManifestSchema` — `{ schemaVersion: 1, skills: [...] }`.
|
||||
- Per-skill validation: `id`, semver `version`, `dir`, `files`.
|
||||
- **Not memoised** — every call re-reads the file so the testing harness
|
||||
can swap in alternate manifests by passing `manifestPath`.
|
||||
- Defaults to the bundled file shipped inside the package
|
||||
(`<pkg-root>/assets/skills/manifest.json`).
|
||||
- Distinguishes parse, read, and schema failures only by `messageKey`;
|
||||
the surfaced code is always `INSTALL_SKILLS.MANIFEST_INVALID`.
|
||||
|
||||
## Basic Example
|
||||
|
||||
```ts
|
||||
import { loadBundledManifest } from "@suaveplan/install-agent-skills";
|
||||
|
||||
const manifest = await loadBundledManifest();
|
||||
console.log(`bundled ${manifest.skills.length} skills`);
|
||||
```
|
||||
|
||||
## Advanced Example
|
||||
|
||||
```ts
|
||||
import {
|
||||
InstallSkillsError,
|
||||
loadBundledManifest,
|
||||
} from "@suaveplan/install-agent-skills";
|
||||
|
||||
try {
|
||||
const manifest = await loadBundledManifest({
|
||||
manifestPath: "/tmp/test-fixture-manifest.json",
|
||||
});
|
||||
for (const skill of manifest.skills) {
|
||||
console.log(`${skill.id}@${skill.version} (${skill.files.length} files)`);
|
||||
}
|
||||
} catch (err) {
|
||||
if (
|
||||
err instanceof InstallSkillsError &&
|
||||
err.code === "INSTALL_SKILLS.MANIFEST_INVALID"
|
||||
) {
|
||||
console.error("Bundle is broken — rebuild via build-skills-bundle.ts");
|
||||
process.exit(2);
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `loadBundledManifest(options?: LoadOptions): Promise<BundledManifest>`
|
||||
- `interface LoadOptions` — `{ manifestPath?: string }`.
|
||||
- `BundledManifest` — `{ schemaVersion: 1, skills: SkillEntry[] }`.
|
||||
- `SkillEntry` — `{ id, version, dir, files }`.
|
||||
- `BundledManifestSchema` — Zod schema, exported for advanced reuse.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The default manifest path is resolved via `import.meta.url` so the loader
|
||||
works correctly under ESM with no fallback to `__dirname` — the package
|
||||
ships ESM-only and `import.meta.url` is always available. Schema
|
||||
violations carry `context.issues` (the Zod issue list) plus
|
||||
`context.path` so error reporters can show field-level breakdowns.
|
||||
Read failures (file missing, permission denied) and parse failures
|
||||
(truncated/garbage JSON) get distinct `messageKey` values
|
||||
(`unreadable`, `unparseable`, `invalid`) but share the same code so
|
||||
consumers don't need three handlers.
|
||||
Reference in New Issue
Block a user