Ai Context to build Plugins

Estimated reading: 8 minutes 32 views

DevScribe Plugin Development & AI Context Specification

AI Prompt Directive: Use this document as the authoritative context specification when instructing AI coding assistants (e.g. Gemini, Claude, Cursor, ChatGPT) to build, refactor, or generate custom plugins for the DevScribe developer workspace.


1. AI System Prompt / Directive

Copy and paste the following prompt block when starting a new plugin project with an AI assistant:

You are an expert full-stack developer building a plugin for DevScribe (an Electron-based developer application).
DevScribe plugins run inside an Electron Webview and communicate with the main application strictly through `window.pluginAPI`.

Core Architectural Rules:
1. All interactions with DevScribe (storage, file operations, code execution, database queries, terminal, notifications, API client) MUST use `window.pluginAPI`.
2. Do NOT use Node.js `require` or Electron direct modules in the webview bundle; use `window.pluginAPI`.
3. Listen for theme updates via `window.addEventListener("theme-changed", ...)` or read `window.pluginAPI.context.theme`.
4. Persist document state using `window.pluginAPI.updateDocument(window.pluginAPI.context.fileId, data)` or `window.pluginAPI.saveData(data)`.
5. Strictly adhere to the method signatures in the DevScribe Plugin API reference below.

2. Quickstart: Commands to Initialize a Plugin Repository

Run these commands to set up a new DevScribe plugin repository using Vite + React (recommended) or Vanilla JavaScript:

Option A: React + Vite (Recommended)

# 1. Create a new React plugin repository
npx -y create-vite@latest devscribe-plugin-mytool --template react
cd devscribe-plugin-mytool

# 2. Install dependencies
npm install

# 3. Add Remix Icons for visual consistency with DevScribe
npm install remixicon

# 4. Start local development server
npm run dev

Option B: Vanilla JavaScript

mkdir devscribe-plugin-mytool && cd devscribe-plugin-mytool
npm init -y

3. Plugin Manifest Specification (manifest.json)

Every plugin repository MUST include a manifest.json at its root directory:

{
  "id": "my-custom-plugin",
  "name": "My Custom Plugin",
  "version": "1.0.0",
  "description": "A custom developer tool plugin for the DevScribe workspace.",
  "author": "Developer Name",
  "entry": "index.html",
  "icon": "ri-code-s-slash-line",
  "fileTypes": ["code-editor", "custom-tool"],
  "permissions": [
    "file-system",
    "code-execution",
    "terminal",
    "database"
  ]
}

4. Complete Reference of Allowed window.pluginAPI Methods

A. Context & Theme Properties

PropertyTypeDescription
window.pluginAPI.context.pluginIdstringID of the active running plugin
window.pluginAPI.context.fileIdstringID of the current active document file
window.pluginAPI.context.theme"light" | "dark"Synchronously synced DevScribe theme

Theme Listener Pattern:

window.addEventListener("theme-changed", (event) => {
  const currentTheme = event.detail.theme; // "light" | "dark"
  console.log("DevScribe Theme updated:", currentTheme);
});

B. Document & File Management

MethodSignatures / ParametersReturn TypeDescription
updateDocument(fileId: string, content: any)Promise<void>Primary Save: Persists block/JSON document data for active file
getDocumentsByParentFile(fileId: string)Promise<any[]>Loads saved document block array for specified file ID
saveData(data: any)Promise<void>Legacy Save: Saves raw state object for (pluginId, fileId)
loadData()Promise<any>Legacy Load: Retrieves raw state object for (pluginId, fileId)
getFileDetailsById(fileId: string)Promise<{ title, lastEdited, folderId, fileType }>Loads file metadata
updateFileName(newName: string)Promise<void>Renames the current file
createFile(fileData: object)Promise<object>Creates a new file in workspace
openFileInTab(fileId: string, fileType: string, title: string)Promise<void>Opens file tab in DevScribe workspace
getNestedPath(params?: { fileId?: string, folderId?: string })Promise<{ folders: Array, file: object }>Resolves full breadcrumb ancestor folder hierarchy
getAllFiles()Promise<any[]>Lists all files in the active workspace
getPlugins()Promise<any[]>Lists all installed workspace plugins
getCorePlugins()Promise<any[]>Lists core system plugins

