Nicolas Cantu 597f18f758 Add repos-devtools-server and AnythingLLM dev tools panel (0.2.0)
**Motivations:**
- Clone or load repos under /home/ncantu/code with AnythingLLM workspace ensure/create from the editor

**Root causes:**
- N/A (new capability)

**Correctifs:**
- N/A

**Evolutions:**
- services/repos-devtools-server: POST /repos-clone, GET /repos-list, POST /repos-load (Bearer REPOS_DEVTOOLS_TOKEN)
- Extension: Webview panel, slash commands, workspaceEnsure + POST /api/v1/workspace/new
- Docs: feature note and index links

**Pages affectées:**
- services/repos-devtools-server/*
- extensions/anythingllm-workspaces/*
- docs/README.md
- docs/features/repos-devtools-server-and-dev-panel.md
- docs/features/anythingllm-vscode-extension.md
2026-03-23 21:20:32 +01:00

104 lines
3.5 KiB
TypeScript

import * as vscode from "vscode";
import type { DevToolsConfigSnapshot } from "./config";
import { runDevToolsScript, makeOpenAnythingHandler, registerDevToolsOpenFolder } from "./devToolsExecutor";
const PANEL_ID = "anythingllmDevTools";
const panelTitle = "AnythingLLM dev tools";
const buildHtml = (
webview: vscode.Webview,
extensionUri: vscode.Uri,
): string => {
const scriptUri = webview.asWebviewUri(
vscode.Uri.joinPath(extensionUri, "media", "devTools.js"),
);
const csp = webview.cspSource;
return `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src ${csp} 'unsafe-inline'; script-src ${csp};" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>${panelTitle}</title>
<style>
body { font-family: system-ui, sans-serif; margin: 0.75rem; color: var(--vscode-foreground); background: var(--vscode-editor-background); }
label { display: block; margin-bottom: 0.35rem; font-weight: 600; }
textarea#cmd { width: 100%; min-height: 7rem; box-sizing: border-box; font-family: monospace; font-size: 12px; }
pre#out { white-space: pre-wrap; word-break: break-word; min-height: 4rem; padding: 0.5rem; border: 1px solid var(--vscode-panel-border); }
.row { margin-bottom: 0.5rem; }
button { margin-right: 0.5rem; }
</style>
</head>
<body>
<div class="row">
<label for="cmd">Commands (one per line)</label>
<textarea id="cmd" spellcheck="false" placeholder="/repos-clone https://…&#10;repos-list"></textarea>
</div>
<div class="row">
<button type="button" id="run">Run</button>
<button type="button" id="clear">Clear output</button>
</div>
<label for="out">Response</label>
<pre id="out"></pre>
<script src="${scriptUri}"></script>
</body>
</html>`;
};
export const showDevToolsPanel = (
context: vscode.ExtensionContext,
readConfig: () => DevToolsConfigSnapshot,
): void => {
const column = vscode.ViewColumn.Beside;
const panel = vscode.window.createWebviewPanel(
PANEL_ID,
panelTitle,
column,
{
enableScripts: true,
retainContextWhenHidden: true,
localResourceRoots: [
vscode.Uri.joinPath(context.extensionUri, "media"),
],
},
);
panel.webview.html = buildHtml(panel.webview, context.extensionUri);
const openFolder = registerDevToolsOpenFolder(vscode);
panel.webview.onDidReceiveMessage(
(msg: unknown) => {
void (async () => {
if (typeof msg !== "object" || msg === null) {
return;
}
const rec = msg as Record<string, unknown>;
if (rec.type !== "run") {
return;
}
const text = typeof rec.text === "string" ? rec.text : "";
const use = readConfig();
const openBrowser = makeOpenAnythingHandler(vscode, use.anythingBaseUrl);
try {
const result = await runDevToolsScript(text, {
anythingBaseUrl: use.anythingBaseUrl,
anythingApiKey: use.anythingApiKey,
reposApiBaseUrl: use.reposApiBaseUrl,
reposApiToken: use.reposApiToken,
openFolder,
openAnythingWorkspaceInBrowser: openBrowser,
});
panel.webview.postMessage({ type: "result", text: result });
} catch (e) {
const m = e instanceof Error ? e.message : String(e);
panel.webview.postMessage({ type: "result", text: `ERROR: ${m}` });
}
})();
},
undefined,
context.subscriptions,
);
};