plex: full nox module — client, tools and events (ADR 0044/0046)
Moves plex's API client and tools out of the shared hal sdk into the module, so a Plex API change rebuilds only plex. Tools: status, search, sessions, recently-added, refresh. And a real event design: it emits playback started/stopped and item.added by watching the server, and consumes module.*.download.completed to rescan so a downloader's fetch becomes a visible item. Typechecks against the sdk; manifest parses with its emits/ consumes and broker own-secret. Claude-Session: https://claude.ai/code/session_01LrgweAeERJYBg88c5cKDzF
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
// plex's tools — moved here from the shared sdk (novox/hq ADR 0044), importing plex's own client.
|
||||
// They return structured data; the mesh serves them through the sdk's tool harness.
|
||||
|
||||
import { registerModuleTools, type ToolDefinition } from "@novox/mesh-sdk/tools";
|
||||
import { PlexClient } from "../client.js";
|
||||
|
||||
export function getPlexTools(plex: PlexClient): ToolDefinition[] {
|
||||
return [
|
||||
{
|
||||
name: "plex_status",
|
||||
description: "Plex server status: server info, libraries, active sessions, recently added.",
|
||||
input: {},
|
||||
run: async () => {
|
||||
const [server, libraries, sessions, recent] = await Promise.all([
|
||||
plex.getServerInfo(),
|
||||
plex.getLibraries(),
|
||||
plex.getSessions(),
|
||||
plex.getRecentlyAdded(10),
|
||||
]);
|
||||
return { server, libraries, sessions, recentlyAdded: recent };
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "plex_search",
|
||||
description: "Search across all Plex libraries — movies, shows, episodes, music.",
|
||||
input: { query: { type: "string", description: "the search query" } },
|
||||
run: async (args) => ({ query: String(args.query), results: await plex.search(String(args.query)) }),
|
||||
},
|
||||
{
|
||||
name: "plex_sessions",
|
||||
description: "Active Plex playback sessions — who is watching what, and where.",
|
||||
input: {},
|
||||
run: async () => {
|
||||
const sessions = await plex.getSessions();
|
||||
return { count: sessions.length, sessions };
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "plex_recently_added",
|
||||
description: "Recently added media in Plex.",
|
||||
input: { limit: { type: "number", description: "how many items (default 20)" } },
|
||||
run: async (args) => ({ items: await plex.getRecentlyAdded(args.limit ? Number(args.limit) : 20) }),
|
||||
},
|
||||
{
|
||||
name: "plex_refresh",
|
||||
description: "Ask Plex to rescan its libraries so new files on disk become visible items.",
|
||||
input: { library: { type: "string", description: "a library section key; omitted rescans all" } },
|
||||
run: async (args) => {
|
||||
if (args.library) {
|
||||
await plex.refreshLibrary(String(args.library));
|
||||
return { refreshed: String(args.library) };
|
||||
}
|
||||
await plex.refreshAll();
|
||||
return { refreshed: "all" };
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
// The tools exist only when a token can be found; without one, plex contributes none rather than
|
||||
// failing the whole runtime.
|
||||
registerModuleTools("plex", (env) => {
|
||||
try {
|
||||
return getPlexTools(PlexClient.fromEnv(env));
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user