C. Native Code Execution Engine

MethodParametersReturn TypeDescription
runJsCode(code: string)Promise<any>Executes JavaScript code natively in main process
runTsCode(code: string)Promise<any>Executes TypeScript code
runJavaCode(code: string, config?: object)Promise<any>Compiles & runs Java code
runShellCommand(command: string)Promise<any>Executes terminal shell command in main process
runSqliteCommand(query: string)Promise<any>Executes SQLite query on local workspace database
runSqlCommand(queryOrParams: any, configId: string)Promise<any>Executes SQL query on configured remote DB
runDockerCompose(code: string, action?: string, fileName?: string, fileId?: string)Promise<any>Executes Docker Compose action (up -d, stop, down)

D. Data-Bridge (Database Operations)

MethodParametersReturn TypeDescription
getConnections()Promise<any[]>Returns all configured database connections
saveConnection(data: object)Promise<any>Saves database connection configuration
testConnection(data: object)Promise<boolean>Tests database connection parameters
deleteConnection(id: string)Promise<void>Removes a database connection
getDatabases(connectionId: string)Promise<string[]>Lists databases for a connection
getDatabaseTables(connectionId: string, database: string)Promise<string[]>Lists tables in a database
executeQuery(connectionId: string, query: string, database: string)Promise<any>Executes SQL query on specified connection

E. Integrated PTY Terminal (window.pluginAPI.terminal)

MethodParametersReturn TypeDescription
terminal.create(id: string)voidInitializes a PTY terminal instance
terminal.input(id: string, data: string)voidSends keystrokes/data to terminal
terminal.resize(id: string, cols: number, rows: number)voidResizes terminal grid dimensions
terminal.dispose(id: string)voidDestroys PTY terminal instance
terminal.onData(id: string, callback: (data: string) => void)() => voidSubscribes to terminal output; returns unsubscribe fn

F. Native API Client & Environments (window.pluginAPI.api)

MethodParametersReturn TypeDescription
api.executeApiRequest{ url: string, method: string, headers: object, body?: string, filePath?: string, formData?: any[] }Promise<Response>Native HTTP request (bypasses browser CORS)
api.executeCurl(command: string)Promise<Response>Executes cURL command string
api.fetchAllEnvs()Promise<Array<{ id, name }>>Fetches environment scopes
api.fetchEnvByScopeId(scopeId: string)Promise<Array<{ id, key, value }>>Fetches key-value environment variables
api.createEnv(name: string)Promise<object>Creates a new environment scope
api.saveEnvVariable{ key, value, scopeType, scopeId }Promise<void>Creates/saves env variable
api.updateEnvVariable{ id: number, key: string, value: string }Promise<void>Updates existing variable
api.deleteEnvVariable(id: number)Promise<void>Deletes an environment variable

G. Messaging & System Utilities

MethodParametersReturn TypeDescription
notify(message: string, type?: 'info' | 'success' | 'warning' | 'error')voidTriggers DevScribe desktop toast notification
openExternal(url: string)voidOpens URL in system default browser
messaging.invoke(channel: string, ...args: any)Promise<any>Sends custom IPC invocation to Main process
messaging.on(channel: string, callback: (data: any) => void)() => voidSubscribes to main process push events
messaging.removeAllListeners(channel: string)voidRemoves IPC event listeners for channel

5. Standard Component Architecture Example (React)

Below is a production boilerplate for a DevScribe plugin component demonstrating theme synchronization, auto-saving, and code execution:

import React, { useState, useEffect } from 'react';

