diff --git a/modules/postgres/module.json b/modules/postgres/module.json index 9a0a5cc..d958817 100644 --- a/modules/postgres/module.json +++ b/modules/postgres/module.json @@ -10,7 +10,11 @@ "claims": [ { "name": "mesh-store", - "scope": "mesh" + "scope": "mesh", + "serves": [ + "databases", + "query" + ] } ], "capabilities": [ diff --git a/modules/postgres/tools/index.ts b/modules/postgres/tools/index.ts index 51185be..90c048d 100644 --- a/modules/postgres/tools/index.ts +++ b/modules/postgres/tools/index.ts @@ -33,6 +33,37 @@ export function getPostgresTools(postgres: PostgresClient): ToolDefinition[] { ]; } +// The store seat's verbs (novox/hq ADR 0159, 0160): the role's, not postgres's. Registered under the +// seat's name, so the runtime serves them on the seat's subjects wherever this module holds the +// seat and never lists them as postgres's own; scoped to what the store enables — asking what it +// holds and reading from it — so creating a database is postgres's tool and not the store's. +export function getStoreVerbs(postgres: PostgresClient): ToolDefinition[] { + return [ + { + name: "databases", + description: "Every database the store holds, with its on-disk size.", + input: {}, + run: async () => ({ databases: await postgres.listDatabases() }), + }, + { + name: "query", + description: "One read-only statement against one database the store holds.", + input: { + database: { type: "string", description: "the database to query" }, + sql: { type: "string", description: "the SELECT (or other read-only) statement" }, + }, + run: async (args) => { + const database = String(args.database ?? ""); + const sql = String(args.sql ?? ""); + if (!database) throw new Error("query: database is required"); + if (!sql) throw new Error("query: sql is required"); + const result = await postgres.readOnlyQuery(database, sql); + return { database, command: result.command, rows: result.rows }; + }, + }, + ]; +} + // The tools exist only when the server can be reached from the environment; without it, postgres // contributes none rather than failing the whole tool runtime. registerModuleTools("postgres", (env) => { @@ -42,3 +73,11 @@ registerModuleTools("postgres", (env) => { return []; } }); + +registerModuleTools("mesh-store", (env) => { + try { + return getStoreVerbs(PostgresClient.fromEnv(env)); + } catch { + return []; + } +});