Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 42 additions & 77 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,95 +1,60 @@
# cate-extensions

Extensions for [Cate](https://github.com/0-AI-UG/cate). Each folder under
`extensions/` is one extension, published to the catalog Cate ships by default:

```
https://github.com/0-AI-UG/cate-extensions/releases/download/catalog/index.json
```
Extensions for [Cate](https://github.com/0-AI-UG/cate). One folder per extension
under `extensions/`, published to the catalog Cate ships by default.

## Extensions

| Id | Shape | What it is |
| --- | --- | --- |
| `cate.aisession` | frontend-only | Read-only chat viewer for AI coding-agent session files: drop a session `.jsonl` onto the panel. |
| `cate.excalidraw` | frontend-only | The Excalidraw whiteboard as a canvas panel, themed and autosaved per panel. |
| `cate.mcp` | server-backed | MCP server manager: configure and supervise servers in `.cate/mcp.json`, explore tools, one aggregated `/mcp` endpoint. |
| `cate.mermaid` | frontend-only | Split-pane Mermaid editor with live render, per-panel autosave, SVG/PNG export. |
| `cate.sqlite` | server-backed | Read-only SQLite browser for workspace databases (bundled WASM engine, nothing installed or spawned). |
| `cate.usage` | server-backed | Agent usage and cost dashboard powered by ccusage. |

Nine more are url-mode: the manifest is a single `url` and Cate loads that web
app in the panel, signed in with the user's own session. No build, no server, no
`cate.*` bridge.

| Id | Loads |
| --- | --- |
| `cate.confluence` | https://home.atlassian.com/ |
| `cate.discord` | https://discord.com/app |
| `cate.dynamics365` | https://www.office.com/apps |
| `cate.hubspot` | https://app.hubspot.com/ |
| `cate.jira` | https://home.atlassian.com/ |
| `cate.pipedrive` | https://app.pipedrive.com/ |
| `cate.salesforce` | https://login.salesforce.com/ |
| `cate.slack` | https://app.slack.com/client |
| `cate.zohocrm` | https://crm.zoho.com/crm/ShowHomePage.do |
- **AI** — `cate.aisession` (session file viewer), `cate.mcp` (MCP server
manager), `cate.usage` (agent usage and cost)
- **Data** — `cate.sqlite` (read-only SQLite browser)
- **Design** — `cate.excalidraw` (whiteboard), `cate.mermaid` (diagram editor)
- **Productivity** — `cate.confluence`, `cate.jira`
- **Communication** — `cate.discord`, `cate.slack`
- **Sales & CRM** — `cate.dynamics365`, `cate.hubspot`, `cate.pipedrive`,
`cate.salesforce`, `cate.zohocrm`
- **Development** — `cate.frontendkit`, `cate.kitchensink` (reference apps,
`"dev": true`, sideload only)

Two more folders are reference implementations, not products. They carry
`"dev": true` in their manifest, so `gen-catalog.mjs` leaves them out of the
published catalog and you only get them by sideloading:
The CRM, chat and docs ones are url-mode: the manifest is a single `url`, so
there is no build, no server and no `cate.*` bridge.

| Id | Shape | What it is |
| --- | --- | --- |
| `cate.frontendkit` | frontend-only | Smallest useful extension: static assets, no server, no build step. |
| `cate.kitchensink` | server-backed | Exercises the host API: most `cate.*` scopes, a Node server, WebSockets. |
## Layout

## Repo layout
- `extensions/<id>/` — one extension
- `kit/` — shared UI kit: tokens, theme bridge, host typings, ServiceConnection,
proxy api-client, server scaffolding (see `kit/README.md`)
- `scripts/sync-kit.mjs` — copies `kit/` into consumers' `src/_kit/`
- `scripts/gen-catalog.mjs` — builds `dist/catalog/index.json`
- `build.sh` — sync-kit, npm builds, tars artifacts, generates the catalog

```
cate-extensions/
extensions/<id>/ # one folder per extension
kit/ # shared UI kit: tokens, theme bridge, host typings,
# ServiceConnection, proxy api-client, server
# HTTP scaffolding (see kit/README.md)
scripts/sync-kit.mjs # copies kit/ into consumers' src/_kit/ (+ src/_kitserver/)
scripts/gen-catalog.mjs # builds dist/catalog/index.json
build.sh # sync-kit, npm builds, tars extensions, then gen-catalog
.github/workflows/publish.yml
dist/ # build output (gitignored)
```
## Development

## Local development

`./build.sh` writes `dist/catalog/index.json` with `file://` artifact URLs;
add its absolute path as a catalog source in Cate. Local entries re-provision
on panel open, so edits land without version bumps.

Faster for a single extension: sideload its folder via Settings, Extensions,
"Add local folder...".
- `./build.sh`, then add the absolute path of `dist/catalog/index.json` as a
catalog source in Cate. Local entries re-provision on panel open.
- Single extension: sideload its folder via Settings, Extensions, "Add local
folder...".

## Contributing

Authoring (manifest, scopes, `window.cate` API, server contract) is documented
in the Cate repo:
[`docs/extensions.md`](https://github.com/0-AI-UG/cate/blob/main/docs/extensions.md)
and
Authoring (manifest, scopes, `window.cate` API, server contract) lives in the
Cate repo: [`docs/extensions.md`](https://github.com/0-AI-UG/cate/blob/main/docs/extensions.md),
[`skills/cate-extension/SKILL.md`](https://github.com/0-AI-UG/cate/blob/main/skills/cate-extension/SKILL.md).
In this repo:

- `extensions/<id>/` with a `manifest.json`; the README's first line is the
catalog description fallback.
- With a `build` script in `package.json`, `build.sh` compiles it and the
artifact ships only `manifest.json` + `dist/`; otherwise the folder ships
as-is.
- Kit consumers: add the id in `scripts/sync-kit.mjs`, run it, commit the
synced `src/_kit/` (never edit it directly). `--check` reports stale copies
without writing.
- A reference or work-in-progress extension that should not reach users gets
`"dev": true`; the catalog skips it and it stays sideload-only.
Here:

- `extensions/<id>/` with `manifest.json`; a README's first line is the catalog
description fallback.
- `category` in the manifest: `ai`, `development`, `data`, `design`,
`productivity`, `communication`, `sales`, `other`. Pick by what it is for, not
how it is built. The list stays short; use `other` rather than adding one.
- With a `build` script, the artifact ships `manifest.json` + `dist/`;
otherwise the folder as-is.
- Kit consumers: add the id in `scripts/sync-kit.mjs`, run it, commit
`src/_kit/` (never edit it directly). `--check` reports stale copies.
- Not meant for users yet: `"dev": true` keeps it out of the catalog.
- `./build.sh` must pass; bump `version` for every published change.

## Publishing

PR CI validates `./build.sh`; merge to `main` rebuilds against the rolling
`catalog` release and uploads `index.json` plus the artifact tarballs as its
assets.
PR CI runs `./build.sh`; merging to `main` rebuilds and uploads `index.json`
plus the artifact tarballs to the rolling `catalog` release.
1 change: 1 addition & 0 deletions extensions/cate.aisession/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"id": "cate.aisession",
"name": "AI Session Viewer",
"version": "1.1.0",
"category": "ai",
"frontend": "dist/index.html",
"description": "Drop a Claude Code, Codex, or pi session file to read it back as a chat.",
"panels": [
Expand Down
1 change: 1 addition & 0 deletions extensions/cate.confluence/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"id": "cate.confluence",
"name": "Confluence",
"version": "1.0.0",
"category": "productivity",
"description": "Confluence as a canvas panel. Points a panel at Atlassian Home in the extension's own persistent session, so you stay signed in across restarts and can keep your team's docs next to your code.",
"url": "https://home.atlassian.com/",
"panels": [
Expand Down
1 change: 1 addition & 0 deletions extensions/cate.discord/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"id": "cate.discord",
"name": "Discord",
"version": "1.0.0",
"category": "communication",
"description": "Discord as a canvas panel. Points a panel at the Discord web app in the extension's own persistent session, so you stay signed in across restarts and can keep a chat next to your code.",
"url": "https://discord.com/app",
"panels": [
Expand Down
1 change: 1 addition & 0 deletions extensions/cate.dynamics365/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"id": "cate.dynamics365",
"name": "Microsoft Dynamics 365",
"version": "1.0.0",
"category": "sales",
"description": "Dynamics 365 as a canvas panel. Points a panel at the Microsoft 365 app launcher in the extension's own persistent session, so you stay signed in across restarts and can keep your CRM next to your code.",
"url": "https://www.office.com/apps",
"panels": [
Expand Down
1 change: 1 addition & 0 deletions extensions/cate.excalidraw/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"id": "cate.excalidraw",
"name": "Excalidraw",
"version": "1.0.1",
"category": "design",
"description": "The Excalidraw whiteboard, running as a panel on the Cate canvas. Drawings autosave per panel.",
"frontend": "dist/index.html",
"panels": [
Expand Down
1 change: 1 addition & 0 deletions extensions/cate.frontendkit/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"id": "cate.frontendkit",
"name": "Frontend Kit",
"version": "1.0.0",
"category": "development",
"dev": true,
"frontend": "index.html",
"panels": [
Expand Down
1 change: 1 addition & 0 deletions extensions/cate.hubspot/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"id": "cate.hubspot",
"name": "HubSpot",
"version": "1.0.0",
"category": "sales",
"description": "HubSpot as a canvas panel. Points a panel at the HubSpot web app in the extension's own persistent session, so you stay signed in across restarts and can keep your pipeline next to your code.",
"url": "https://app.hubspot.com/",
"panels": [
Expand Down
1 change: 1 addition & 0 deletions extensions/cate.jira/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"id": "cate.jira",
"name": "Jira",
"version": "1.0.0",
"category": "productivity",
"description": "Jira as a canvas panel. Points a panel at Atlassian Home in the extension's own persistent session, so you stay signed in across restarts and can keep your board next to your code.",
"url": "https://home.atlassian.com/",
"panels": [
Expand Down
1 change: 1 addition & 0 deletions extensions/cate.kitchensink/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"id": "cate.kitchensink",
"name": "Kitchen Sink",
"version": "1.0.0",
"category": "development",
"dev": true,
"panels": [{ "id": "main", "label": "Kitchen Sink" }],
"server": {
Expand Down
1 change: 1 addition & 0 deletions extensions/cate.mcp/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"id": "cate.mcp",
"name": "MCP Servers",
"version": "1.3.1",
"category": "ai",
"description": "Native MCP server manager. Configure stdio and remote MCP servers in .cate/mcp.json, supervise them with health checks and auto-restart, browse their tools/resources/prompts, invoke tools from a playground, discover servers in the official MCP registry, and expose everything through one aggregated MCP endpoint any client can connect to.",
"panels": [
{
Expand Down
1 change: 1 addition & 0 deletions extensions/cate.mermaid/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"id": "cate.mermaid",
"name": "Mermaid",
"version": "1.1.0",
"category": "design",
"description": "A split-pane Mermaid diagram editor: text source on the left, live-rendered diagram on the right, resizable divider between. Theme picker, autosaves per panel, exports SVG and PNG.",
"frontend": "dist/index.html",
"panels": [
Expand Down
1 change: 1 addition & 0 deletions extensions/cate.pipedrive/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"id": "cate.pipedrive",
"name": "Pipedrive",
"version": "1.0.0",
"category": "sales",
"description": "Pipedrive as a canvas panel. Points a panel at the Pipedrive web app in the extension's own persistent session, so you stay signed in across restarts and can keep your deal pipeline next to your code.",
"url": "https://app.pipedrive.com/",
"panels": [
Expand Down
1 change: 1 addition & 0 deletions extensions/cate.salesforce/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"id": "cate.salesforce",
"name": "Salesforce",
"version": "1.0.0",
"category": "sales",
"description": "Salesforce as a canvas panel. Points a panel at the Salesforce login gateway in the extension's own persistent session, so you stay signed in across restarts and can keep your org next to your code.",
"url": "https://login.salesforce.com/",
"panels": [
Expand Down
1 change: 1 addition & 0 deletions extensions/cate.slack/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"id": "cate.slack",
"name": "Slack",
"version": "1.0.0",
"category": "communication",
"description": "Slack as a canvas panel. Points a panel at the Slack web client in the extension's own persistent session, so you stay signed in across restarts and can keep a channel next to your code.",
"url": "https://app.slack.com/client",
"panels": [
Expand Down
1 change: 1 addition & 0 deletions extensions/cate.sqlite/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"id": "cate.sqlite",
"name": "SQLite",
"version": "1.1.0",
"category": "data",
"description": "Browse and query the SQLite databases in your workspace, right on the Cate canvas. Self-contained: reads .db / .sqlite / .sqlite3 files with a bundled WASM engine, so nothing is installed or spawned. Lists tables and views, shows sortable paginated rows, and runs read-only SQL.",
"panels": [
{
Expand Down
1 change: 1 addition & 0 deletions extensions/cate.usage/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"id": "cate.usage",
"name": "Agent Usage",
"version": "1.1.0",
"category": "ai",
"description": "Agent usage and cost dashboard powered by ccusage. Reads the local Claude Code data (~/.claude) on the machine running the extension server and shows cost and tokens for today, this week, this month, and everything still on disk, a daily cost/token timeline, and a per-model cost split. No data leaves the machine.",
"panels": [
{
Expand Down
1 change: 1 addition & 0 deletions extensions/cate.zohocrm/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"id": "cate.zohocrm",
"name": "Zoho CRM",
"version": "1.0.0",
"category": "sales",
"description": "Zoho CRM as a canvas panel. Points a panel at the Zoho CRM home in the extension's own persistent session, so you stay signed in across restarts and can keep your accounts next to your code.",
"url": "https://crm.zoho.com/crm/ShowHomePage.do",
"panels": [
Expand Down
25 changes: 24 additions & 1 deletion scripts/gen-catalog.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
//
// Dependency-free. Scans extensions/<id>/manifest.json, and for each extension
// reads the already-built artifact at dist/artifacts/<id>-<version>.tgz,
// computes its sha256, and emits a catalog entry.
// computes its sha256, and emits a catalog entry. A manifest whose `category`
// isn't one Cate knows is a hard error (see CATEGORIES).
//
// artifactUrl:
// - ${CATALOG_BASE_URL}/<id>-<version>.tgz when CATALOG_BASE_URL is set
Expand Down Expand Up @@ -32,6 +33,20 @@ const CATALOG_DIR = join(DIST_DIR, "catalog");

const baseUrl = (process.env.CATALOG_BASE_URL || "").replace(/\/+$/, "");

// Functional categories Cate's catalog UI filters by — must stay in sync with
// EXTENSION_CATEGORIES in cate/src/shared/extensions.ts. Cate silently files an
// unknown category under "Other", so catch typos here instead.
const CATEGORIES = [
"ai",
"development",
"data",
"design",
"productivity",
"communication",
"sales",
"other",
];

// First line of a README, or undefined.
function readmeFirstLine(dir) {
const p = join(dir, "README.md");
Expand Down Expand Up @@ -71,6 +86,14 @@ for (const entry of entries) {
continue;
}

if (manifest.category === undefined) {
console.warn(`${id}: no category — it will show up under "Other" in the catalog`);
} else if (!CATEGORIES.includes(manifest.category)) {
throw new Error(
`${id}: unknown category "${manifest.category}" (expected one of ${CATEGORIES.join(", ")})`,
);
}

const artifactName = `${id}-${version}.tgz`;
const artifactPath = join(ARTIFACT_DIR, artifactName);
if (!existsSync(artifactPath) || !statSync(artifactPath).isFile()) {
Expand Down
Loading