export default function App() {
  const [code, setCode] = useState('');
  const [output, setOutput] = useState('');
  const [theme, setTheme] = useState(window.pluginAPI?.context?.theme || 'light');
  const [loading, setLoading] = useState(false);

  const fileId = window.pluginAPI?.context?.fileId;

  // 1. Initialize Document Content & Theme Listener
  useEffect(() => {
    async function loadContent() {
      if (!fileId || !window.pluginAPI) return;
      try {
        const docs = await window.pluginAPI.getDocumentsByParentFile(fileId);
        if (docs && docs.length > 0 && docs[0].content) {
          const docData = docs[0].content;
          const initialCode = Array.isArray(docData) ? docData[0]?.data?.code : docData.code;
          if (initialCode) setCode(initialCode);
        }
      } catch (err) {
        console.error("Failed to load initial document data:", err);
      }
    }

    loadContent();

    const handleThemeChange = (e) => setTheme(e.detail.theme);
    window.addEventListener('theme-changed', handleThemeChange);
    return () => window.removeEventListener('theme-changed', handleThemeChange);
  }, [fileId]);

  // 2. Persist Document Content to DevScribe
  const handleCodeChange = async (newCode) => {
    setCode(newCode);
    if (!fileId || !window.pluginAPI) return;

    try {
      await window.pluginAPI.updateDocument(fileId, [
        {
          type: "code-editor",
          data: { code: newCode, updatedAt: Date.now() }
        }
      ]);
    } catch (err) {
      console.error("Auto-save failed:", err);
    }
  };

  // 3. Run Code Action
  const handleExecute = async () => {
    setLoading(true);
    try {
      const result = await window.pluginAPI.runJsCode(code);
      setOutput(typeof result === 'object' ? JSON.stringify(result, null, 2) : String(result));
      window.pluginAPI.notify("Code executed successfully!", "success");
    } catch (err) {
      setOutput("Error: " + err.message);
      window.pluginAPI.notify("Execution failed", "error");
    } finally {
      setLoading(false);
    }
  };

  return (
    <div style={{
      padding: '16px',
      backgroundColor: theme === 'dark' ? '#1E1E1E' : '#FFFFFF',
      color: theme === 'dark' ? '#F3F4F6' : '#111827',
      minHeight: '100vh',
      fontFamily: 'Inter, sans-serif'
    }}>
      <header style={{ display: 'flex', justifyContent: 'space-between', marginBottom: '12px' }}>
        <h3>DevScribe Plugin Tool</h3>
        <button
          onClick={handleExecute}
          disabled={loading}
          style={{
            padding: '6px 14px',
            backgroundColor: '#2563EB',
            color: '#FFFFFF',
            border: 'none',
            borderRadius: '4px',
            cursor: 'pointer'
          }}
        >
          {loading ? 'Executing...' : 'Run Code'}
        </button>
      </header>

      <textarea
        value={code}
        onChange={(e) => handleCodeChange(e.target.value)}
        placeholder="// Write your code or document content here..."
        style={{
          width: '100%',
          height: '240px',
          fontFamily: 'monospace',
          fontSize: '13px',
          padding: '10px',
          borderRadius: '6px',
          border: '1px solid #D1D5DB',
          backgroundColor: theme === 'dark' ? '#2D2D2D' : '#FAFAFA',
          color: theme === 'dark' ? '#F9FAFB' : '#111827'
        }}
      />

      {output && (
        <div style={{ marginTop: '16px' }}>
          <h4>Console Output:</h4>
          <pre style={{
            padding: '12px',
            borderRadius: '6px',
            backgroundColor: theme === 'dark' ? '#111827' : '#F3F4F6',
            overflowX: 'auto'
          }}>
            {output}
          </pre>
        </div>
      )}
    </div>
  );
}

Leave a Reply

Your email address will not be published. Required fields are marked *

Share this Doc

Ai Context to build Plugins

Or copy link

CONTENTS