Official
settings
Built-in settings UI (JavaScript UI plugin).
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/settings@0.2.0
Permissions in 0.2.0
Files
main.ts2.2 KB
// Register the settings page, then the convergence/settings service, then
// the host events that change what the page shows. The page loads the first
// time it is opened, not at activation.
import * as Effect from "effect/Effect";
import * as Stream from "effect/Stream";
import { Events, Services, Views, runPlugin } from "convergence/effect";
import type { HostEvents } from "convergence";
import { SettingsPage } from "./controller.ts";
import { Settings as SettingsService } from "./contract.ts";
import { renderSettings } from "./views/page.ts";
const program = Effect.gen(function* () {
const page = yield* SettingsPage;
const views = yield* Views;
page.views.push(
yield* views.slot("center", (ctx) => renderSettings(ctx, page), {
on: [
"app_state",
"agents_changed",
"plugins_changed",
"updates_changed",
"keybindings_changed",
"plugin_settings_changed",
],
}),
);
const services = yield* Services;
yield* services.provide(SettingsService, {
showShortcuts: ({ query }) => page.showShortcuts(query),
});
const events = yield* Events;
// Every listener fires its effect as its own fork, as the original's
// async listeners did; a failure is logged, not propagated.
const follow = <E extends keyof HostEvents, R>(
name: E,
run: (event: HostEvents[E]) => Effect.Effect<void, unknown, R>,
) =>
events.stream(name).pipe(
Stream.runForEach((event) => Effect.forkScoped(run(event).pipe(Effect.ignore), { startImmediately: true })),
Effect.ignore,
Effect.forkScoped({ startImmediately: true }),
);
yield* follow("keybindings_changed", () => page.loadKeys());
yield* follow("plugin_settings_changed", (event) =>
page.state.sections[event.plugin] ? page.loadSection(event.plugin) : Effect.void,
);
yield* follow("agents_changed", () => page.load());
yield* follow("plugins_changed", () => page.load());
// A plugin enabled or turned off, or a grant given or taken back.
yield* follow("access_changed", () => page.load());
yield* follow("workspaces_changed", () => page.load());
yield* follow("updates_changed", () => page.refreshUpdates());
});
export const activate = runPlugin(SettingsPage.layer, program);Versions
| Version | Published | Plugin API | Size | Permissions | Status |
|---|---|---|---|---|---|
| 0.2.0latest | Oct 5, 2026 | >=2 <3 | 24.7 KB | 7 permissions | Listed |
No comments yet.