grafana, tautulli, nextcloud, nodered: full nox modules (ADR 0044/0046)

grafana: status/datasources/dashboards/alerts tools, emits alert.firing.
tautulli: activity/history/stats tools, emits watch.recorded. nextcloud:
users/shares/apps/occ tools (occ via docker exec, shares over OCS), emits
user.created/share.created. nodered: flows/nodes/deploy tools, emits
flows.deployed inline from the deploy tool. All typecheck; manifests parse.
This commit is contained in:
2026-09-04 02:43:20 +02:00
parent 1e2a849b90
commit eccfc70991
23 changed files with 897 additions and 2 deletions
+57
View File
@@ -0,0 +1,57 @@
// nextcloud's tools — importing nextcloud's own client (novox/hq ADR 0044). occ runs inside the
// container; shares come over OCS. They return structured data; the mesh serves them through the
// sdk's tool harness.
import { registerModuleTools, type ToolDefinition } from "@novox/mesh-sdk/tools";
import { NextcloudClient } from "../client.js";
export function getNextcloudTools(nextcloud: NextcloudClient): ToolDefinition[] {
return [
{
name: "nextcloud_users",
description: "List Nextcloud user accounts — uid and display name — via occ.",
input: {},
run: async () => {
const users = nextcloud.listUsers();
return { count: users.length, users };
},
},
{
name: "nextcloud_shares",
description: "List Nextcloud shares — path, type, who it is shared with — via the OCS API.",
input: {},
run: async () => {
const shares = await nextcloud.listShares();
return { count: shares.length, shares };
},
},
{
name: "nextcloud_apps",
description: "List Nextcloud apps, split into enabled and disabled, via occ.",
input: {},
run: async () => nextcloud.listApps(),
},
{
name: "nextcloud_occ",
description:
"Run an arbitrary occ admin command, e.g. status, 'config:system:get trusted_domains', " +
"user:list. occ is Nextcloud's CLI inside the container, run as the web user.",
input: { args: { type: "array", description: 'occ arguments, e.g. ["config:system:get","trusted_domains"]' } },
run: async (args) => {
const occArgs = (args.args ?? []) as unknown[];
if (!Array.isArray(occArgs) || occArgs.length === 0) throw new Error('args must be a non-empty array, e.g. ["status"]');
return { output: nextcloud.occ(occArgs.map(String)) || "(no output)" };
},
},
];
}
// The tools exist only when the admin password can be resolved; without it, nextcloud contributes
// none rather than failing the whole tool runtime.
registerModuleTools("nextcloud", (env) => {
try {
return getNextcloudTools(NextcloudClient.fromEnv(env));
} catch {
return [];
}
});