Official
market
The plugin marketplace: browse, install through an agent's scan, update and publish plugins, and the marketplace tools of agents in the Plugins workspace.
The app opens the listing; nothing installs until an agent in your Plugins workspace has read the files and you enable the plugin. In a terminal: cvg install convergence/market@0.1.0
Permissions in 0.1.0
Files
remote.ts6.6 KB
// The shapes the marketplace host answers take, parsed at the host
// boundary. The registry is free-form JSON, so every schema stays loose:
// only the fields the page reads are named, everything else passes through
// untyped. A parse failure surfaces as the section's error, never a cast.
import * as z from "zod";
const versionSchema = z.looseObject({
version: z.string(),
permissions: z.unknown().optional(),
yanked: z.boolean().optional(),
malicious: z.boolean().optional(),
publishedAt: z.string().optional(),
});
export type ListingVersion = z.infer<typeof versionSchema>;
const installedSchema = z.looseObject({
version: z.string(),
enabled: z.boolean(),
folder: z.string(),
});
export type MarketInstalled = z.infer<typeof installedSchema>;
export const listingSchema = z.looseObject({
id: z.string(),
name: z.string().optional(),
description: z.string().optional(),
publisher: z
.looseObject({ name: z.string().optional(), displayName: z.string().optional(), verified: z.boolean().optional() })
.optional(),
visibility: z.string().optional(),
latestVersion: z.string().optional(),
downloads: z.unknown().optional(),
rating: z.looseObject({ average: z.number().optional(), count: z.number().optional() }).optional(),
createdAt: z.string().optional(),
basedOn: z.looseObject({ id: z.string(), version: z.string() }).nullable().optional(),
mods: z.array(z.looseObject({ id: z.string(), name: z.string().optional() })).optional(),
permissions: z.unknown().optional(),
versions: z.array(versionSchema).optional(),
installed: installedSchema.nullable().optional(),
});
export type Listing = z.infer<typeof listingSchema>;
export const searchAnswerSchema = z.looseObject({
results: z.array(listingSchema).optional(),
total: z.number().optional(),
});
export type SearchAnswer = z.infer<typeof searchAnswerSchema>;
export const releaseSchema = z.looseObject({
id: z.string().optional(),
version: z.string().optional(),
files: z
.array(
z.looseObject({
path: z.string(),
size: z.number().optional(),
binary: z.boolean().optional(),
executable: z.boolean().optional(),
}),
)
.optional(),
});
export type MarketRelease = z.infer<typeof releaseSchema>;
export const releaseFileSchema = z.looseObject({
path: z.string().optional(),
size: z.number().optional(),
text: z.string().optional(),
truncated: z.boolean().optional(),
binary: z.boolean().optional(),
});
export type MarketReleaseFile = z.infer<typeof releaseFileSchema>;
export interface MarketComment {
readonly id?: string;
readonly user?: { readonly name?: string };
readonly body?: string;
readonly stars?: number;
readonly createdAt?: string;
readonly pluginVersion?: string;
readonly replies?: readonly MarketComment[];
}
const commentSchema: z.ZodType<MarketComment> = z.looseObject({
id: z.string().optional(),
user: z.looseObject({ name: z.string().optional() }).optional(),
body: z.string().optional(),
stars: z.number().optional(),
createdAt: z.string().optional(),
pluginVersion: z.string().optional(),
replies: z.array(z.lazy(() => commentSchema)).optional(),
});
export const commentsSchema = z.looseObject({ threads: z.array(commentSchema).optional() });
export type MarketComments = z.infer<typeof commentsSchema>;
export const categoriesSchema = z.looseObject({
categories: z.array(z.looseObject({ id: z.string(), title: z.string() })),
});
export type MarketCategories = z.infer<typeof categoriesSchema>;
export const accountSchema = z.union([
z.looseObject({
signedIn: z.literal(false),
registry: z.string(),
error: z.string().optional(),
expired: z.boolean().optional(),
}),
z.looseObject({
signedIn: z.literal(true),
registry: z.string(),
account: z
.looseObject({
publisher: z.looseObject({ name: z.string().optional() }).optional(),
user: z.looseObject({ email: z.string().optional() }).optional(),
})
.optional(),
}),
]);
export type MarketAccount = z.infer<typeof accountSchema>;
export const updateItemSchema = z.object({
id: z.string(),
folder: z.string(),
installed: z.string().optional(),
latest: z.string().optional(),
official: z.boolean().optional(),
direct: z.boolean().optional(),
malicious: z.boolean().optional(),
yanked: z.boolean().optional(),
reason: z.string().optional(),
});
export type MarketUpdateItem = z.infer<typeof updateItemSchema>;
export const updatesSchema = z.looseObject({ updates: z.array(updateItemSchema).optional() });
export const loginSchema = z.looseObject({
userCode: z.string(),
verificationUri: z.string(),
verificationUriComplete: z.string().nullable().optional(),
});
export type MarketLogin = z.infer<typeof loginSchema>;
export const draftPluginSchema = z.looseObject({
name: z.string(),
id: z.string(),
version: z.string().optional(),
official: z.boolean().optional(),
changed: z.boolean().optional(),
suggested: z.boolean().optional(),
reasons: z.array(z.string()).optional(),
});
export type DraftPlugin = z.infer<typeof draftPluginSchema>;
export const bugDraftSchema = z.looseObject({
plugins: z.array(draftPluginSchema).optional(),
note: z.string().optional(),
registry: z.string().optional(),
signedIn: z.boolean().optional(),
appVersion: z.string().optional(),
});
export type BugDraft = z.infer<typeof bugDraftSchema>;
export const attachmentSchema = z.looseObject({
id: z.string(),
kind: z.string(),
title: z.string(),
name: z.string(),
size: z.number(),
defaultOn: z.boolean().optional(),
removed: z.array(z.looseObject({ line: z.number(), kind: z.string() })).optional(),
text: z.string().optional(),
path: z.string().optional(),
});
export type BugAttachment = z.infer<typeof attachmentSchema>;
export const bugPreviewSchema = z.looseObject({
plugins: z.array(z.looseObject({ folder: z.string(), id: z.string() })).optional(),
attachments: z.array(attachmentSchema).optional(),
note: z.string().optional(),
});
export type BugPreview = z.infer<typeof bugPreviewSchema>;
export const sentReportSchema = z.looseObject({
id: z.string(),
number: z.number(),
text: z.string(),
plugins: z.array(z.looseObject({ id: z.string() })).optional(),
});
export type SentReport = z.infer<typeof sentReportSchema>;
export const bugReportsSchema = z.looseObject({ reports: z.array(sentReportSchema).optional() });
// The settings a release declares (`plugin.json` `contributes.settings`),
// for scopes a setting fills (MARKETPLACE.md §15.3 rule 6).
export const settingsContributesSchema = z.looseObject({
contributes: z.looseObject({ settings: z.unknown() }).optional(),
});Versions
| Version | Published | Plugin API | Size | Permissions | Status |
|---|---|---|---|---|---|
| 0.1.0latest | Oct 5, 2026 | >=2 <3 | 44.9 KB | 6 permissions | Listed |
No comments yet.