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
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
| Version | Published | Plugin API | Size | Permissions | Status |
|---|---|---|---|---|---|
| 0.1.0latest | Oct 5, 2026 | >=2 <3 | 44.9 KB | 6 permissions | Listed |
No comments yet.