Initial Commit
This commit is contained in:
91
packages/devtools/tooling/installer/src/manifest/manifest.md
Normal file
91
packages/devtools/tooling/installer/src/manifest/manifest.md
Normal file
@@ -0,0 +1,91 @@
|
||||
# `manifest`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## Purpose
|
||||
|
||||
Loads and validates plugin manifest files. Every Suaveplan installer plugin
|
||||
ships a `manifest.json` next to its entry module; this module exposes
|
||||
`loadManifest(packagePath)` and `validateManifest(raw)` which both surface
|
||||
schema violations as `InstallerError(INSTALLER.PLUGIN_INVALID_MANIFEST)`
|
||||
with the underlying Zod error attached as `cause`. The host calls
|
||||
`loadManifest` once per plugin during discovery; the result is cached on
|
||||
the `DiscoveredPlugin` record returned to callers.
|
||||
|
||||
## Features
|
||||
|
||||
- Backed by `PluginManifestSchema` (Zod) which enforces required fields:
|
||||
`id`, semver `version`, non-empty `description`, relative `entry`,
|
||||
`engines: Record<string, string>`, and `assets: string[]`.
|
||||
- Optional `peerInstallers: string[]` for plugins that depend on other
|
||||
installers being present at runtime.
|
||||
- Distinguishes parse errors from schema errors but emits the same code
|
||||
(`PLUGIN_INVALID_MANIFEST`) so consumers don't have to handle three
|
||||
variants.
|
||||
- Pure validator — `validateManifest(raw)` is synchronous and side-effect
|
||||
free, so plugins can be validated before any disk I/O happens.
|
||||
|
||||
## Basic Example
|
||||
|
||||
```ts
|
||||
import { loadManifest } from "@suaveplan/installer";
|
||||
|
||||
const manifest = await loadManifest(
|
||||
"/path/to/node_modules/@suaveplan/install-agent-skills"
|
||||
);
|
||||
console.log(manifest.id, manifest.version);
|
||||
```
|
||||
|
||||
## Advanced Example
|
||||
|
||||
```ts
|
||||
import {
|
||||
InstallerError,
|
||||
loadManifest,
|
||||
validateManifest,
|
||||
} from "@suaveplan/installer";
|
||||
|
||||
async function safeLoad(path: string): Promise<unknown> {
|
||||
try {
|
||||
return await loadManifest(path);
|
||||
} catch (err) {
|
||||
if (
|
||||
err instanceof InstallerError &&
|
||||
err.code === "INSTALLER.PLUGIN_INVALID_MANIFEST"
|
||||
) {
|
||||
console.warn(`skipping ${path}: bad manifest`);
|
||||
return null;
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
// Standalone validation — no disk I/O:
|
||||
const valid = validateManifest({
|
||||
id: "demo",
|
||||
version: "0.1.0",
|
||||
description: "demo plugin",
|
||||
entry: "dist/index.js",
|
||||
engines: { node: ">=20" },
|
||||
assets: [],
|
||||
});
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `loadManifest(packagePath: string): Promise<PluginManifest>` —
|
||||
reads `<packagePath>/manifest.json`, parses, and validates.
|
||||
- `validateManifest(raw: unknown): PluginManifest` — pure schema check.
|
||||
- `PluginManifest` — inferred type:
|
||||
`{ id, version, description, entry, engines, assets, peerInstallers? }`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The schema uses a strict semver regex (`MAJOR.MINOR.PATCH` with optional
|
||||
`-prerelease+build`) rather than `z.string()` so prerelease ergonomics are
|
||||
explicit. Failures from `JSON.parse` are caught and re-thrown as
|
||||
`PLUGIN_INVALID_MANIFEST`, not as raw `SyntaxError`, so callers always
|
||||
have a typed `InstallerError` to switch on. The Zod error issues are
|
||||
attached via `context.issues` for downstream error reporters that want
|
||||
field-level breakdowns without re-walking the cause chain.
|
||||
Reference in New Issue
Block a user