registry, verdaccio, portainer: full nox modules (ADR 0044/0046)
registry (docker v2): catalog/tags/delete tools, emits image.pushed (a build's image is now pullable). verdaccio (npm): list/info tools, emits package.published. portainer: endpoints/stacks/containers tools — tools-only, since its only events are the underlying containers' lifecycle, which the host owns. Typecheck; manifests parse.
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
// registry's tools — moved here from the shared sdk (novox/hq ADR 0044), importing registry's own
|
||||
// client. They return structured data; the mesh serves them through the sdk's tool harness.
|
||||
|
||||
import { registerModuleTools, type ToolDefinition } from "@novox/mesh-sdk/tools";
|
||||
import { RegistryClient } from "../client.js";
|
||||
|
||||
export function getRegistryTools(registry: RegistryClient): ToolDefinition[] {
|
||||
return [
|
||||
{
|
||||
name: "registry_list",
|
||||
description: "List every repository in the Docker registry (the catalog).",
|
||||
input: {},
|
||||
run: async () => {
|
||||
const repositories = await registry.listRepositories();
|
||||
return { count: repositories.length, repositories };
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "registry_tags",
|
||||
description: "List the tags of one repository in the Docker registry.",
|
||||
input: { repo: { type: "string", description: "the repository name, e.g. 'novox/mesh'" } },
|
||||
run: async (args) => {
|
||||
const repo = String(args.repo);
|
||||
const tags = await registry.listTags(repo);
|
||||
return { repo, count: tags.length, tags };
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "registry_delete_image",
|
||||
description:
|
||||
"Delete an image tag from the registry (DESTRUCTIVE). Removes the manifest; storage is reclaimed by garbage collection later. Requires confirm: true.",
|
||||
input: {
|
||||
repo: { type: "string", description: "the repository name, e.g. 'novox/mesh'" },
|
||||
tag: { type: "string", description: "the tag to delete, e.g. 'latest'" },
|
||||
confirm: { type: "boolean", description: "must be true to actually delete" },
|
||||
},
|
||||
run: async (args) => {
|
||||
const repo = String(args.repo);
|
||||
const tag = String(args.tag);
|
||||
if (args.confirm !== true) {
|
||||
return { deleted: false, reason: "confirm must be true to delete an image" };
|
||||
}
|
||||
const digest = await registry.getManifestDigest(repo, tag);
|
||||
await registry.deleteManifest(repo, digest);
|
||||
return { deleted: true, repo, tag, digest, note: "run registry garbage collection to reclaim storage" };
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
// The tools exist only when a registry URL is configured; otherwise registry contributes none
|
||||
// rather than failing the whole runtime.
|
||||
registerModuleTools("registry", (env) => {
|
||||
try {
|
||||
return getRegistryTools(RegistryClient.fromEnv(env));
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user