feat: Scribe-as-plugin foundation (push-channel endpoint, in-repo plugin, plugin-install Settings UI, backup v3) #62

Merged
bvandeusen merged 5 commits from dev into main 2026-06-10 00:02:54 -04:00
Showing only changes of commit c0b3ec7d9b - Show all commits
+83 -14
View File
@@ -137,6 +137,18 @@ const claudeCodeCommand = computed(() => {
--header "Authorization: Bearer ${effectiveApiKey.value}"`;
});
// Plugin install — the recommended path. The Scribe plugin bundles the MCP
// connection, a session-start hook that surfaces your rules, and the Scribe
// process-skills. The marketplace is the Scribe app's own git repo; persisted
// per-browser like the MCP fields above.
const _MKT_KEY = 'plugin_marketplace_url';
const pluginMarketplaceUrl = ref<string>(localStorage.getItem(_MKT_KEY) || '');
watch(pluginMarketplaceUrl, (v) => localStorage.setItem(_MKT_KEY, (v || '').trim()));
const pluginInstallCommands = computed(() => {
const mkt = (pluginMarketplaceUrl.value || '').trim() || '<your-scribe-repo>.git';
return `/plugin marketplace add ${mkt}\n/plugin install scribe@scribe-plugin`;
});
const mcpConfigSnippet = computed(() => JSON.stringify({
mcpServers: {
[effectiveMcpName.value]: {
@@ -1546,20 +1558,64 @@ function formatUserDate(iso: string): string {
</div>
<!-- Claude Code tab -->
<ol v-if="mcpClientTab === 'claude-code'">
<li>
Register the server with Claude Code:
<div class="mcp-code-row">
<pre class="mcp-code">{{ claudeCodeCommand }}</pre>
<button class="btn btn-secondary btn-sm" @click="copySnippet(claudeCodeCommand, 'cc-add')">
{{ copiedSnippetKey === 'cc-add' ? 'Copied' : 'Copy' }}
</button>
</div>
</li>
<li>
Verify the connection by running <code>/mcp</code> inside Claude Code <code>{{ effectiveMcpName }}</code> should appear as connected.
</li>
</ol>
<div v-if="mcpClientTab === 'claude-code'">
<p class="settings-description">
<strong>Recommended install the Scribe plugin.</strong> One install wires up the MCP
connection, a session-start hook that surfaces your rules, and the Scribe process-skills.
</p>
<label class="mcp-config-field">
<span class="mcp-config-label">Scribe plugin marketplace (git URL)</span>
<input
v-model="pluginMarketplaceUrl"
type="text"
placeholder="https://git.example.com/you/Scribe.git"
class="settings-input"
spellcheck="false"
/>
<span class="mcp-hint">
The Scribe app's own git repo — it ships the plugin in lockstep with this instance.
</span>
</label>
<ol>
<li>
Add the marketplace and install the plugin:
<div class="mcp-code-row">
<pre class="mcp-code">{{ pluginInstallCommands }}</pre>
<button class="btn btn-secondary btn-sm" @click="copySnippet(pluginInstallCommands, 'plugin-install')">
{{ copiedSnippetKey === 'plugin-install' ? 'Copied' : 'Copy' }}
</button>
</div>
</li>
<li>
When prompted, enter your <strong>Scribe base URL</strong> (<code>{{ origin }}</code>),
an <strong>API key</strong> (generate one above), and optionally a
<strong>project id</strong> to scope the session-start context.
</li>
<li>
Restart Claude Code — <code>/mcp</code> shows <code>scribe</code> connected and your
standing rules load at session start.
</li>
</ol>
<details class="mcp-advanced">
<summary>Advanced: connect the MCP only (no plugin)</summary>
<ol>
<li>
Register just the MCP server:
<div class="mcp-code-row">
<pre class="mcp-code">{{ claudeCodeCommand }}</pre>
<button class="btn btn-secondary btn-sm" @click="copySnippet(claudeCodeCommand, 'cc-add')">
{{ copiedSnippetKey === 'cc-add' ? 'Copied' : 'Copy' }}
</button>
</div>
</li>
<li>
Verify with <code>/mcp</code> — <code>{{ effectiveMcpName }}</code> should appear as connected.
You won't get the session-start rule push or the Scribe skills this way.
</li>
</ol>
</details>
</div>
<!-- Claude Desktop tab -->
<ol v-else-if="mcpClientTab === 'claude-desktop'">
@@ -3162,6 +3218,19 @@ function formatUserDate(iso: string): string {
}
.mcp-code-row .mcp-code { margin-top: 0; }
.mcp-code-row .btn-sm { white-space: nowrap; }
.mcp-advanced {
margin-top: 1.25rem;
border-top: 1px solid var(--color-border, rgba(255, 255, 255, 0.1));
padding-top: 0.75rem;
}
.mcp-advanced summary {
cursor: pointer;
font-size: 0.85rem;
opacity: 0.75;
user-select: none;
}
.mcp-advanced summary:hover { opacity: 1; }
.mcp-advanced[open] summary { margin-bottom: 0.5rem; }
.mcp-hint {
margin-top: 0.5rem;
font-size: 0.8rem;