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

  • Marketplace marketOfficial onlyUses the marketplace APIs. Only official plugins can have it.Search, read, install, update and publish marketplace plugins, and sign in to the marketplace
  • Manage plugins plugins.manageOfficial onlyReloads and enables plugins. Only official plugins can have it.Ask for the enable card of a plugin an agent installed
  • Control chats chats.controlHighCreates chats, sends prompts and cancels runs.Open the chat in the Plugins workspace where an agent scans, installs or updates a plugin
  • Provide agent tools tools.provideMediumGives tools to agents.Give agents in the Plugins workspace the marketplace tools
  • Read chats chats.readMediumReads your transcripts and chat lists.Find the agent, model and effort last used in the Plugins workspace
  • Show panels ui.slotsLowShows views in the listed parts of the window.Show the marketplace button, with its update count, and the marketplace pageSlots: railcenter

Files

main.ts2.8 KB
// The marketplace (convergence/market, MARKETPLACE.md §10.3): browse and
// search, a listing page with its files, permissions and comments, Install
// through a scan chat in the Plugins workspace, update notices, sign-in, and
// the tools agents in the Plugins workspace use.
//
// Nothing here enables, publishes or reports by itself. Those are native
// cards the app draws (the enable card, the publish row, the report card,
// the bug report's send card and the attach card); this plugin only asks
// for them.
import * as Effect from "effect/Effect";
import * as Stream from "effect/Stream";
import { App, Commands, Events, Views, runPlugin } from "convergence/effect";
import type { PluginServices } from "convergence/effect";
import { MarketState, ROUTE } from "./state.ts";
import { controller } from "./controller.ts";
import { registerMarketTools } from "./tools.ts";
import { renderCenter, renderRail } from "./views.ts";

export { ROUTE };

const follow = <E>(stream: Stream.Stream<E>, handle: (event: E) => Effect.Effect<void, unknown, PluginServices>) =>
  stream.pipe(Stream.mapEffect(handle, { concurrency: "unbounded" }), Stream.runDrain, Effect.forkScoped);

const program = Effect.gen(function* () {
  const market = yield* controller();
  const views = yield* Views;
  market.state.views.push(yield* views.slot("center", (ctx) => renderCenter(ctx, market), { on: ["app_state"] }));
  market.state.views.push(
    yield* views.slot("rail", (ctx) => renderRail(ctx, market), { on: ["app_state"], order: 40 }),
  );
  const app = yield* App;
  const commands = yield* Commands;
  yield* commands.register("market.open", app.route(ROUTE));
  // "Report a bug" (§14.1): the palette lists it; Settings and the Help
  // menu reach the same form through `host/market.open_bug_form`.
  yield* commands.register("market.reportBug", market.openBugForm());
  yield* registerMarketTools();
  const events = yield* Events;
  yield* follow(events.stream("market_bug_form"), market.onBugForm);
  yield* follow(events.stream("market_bug_report"), market.onBugReport);
  yield* follow(events.stream("security_resolved"), (event) =>
    Effect.sync(() => market.onSecurityResolved(event.id, event.outcome)),
  );
  yield* follow(events.stream("market_changed"), (event) => Effect.sync(() => market.onMarketChanged(event.updates)));
  yield* follow(events.stream("market_account"), market.onMarketAccount);
  // A listing installed, enabled or removed: its Install row changes.
  yield* follow(events.stream("plugins_changed"), () => market.refreshListing());
  yield* follow(events.stream("access_changed"), () => market.refreshListing());
  yield* follow(app.changes, market.followApp);
  yield* Effect.forkScoped(market.loadUpdates(), { startImmediately: true });
  yield* market.followApp(yield* app.state);
});

export const activate = runPlugin(MarketState.layer, program);

Versions

VersionPublishedPlugin APISizePermissionsStatus
0.1.0latestOct 5, 2026>=2 <344.9 KB6 permissionsListed

Reviews and comments

0 threads · 0 reviews

No comments yet.