Add AgentBBS connector plugin

Declares the AgentBBS capability surface (chat, pods, arcade, ascii-live,
finger) as @logicsrc/plugin-agentbbs and registers it in the CLI registry
and CommandBoard API.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Anthony Ettinger 2026-06-12 14:31:05 +00:00
parent c23ce42948
commit 6d6c170f3e
13 changed files with 133 additions and 4 deletions

View file

@ -13,6 +13,7 @@
}, },
"dependencies": { "dependencies": {
"@logicsrc/plugin-core": "file:../../packages/plugin-core", "@logicsrc/plugin-core": "file:../../packages/plugin-core",
"@logicsrc/plugin-agentbbs": "file:../../plugins/agentbbs",
"@logicsrc/plugin-c0mpute": "file:../../plugins/c0mpute", "@logicsrc/plugin-c0mpute": "file:../../plugins/c0mpute",
"@logicsrc/plugin-coinpay": "file:../../plugins/coinpay", "@logicsrc/plugin-coinpay": "file:../../plugins/coinpay",
"@logicsrc/plugin-email-accounts": "file:../../plugins/email-accounts", "@logicsrc/plugin-email-accounts": "file:../../plugins/email-accounts",

View file

@ -47,7 +47,7 @@ describe("CommandBoard API contracts", () => {
}; };
expect(response.status).toBe(200); expect(response.status).toBe(200);
expect(body.plugins.map((plugin) => plugin.id)).toEqual(["coinpay", "ugig", "sh1pt", "c0mpute", "feed-discovery", "social-accounts", "email-accounts"]); expect(body.plugins.map((plugin) => plugin.id)).toEqual(["coinpay", "ugig", "sh1pt", "c0mpute", "feed-discovery", "social-accounts", "email-accounts", "agentbbs"]);
expect(body.plugins.find((plugin) => plugin.id === "sh1pt")).toMatchObject({ expect(body.plugins.find((plugin) => plugin.id === "sh1pt")).toMatchObject({
enabled: true, enabled: true,
capabilities: expect.arrayContaining(["projects.sync", "actions.publish", "deployments.status"]) capabilities: expect.arrayContaining(["projects.sync", "actions.publish", "deployments.status"])
@ -61,6 +61,7 @@ describe("CommandBoard API contracts", () => {
expect(body.capabilities["feeds.discover"]).toEqual(["feed-discovery"]); expect(body.capabilities["feeds.discover"]).toEqual(["feed-discovery"]);
expect(body.capabilities["social.post.publish"]).toEqual(["social-accounts"]); expect(body.capabilities["social.post.publish"]).toEqual(["social-accounts"]);
expect(body.capabilities["email.send"]).toEqual(["email-accounts"]); expect(body.capabilities["email.send"]).toEqual(["email-accounts"]);
expect(body.capabilities["pods.provision"]).toEqual(["agentbbs"]);
}); });
it("exposes communication account provider contracts", async () => { it("exposes communication account provider contracts", async () => {

View file

@ -1,6 +1,7 @@
import { createServer, type IncomingMessage, type ServerResponse } from "node:http"; import { createServer, type IncomingMessage, type ServerResponse } from "node:http";
import { pathToFileURL } from "node:url"; import { pathToFileURL } from "node:url";
import { createPluginRegistry } from "@logicsrc/plugin-core"; import { createPluginRegistry } from "@logicsrc/plugin-core";
import { agentBbsPlugin } from "@logicsrc/plugin-agentbbs";
import { c0mputePlugin } from "@logicsrc/plugin-c0mpute"; import { c0mputePlugin } from "@logicsrc/plugin-c0mpute";
import { coinPayPlugin } from "@logicsrc/plugin-coinpay"; import { coinPayPlugin } from "@logicsrc/plugin-coinpay";
import { emailAccountsPlugin, listEmailAccountProviders } from "@logicsrc/plugin-email-accounts"; import { emailAccountsPlugin, listEmailAccountProviders } from "@logicsrc/plugin-email-accounts";
@ -10,7 +11,7 @@ import { listSocialAccountProviders, socialAccountsPlugin } from "@logicsrc/plug
import { uGigPlugin } from "@logicsrc/plugin-ugig"; import { uGigPlugin } from "@logicsrc/plugin-ugig";
import { schemas, validate } from "@logicsrc/validators"; import { schemas, validate } from "@logicsrc/validators";
const registry = createPluginRegistry([coinPayPlugin, uGigPlugin, sh1ptPlugin, c0mputePlugin, feedDiscoveryPlugin, socialAccountsPlugin, emailAccountsPlugin]); const registry = createPluginRegistry([coinPayPlugin, uGigPlugin, sh1ptPlugin, c0mputePlugin, feedDiscoveryPlugin, socialAccountsPlugin, emailAccountsPlugin, agentBbsPlugin]);
const boards = [ const boards = [
{ path: "/general", title: "General", description: "CommandBoard.run general discussion." }, { path: "/general", title: "General", description: "CommandBoard.run general discussion." },

16
package-lock.json generated
View file

@ -23,6 +23,7 @@
"name": "@logicsrc/commandboard-api", "name": "@logicsrc/commandboard-api",
"version": "0.1.0", "version": "0.1.0",
"dependencies": { "dependencies": {
"@logicsrc/plugin-agentbbs": "file:../../plugins/agentbbs",
"@logicsrc/plugin-c0mpute": "file:../../plugins/c0mpute", "@logicsrc/plugin-c0mpute": "file:../../plugins/c0mpute",
"@logicsrc/plugin-coinpay": "file:../../plugins/coinpay", "@logicsrc/plugin-coinpay": "file:../../plugins/coinpay",
"@logicsrc/plugin-core": "file:../../packages/plugin-core", "@logicsrc/plugin-core": "file:../../packages/plugin-core",
@ -1442,6 +1443,10 @@
"resolved": "apps/commandboard-web", "resolved": "apps/commandboard-web",
"link": true "link": true
}, },
"node_modules/@logicsrc/plugin-agentbbs": {
"resolved": "plugins/agentbbs",
"link": true
},
"node_modules/@logicsrc/plugin-c0mpute": { "node_modules/@logicsrc/plugin-c0mpute": {
"resolved": "plugins/c0mpute", "resolved": "plugins/c0mpute",
"link": true "link": true
@ -6068,6 +6073,7 @@
"version": "0.1.0", "version": "0.1.0",
"dependencies": { "dependencies": {
"@logicsrc/account-core": "file:../account-core", "@logicsrc/account-core": "file:../account-core",
"@logicsrc/plugin-agentbbs": "file:../../plugins/agentbbs",
"@logicsrc/plugin-coinpay": "file:../../plugins/coinpay", "@logicsrc/plugin-coinpay": "file:../../plugins/coinpay",
"@logicsrc/plugin-core": "file:../plugin-core", "@logicsrc/plugin-core": "file:../plugin-core",
"@logicsrc/plugin-email-accounts": "file:../../plugins/email-accounts", "@logicsrc/plugin-email-accounts": "file:../../plugins/email-accounts",
@ -6148,6 +6154,16 @@
"vitest": "^4.0.8" "vitest": "^4.0.8"
} }
}, },
"plugins/agentbbs": {
"name": "@logicsrc/plugin-agentbbs",
"version": "0.1.0",
"dependencies": {
"@logicsrc/plugin-core": "file:../../packages/plugin-core"
},
"devDependencies": {
"vitest": "^4.0.8"
}
},
"plugins/c0mpute": { "plugins/c0mpute": {
"name": "@logicsrc/plugin-c0mpute", "name": "@logicsrc/plugin-c0mpute",
"version": "0.1.0", "version": "0.1.0",

View file

@ -12,7 +12,7 @@
"apps/*" "apps/*"
], ],
"scripts": { "scripts": {
"build": "npm --workspace @logicsrc/schemas run build && npm --workspace @logicsrc/validators run build && npm --workspace @logicsrc/sdk run build && npm --workspace @logicsrc/plugin-core run build && npm --workspace @logicsrc/account-core run build && npm --workspace @logicsrc/plugin-coinpay run build && npm --workspace @logicsrc/plugin-ugig run build && npm --workspace @logicsrc/plugin-sh1pt run build && npm --workspace @logicsrc/plugin-c0mpute run build && npm --workspace @logicsrc/plugin-feed-discovery run build && npm --workspace @logicsrc/plugin-social-accounts run build && npm --workspace @logicsrc/plugin-email-accounts run build && npm --workspace @logicsrc/tui run build && npm --workspace @logicsrc/cli run build && npm --workspace @profullstack/logicsrc-mcp run build && npm --workspace @logicsrc/commandboard-api run build && npm --workspace @logicsrc/commandboard-web run build && npm --workspace @logicsrc/web run build", "build": "npm --workspace @logicsrc/schemas run build && npm --workspace @logicsrc/validators run build && npm --workspace @logicsrc/sdk run build && npm --workspace @logicsrc/plugin-core run build && npm --workspace @logicsrc/account-core run build && npm --workspace @logicsrc/plugin-coinpay run build && npm --workspace @logicsrc/plugin-ugig run build && npm --workspace @logicsrc/plugin-sh1pt run build && npm --workspace @logicsrc/plugin-c0mpute run build && npm --workspace @logicsrc/plugin-feed-discovery run build && npm --workspace @logicsrc/plugin-social-accounts run build && npm --workspace @logicsrc/plugin-email-accounts run build && npm --workspace @logicsrc/plugin-agentbbs run build && npm --workspace @logicsrc/tui run build && npm --workspace @logicsrc/cli run build && npm --workspace @profullstack/logicsrc-mcp run build && npm --workspace @logicsrc/commandboard-api run build && npm --workspace @logicsrc/commandboard-web run build && npm --workspace @logicsrc/web run build",
"start": "npm --workspace @logicsrc/web run start", "start": "npm --workspace @logicsrc/web run start",
"test": "npm run test --workspaces --if-present", "test": "npm run test --workspaces --if-present",
"check": "npm run build && npm run test", "check": "npm run build && npm run test",

View file

@ -16,6 +16,7 @@
"dependencies": { "dependencies": {
"@logicsrc/account-core": "file:../account-core", "@logicsrc/account-core": "file:../account-core",
"@logicsrc/plugin-core": "file:../plugin-core", "@logicsrc/plugin-core": "file:../plugin-core",
"@logicsrc/plugin-agentbbs": "file:../../plugins/agentbbs",
"@logicsrc/plugin-coinpay": "file:../../plugins/coinpay", "@logicsrc/plugin-coinpay": "file:../../plugins/coinpay",
"@logicsrc/plugin-email-accounts": "file:../../plugins/email-accounts", "@logicsrc/plugin-email-accounts": "file:../../plugins/email-accounts",
"@logicsrc/plugin-feed-discovery": "file:../../plugins/feed-discovery", "@logicsrc/plugin-feed-discovery": "file:../../plugins/feed-discovery",

View file

@ -1,4 +1,5 @@
import { createPluginRegistry } from "@logicsrc/plugin-core"; import { createPluginRegistry } from "@logicsrc/plugin-core";
import { agentBbsPlugin } from "@logicsrc/plugin-agentbbs";
import { coinPayPlugin } from "@logicsrc/plugin-coinpay"; import { coinPayPlugin } from "@logicsrc/plugin-coinpay";
import { emailAccountsPlugin } from "@logicsrc/plugin-email-accounts"; import { emailAccountsPlugin } from "@logicsrc/plugin-email-accounts";
import { feedDiscoveryPlugin } from "@logicsrc/plugin-feed-discovery"; import { feedDiscoveryPlugin } from "@logicsrc/plugin-feed-discovery";
@ -6,5 +7,5 @@ import { socialAccountsPlugin } from "@logicsrc/plugin-social-accounts";
import { uGigPlugin } from "@logicsrc/plugin-ugig"; import { uGigPlugin } from "@logicsrc/plugin-ugig";
export function defaultPluginRegistry() { export function defaultPluginRegistry() {
return createPluginRegistry([coinPayPlugin, uGigPlugin, feedDiscoveryPlugin, socialAccountsPlugin, emailAccountsPlugin]); return createPluginRegistry([coinPayPlugin, uGigPlugin, feedDiscoveryPlugin, socialAccountsPlugin, emailAccountsPlugin, agentBbsPlugin]);
} }

View file

@ -0,0 +1,22 @@
# @logicsrc/plugin-agentbbs
Connector plugin for [AgentBBS](https://github.com/profullstack/agentbbs), the BBS-over-SSH platform for humans and agents (chat, pods, arcade, finger presence, ASCII video).
The plugin declares the AgentBBS capability surface for the LogicSRC registry. It targets a running AgentBBS instance over SSH — it does not embed the Go server.
## Capabilities
- `bbs.status` — instance reachability and motd
- `chat.read` / `chat.send` — agent@ shared chat rooms
- `pods.list` / `pods.provision` / `pods.membership` — pod@ hosting, CoinPay $1/mo membership
- `arcade.list` — arcade games (DOOM et al.)
- `ascii.stream` — ascii-live video streams
- `finger.lookup` — finger@ user presence
## Configuration
| Env var | Purpose |
| --- | --- |
| `AGENTBBS_SSH_HOST` | AgentBBS host (e.g. `bbs.profullstack.com`) |
| `AGENTBBS_SSH_PORT` | SSH port (default `22`) |
| `AGENTBBS_SSH_KEY_PATH` | Identity key used to authenticate as the agent |

View file

@ -0,0 +1,18 @@
{
"name": "@logicsrc/plugin-agentbbs",
"version": "0.1.0",
"description": "AgentBBS connector plugin: BBS-over-SSH chat, pods, arcade, and finger presence.",
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"scripts": {
"build": "tsc -p tsconfig.json",
"test": "vitest run src --passWithNoTests"
},
"dependencies": {
"@logicsrc/plugin-core": "file:../../packages/plugin-core"
},
"devDependencies": {
"vitest": "^4.0.8"
}
}

View file

@ -0,0 +1,11 @@
import { describe, expect, it } from "vitest";
import { createPluginRegistry } from "@logicsrc/plugin-core";
import { agentBbsPlugin } from "./index.js";
describe("agentbbs plugin", () => {
it("registers with a valid manifest", () => {
const registry = createPluginRegistry([agentBbsPlugin]);
expect(registry.get("agentbbs")?.enabled).toBe(true);
expect(registry.snapshot().capabilities["pods.provision"]).toEqual(["agentbbs"]);
});
});

View file

@ -0,0 +1,27 @@
import type { PluginDefinition } from "@logicsrc/plugin-core";
import { agentBbsManifest } from "./manifest.js";
export const agentBbsPlugin: PluginDefinition = {
manifest: agentBbsManifest,
configDefaults: {
enabled: true,
ssh_host: "${AGENTBBS_SSH_HOST}",
ssh_port: "${AGENTBBS_SSH_PORT}",
ssh_key_path: "${AGENTBBS_SSH_KEY_PATH}",
default_route: "bbs"
},
routes: [
{ method: "GET", path: "/api/plugins/agentbbs/status", capability: "bbs.status" },
{ method: "GET", path: "/api/plugins/agentbbs/chat", capability: "chat.read" },
{ method: "POST", path: "/api/plugins/agentbbs/chat", capability: "chat.send" },
{ method: "GET", path: "/api/plugins/agentbbs/pods", capability: "pods.list" },
{ method: "POST", path: "/api/plugins/agentbbs/pods", capability: "pods.provision" },
{ method: "GET", path: "/api/plugins/agentbbs/arcade", capability: "arcade.list" },
{ method: "GET", path: "/api/plugins/agentbbs/finger/:user", capability: "finger.lookup" }
],
events: [{ event: "payment.confirmed", capability: "pods.membership" }],
permissions: ["bbs:read", "chat:send", "pods:provision"],
tuiPanels: [{ id: "agentbbs-status", title: "AgentBBS" }]
};
export { agentBbsManifest };

View file

@ -0,0 +1,22 @@
import type { PluginManifest } from "@logicsrc/plugin-core";
export const agentBbsManifest: PluginManifest = {
id: "agentbbs",
name: "AgentBBS",
version: "1.0.0",
type: ["community", "chat", "hosting"],
default: false,
capabilities: [
"bbs.status",
"chat.send",
"chat.read",
"pods.list",
"pods.provision",
"pods.membership",
"arcade.list",
"ascii.stream",
"finger.lookup"
],
commands: ["bbs", "pod", "arcade"],
env: ["AGENTBBS_SSH_HOST", "AGENTBBS_SSH_PORT", "AGENTBBS_SSH_KEY_PATH"]
};

View file

@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"rootDir": "src",
"outDir": "dist"
},
"include": ["src/**/*.ts"]
}