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
39 changes: 39 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Release

on:
push:
tags:
- "v*"

permissions:
contents: write

jobs:
dxt:
name: Build and upload pluginos.dxt
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm

- name: Install dependencies
run: npm ci

- name: Build shared
run: npm run build:shared

- name: Build mcp-server
run: npm run build -w packages/mcp-server

- name: Build DXT artifact
run: npm run build:dxt -w packages/mcp-server

- name: Upload DXT to release
uses: softprops/action-gh-release@v2
with:
files: packages/mcp-server/dist/pluginos.dxt
fail_on_unmatched_files: true
28 changes: 17 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,15 @@ PluginOS takes a fundamentally different approach:

### 1. Install for your agent

Pick whichever tool you're using. The Bridge Plugin (step 2) is the same for all three.
Pick whichever tool you're using. The Bridge Plugin (step 2) is the same for all of them.

**Claude Code (recommended — one command):**
**Claude Desktop (recommended for designers — one click):**

```bash
/plugin marketplace add github:LSDimi/pluginos
/plugin install pluginos
```
1. Download [`pluginos.dxt`](https://github.com/LSDimi/pluginos/releases/latest/download/pluginos.dxt) from the latest GitHub Release.
2. Double-click the downloaded file. Claude Desktop opens an install dialog.
3. Confirm. PluginOS appears in Claude Desktop's connector list.

This installs the MCP server registration and the `pluginos-figma` skill in one step.
No JSON editing, no terminal. Note: Claude.ai web is **not** supported — it cannot reach local MCP servers.

**Cursor (`.cursor/mcp.json`):**

Expand All @@ -40,24 +39,31 @@ This installs the MCP server registration and the `pluginos-figma` skill in one
"mcpServers": {
"pluginos": {
"command": "npx",
"args": ["pluginos@latest"]
"args": ["-y", "pluginos@latest"]
}
}
}
```

Then paste the Tier 1 rules below into `.cursorrules` so Cursor prefers PluginOS over the generic Figma MCP.

**Claude chat / Desktop (no Code):**
**Claude Code (CLI — engineers):**

```bash
/plugin marketplace add github:LSDimi/pluginos
/plugin install pluginos
```

Installs the MCP server registration and the `pluginos-figma` skill in one step.

Add the same MCP server block to Claude Desktop's `mcp.json`:
**Manual (advanced — edit `claude_desktop_config.json` directly):**

```json
{
"mcpServers": {
"pluginos": {
"command": "npx",
"args": ["pluginos@latest"]
"args": ["-y", "pluginos@latest"]
}
}
}
Expand Down
9 changes: 8 additions & 1 deletion eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,14 @@ export default tseslint.config(
...tseslint.configs.recommended,
eslintConfigPrettier,
{
ignores: ["**/dist/", "**/node_modules/", "**/*.js", "**/*.cjs", "!eslint.config.js"],
ignores: [
"**/dist/",
"**/node_modules/",
"**/*.js",
"**/*.cjs",
"**/*.mjs",
"!eslint.config.js",
],
},
{
files: ["**/*.ts"],
Expand Down
22 changes: 22 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

122 changes: 68 additions & 54 deletions packages/bridge-plugin/src/bootloader.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,17 @@
.status-sub { font-size: 10px; color: var(--figma-color-text-secondary, #999); margin-top: 1px; }
.divider { height: 1px; background: var(--figma-color-border, #e5e5e5); }
.setup-section { padding: 10px 12px 0; display: none; }
.action-card {
width: 100%; display: flex; align-items: center; gap: 10px;
padding: 8px 10px; margin-bottom: 7px;
background: var(--figma-color-bg-secondary, #f5f5f5);
border: 1px solid var(--figma-color-border, #e5e5e5);
border-radius: 6px; cursor: pointer; text-align: left;
font-family: inherit; font-size: 11px; transition: background 0.15s;
}
.action-card:hover { background: var(--figma-color-bg-hover, #ebebeb); }
.action-icon { font-size: 15px; flex-shrink: 0; width: 18px; text-align: center; }
.action-title { font-size: 11px; font-weight: 600; color: var(--figma-color-text); }
.action-desc { font-size: 10px; color: var(--figma-color-text-secondary, #999); margin-top: 1px; }
.setup-cards { display: flex; flex-direction: column; gap: 8px; }
.card { padding: 10px 12px; background: var(--figma-color-bg-secondary, #f5f5f5); border: 1px solid var(--figma-color-border, #e5e5e5); border-radius: 6px; }
.card-title { font-size: 11px; font-weight: 600; color: var(--figma-color-text); margin-bottom: 4px; }
.card-desc { font-size: 10px; color: var(--figma-color-text-secondary, #999); margin-bottom: 8px; }
.card-actions { display: flex; flex-wrap: wrap; gap: 6px; }
.btn { font-family: inherit; font-size: 10px; padding: 4px 10px; border: 1px solid var(--figma-color-border, #e5e5e5); border-radius: 4px; background: var(--figma-color-bg, #fff); color: var(--figma-color-text, #111); cursor: pointer; transition: background 0.15s; }
.btn:hover { background: var(--figma-color-bg-hover, #ebebeb); }
.btn.copied { color: #1bc47d; border-color: #1bc47d; }
.btn-primary { background: var(--figma-color-text, #111); color: var(--figma-color-bg, #fff); border-color: var(--figma-color-text, #111); text-decoration: none; display: inline-block; }
.btn-primary:hover { opacity: 0.9; }
a.btn { text-decoration: none; }
.progress-section { padding: 8px 12px 10px; display: none; }
.progress-bar { height: 2px; background: var(--figma-color-border, #e5e5e5); border-radius: 1px; overflow: hidden; }
.progress-fill { height: 100%; width: 0%; background: #f5a623; border-radius: 1px; }
Expand All @@ -59,20 +58,32 @@
<div class="divider"></div>

<div class="setup-section" id="setup-section">
<button class="action-card" onclick="copyPrompt()">
<span class="action-icon">›</span>
<div>
<div class="action-title">Easy setup (beginner)</div>
<div class="action-desc" id="prompt-desc">Click here to copy the prompt and paste in your project’s AI chat to configure PluginOS</div>
<div class="setup-cards">
<div class="card" role="region" aria-label="Claude Desktop">
<div class="card-title">Claude Desktop</div>
<div class="card-desc">One-click install. Download the PluginOS extension for Claude Desktop, double-click to install, then return here. No terminal, no JSON.</div>
<div class="card-actions">
<a class="btn btn-primary" id="btn-download-dxt" href="https://github.com/LSDimi/pluginos/releases/latest/download/pluginos.dxt" download>Download for Claude Desktop</a>
</div>
</button>
<button class="action-card" onclick="copyConfig()">
<span class="action-icon">⎘</span>
<div>
<div class="action-title">Copy MCP config</div>
<div class="action-desc" id="copy-desc">Paste in your IDE’s MCP server list or Claude Connectors</div>
</div>

<div class="card" role="region" aria-label="Cursor">
<div class="card-title">Cursor</div>
<div class="card-desc">For engineers. Add PluginOS as an MCP server in Cursor settings, then paste the usage rules into <code>.cursorrules</code>.</div>
<div class="card-actions">
<button class="btn" id="btn-copy-mcp-cursor">1. Copy MCP config</button>
<button class="btn" id="btn-copy-rules-cursor">2. Copy rules</button>
</div>
</button>
</div>

<div class="card" role="region" aria-label="Claude Code">
<div class="card-title">Claude Code (CLI)</div>
<div class="card-desc">For terminal users. Two commands — paste both at once into Claude Code to register the MCP server and skill.</div>
<div class="card-actions">
<button class="btn" id="btn-copy-install">Copy install commands</button>
</div>
</div>
</div>
</div>

<div class="progress-section" id="progress-section">
Expand Down Expand Up @@ -118,39 +129,42 @@
}, 1000);
}

var PROMPT_TEXT = "Start the PluginOS MCP server if it’s not already running: `npx pluginos`\n\nThen find this project’s agent instructions file (CLAUDE.md, AGENTS.md, .cursorrules, or equivalent — create one if none exists) and add the following rules:\n\n- For ALL Figma operations, use PluginOS tools exclusively (pluginos MCP)\n- Call list_operations first to discover what operations are available\n- Use run_operation to execute them\n- Use execute_figma only for one-off custom logic not covered by built-in operations\n- Never use mcp__Figma__* tools — they bypass the plugin and return raw, token-heavy data (~10x token cost)\n- If PluginOS returns “No plugin connected”, ask the user to open the PluginOS Bridge plugin in Figma first\n\nConfirm once the server is running and the instruction file has been updated.";
var CONFIG_TEXT = JSON.stringify({ mcpServers: { pluginos: { command: "npx", args: ["pluginos@latest"] } } }, null, 2);
var MCP_CONFIG_JSON = JSON.stringify({ mcpServers: { pluginos: { command: "npx", args: ["-y", "pluginos@0.4.0"] } } }, null, 2);
var TIER_1_RULES = "When working with Figma, always use PluginOS tools exclusively:\n- Use `list_operations` (pluginos) first to discover available Figma operations.\n- Use `run_operation` (pluginos) to execute them.\n- Use `execute_figma` (pluginos) only for one-off custom logic not covered by built-in ops.\n- Do NOT use `mcp__Figma__*` tools — they bypass the plugin and return raw, token-heavy data. PluginOS returns pre-summarized, structured results at ~230 tokens/call.\n- If PluginOS returns \"No plugin connected\", open the PluginOS Bridge plugin in Figma before retrying.\n\nAudit/lint/check operations default to `scope: \"selection\"`. Pass `scope: \"page\"` explicitly (and `confirm: true` for pages over 500 nodes) to scan the whole page. Responses carry `_hint` and `_next_hints` fields — respect them when deciding what to do next.";
var INSTALL_COMMAND = "/plugin marketplace add github:LSDimi/pluginos\n/plugin install pluginos";

function doCopy(text, descId, revertText) {
var d = el(descId);
function onOk() {
d.textContent = "✓ Copied!";
setTimeout(function() { d.textContent = revertText; }, 2500);
}
function onFail() { d.textContent = "Copy failed — please try again"; }
function fallback() {
try {
var ta = document.createElement("textarea");
ta.value = text;
ta.style.cssText = "position:fixed;top:0;left:0;width:1px;height:1px;opacity:0;";
document.body.appendChild(ta);
ta.focus(); ta.select();
document.execCommand("copy") ? onOk() : onFail();
document.body.removeChild(ta);
} catch(e) { onFail(); }
}
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(text).then(onOk).catch(fallback);
} else { fallback(); }
}
function copyConfig() {
doCopy(CONFIG_TEXT, "copy-desc", "Paste in your IDE’s MCP server list or Claude Connectors");
}
function copyPrompt() {
doCopy(PROMPT_TEXT, "prompt-desc", "Click here to copy the prompt and paste in your project’s AI chat to configure PluginOS");
function wireCopy(btnId, text) {
var btn = document.getElementById(btnId);
if (!btn) return;
btn.addEventListener("click", function() {
function onOk() {
btn.classList.add("copied");
var orig = btn.textContent;
btn.textContent = "Copied!";
setTimeout(function() { btn.textContent = orig; btn.classList.remove("copied"); }, 2500);
}
function onFail() { btn.textContent = "Copy failed"; }
function fallback() {
try {
var ta = document.createElement("textarea");
ta.value = text;
ta.style.cssText = "position:fixed;top:0;left:0;width:1px;height:1px;opacity:0;";
document.body.appendChild(ta);
ta.focus(); ta.select();
document.execCommand("copy") ? onOk() : onFail();
document.body.removeChild(ta);
} catch(e) { onFail(); }
}
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(text).then(onOk).catch(fallback);
} else { fallback(); }
});
}
wireCopy("btn-copy-install", INSTALL_COMMAND);
wireCopy("btn-copy-mcp-cursor", MCP_CONFIG_JSON);
wireCopy("btn-copy-rules-cursor", TIER_1_RULES);

function tryBootload() {
function tryBootload() {
setDot("dot-yellow");
setStatus("Connecting…", "Searching for PluginOS server");
showSection("setup-section", false);
Expand Down
12 changes: 1 addition & 11 deletions packages/bridge-plugin/src/ui-entry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const MCP_CONFIG_JSON = `{
"mcpServers": {
"pluginos": {
"command": "npx",
"args": ["pluginos@0.4.0"]
"args": ["-y", "pluginos@0.4.0"]
}
}
}`;
Expand Down Expand Up @@ -285,16 +285,6 @@ document
.addEventListener("click", (e) =>
copyToClipboard(TIER_1_RULES, e.currentTarget as HTMLButtonElement)
);
document
.getElementById("btn-copy-mcp-chat")!
.addEventListener("click", (e) =>
copyToClipboard(MCP_CONFIG_JSON, e.currentTarget as HTMLButtonElement)
);
document
.getElementById("btn-copy-rules-chat")!
.addEventListener("click", (e) =>
copyToClipboard(TIER_1_RULES, e.currentTarget as HTMLButtonElement)
);

// Forward messages from code.js (plugin sandbox) to WebSocket
window.onmessage = (event: MessageEvent) => {
Expand Down
26 changes: 14 additions & 12 deletions packages/bridge-plugin/src/ui.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
.btn { font: inherit; font-size: 12px; font-weight: 500; padding: 6px 12px; border-radius: 8px; border: 1px solid var(--card-border); background: transparent; color: var(--text-primary); cursor: pointer; }
.btn:hover { background: var(--cream); }
.btn.copied { background: var(--accent); color: #FFF; border-color: var(--accent); }
.btn-primary { background: var(--text-primary); color: var(--card-bg); border-color: var(--text-primary); text-decoration: none; display: inline-block; }
.btn-primary:hover { opacity: 0.9; }
a.btn { text-decoration: none; }
.cards-container { padding: 12px; }
* { box-sizing: border-box; margin: 0; padding: 0; }
.header {
Expand Down Expand Up @@ -207,32 +210,31 @@

<!-- Disconnected: setup guide -->
<div id="view-setup" class="cards-container">
<div class="card" role="region" aria-label="Claude Code">
<svg class="card-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 6l4 4-4 4M12 16h8"/></svg>
<div class="card-title">Claude Code</div>
<div class="card-desc">Two commands: add the marketplace, then install the plugin. Copy and paste into Claude Code — both lines at once. This registers the PluginOS MCP server and the built-in skill that teaches Claude to use it.</div>
<div class="card" role="region" aria-label="Claude Desktop">
<svg class="card-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M12 3l9 5-9 5-9-5 9-5zm0 8l9 5-9 5-9-5"/></svg>
<div class="card-title">Claude Desktop</div>
<div class="card-desc">One-click install. Download the PluginOS extension for Claude Desktop, double-click to install, then return here. No terminal, no JSON.</div>
<div class="card-actions">
<button class="btn" id="btn-copy-install">Copy install commands</button>
<a class="btn btn-primary" id="btn-download-dxt" href="https://github.com/LSDimi/pluginos/releases/latest/download/pluginos.dxt" download>Download for Claude Desktop</a>
</div>
</div>

<div class="card" role="region" aria-label="Cursor">
<svg class="card-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M7 9h10M7 13h6"/></svg>
<div class="card-title">Cursor</div>
<div class="card-desc">Two-step setup. Add PluginOS as an MCP server in Cursor settings, then paste the usage rules into <code>.cursorrules</code> so Cursor reaches for PluginOS first.</div>
<div class="card-desc">For engineers. Add PluginOS as an MCP server in Cursor settings, then paste the usage rules into <code>.cursorrules</code>.</div>
<div class="card-actions">
<button class="btn" id="btn-copy-mcp-cursor">1. Copy MCP config</button>
<button class="btn" id="btn-copy-rules-cursor">2. Copy rules</button>
</div>
</div>

<div class="card" role="region" aria-label="Claude chat">
<svg class="card-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 5h16v10H8l-4 4V5z"/></svg>
<div class="card-title">Claude chat</div>
<div class="card-desc">For Claude Desktop without Claude Code. Add PluginOS as an MCP server, then paste the usage rules into a Claude Project's custom instructions so Claude follows them in every message.</div>
<div class="card" role="region" aria-label="Claude Code">
<svg class="card-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M4 6l4 4-4 4M12 16h8"/></svg>
<div class="card-title">Claude Code (CLI)</div>
<div class="card-desc">For terminal users. Two commands — paste both at once into Claude Code to register the MCP server and skill.</div>
<div class="card-actions">
<button class="btn" id="btn-copy-mcp-chat">1. Copy MCP config</button>
<button class="btn" id="btn-copy-rules-chat">2. Copy rules</button>
<button class="btn" id="btn-copy-install">Copy install commands</button>
</div>
</div>

Expand Down
Binary file added packages/mcp-server/dxt/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading