feat(scripts): add sidecar icons and tags in the admin UI

Serve optional PNG/JPG next to each script and show meta tags in lists, cards, and the editor.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-15 21:21:24 +07:00
co-authored by Cursor
parent bccbf551e3
commit cae308359a
15 changed files with 256 additions and 47 deletions
+19 -2
View File
@@ -1,3 +1,4 @@
import fs from "fs";
import {
clearScriptCache,
inspectScriptSource,
@@ -21,11 +22,27 @@ export default function scriptsPluginFactory(registry) {
content == null
? { meta: null, metaError: "script not found" }
: inspectScriptSource(name, content);
return { name, ...inspected };
return { name, hasIcon: fsStore.scriptHasIcon(name), ...inspected };
});
return { scripts };
});
fastify.get("/scripts/:name/icon", async (req, reply) => {
const { name } = /** @type {{ name: string }} */ (req.params);
try {
fsStore.assertScriptName(name);
} catch (err) {
return reply.code(err.statusCode ?? 400).send({ error: err.message });
}
const icon = fsStore.resolveScriptIcon(name);
if (icon == null) return reply.code(404).send({ error: "icon not found" });
const body = fs.readFileSync(icon.filePath);
return reply
.type(icon.contentType)
.header("Cache-Control", "private, max-age=60")
.send(body);
});
fastify.get("/scripts/:name", async (req, reply) => {
const { name } = /** @type {{ name: string }} */ (req.params);
try {
@@ -35,7 +52,7 @@ export default function scriptsPluginFactory(registry) {
}
const content = fsStore.readScript(name);
if (content == null) return reply.code(404).send({ error: "script not found" });
return { name, content, ...inspectScriptSource(name, content) };
return { name, content, hasIcon: fsStore.scriptHasIcon(name), ...inspectScriptSource(name, content) };
});
fastify.put("/scripts/:name", async (req, reply) => {