Stand up mesh-sdk — the stable spine a module builds against
Per novox/hq ADR 0044/0045: the sdk holds only what rarely changes and is shared across modules; per-module code (a client, tool impls, a create-a-resource adapter) lives in the module. Five areas, real and tested: - contracts: the runtime shapes module code touches (grant, credential, a mesh Interface, tool + envelope types) — not the manifest schema, which the control plane owns. - provisioner: the reconcile harness every provider shares (watch grants, create via the module's adapter, seal + write the credential, remove on withdrawal). A module writes only the adapter. - tools: registerModuleTools + collectTools — the serving harness; tools and their client live in the module. - messaging: the Broker/Envelope/event contract over the mesh broker; the concrete binding is provided by the hosting runtime. - primitives: AES-256-GCM seal/unseal, semver, resolved-env access. Compiles (tsc, NodeNext) and passes tests: sealing round-trip + wrong-key rejection, semver, tool registration (a thrower is skipped not fatal), and the provisioner creating then removing a sealed grant. Claude-Session: https://claude.ai/code/session_01LrgweAeERJYBg88c5cKDzF
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
// The tool-serving harness. A module declares its tools through registerModuleTools; a runtime
|
||||
// (the mesh's per-node tool host) collects the registrations and serves them through the command
|
||||
// surface. HOW a tool is declared and served is settled and lives here; the tools themselves, and
|
||||
// the API client they call, live in the module (novox/hq ADR 0044).
|
||||
|
||||
import type { ToolDefinition } from "../contracts/index.js";
|
||||
|
||||
export type { ToolDefinition };
|
||||
|
||||
/** A module contributes its tools as a function of its resolved environment. Returning [] (e.g.
|
||||
* when a token is absent) is normal — the module simply exposes nothing until it can. */
|
||||
export type ToolContributor = (env: NodeJS.ProcessEnv) => ToolDefinition[];
|
||||
|
||||
interface Registration {
|
||||
readonly module: string;
|
||||
readonly contribute: ToolContributor;
|
||||
}
|
||||
|
||||
const registrations: Registration[] = [];
|
||||
|
||||
/**
|
||||
* Declare the tools a module exposes. Called once, at module-tool load time, from the module's
|
||||
* tools/ entrypoint. The client and the tool implementations are imported from the module itself.
|
||||
*/
|
||||
export function registerModuleTools(module: string, contribute: ToolContributor): void {
|
||||
registrations.push({ module, contribute });
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect every registered module's tools against an environment. The tool runtime calls this
|
||||
* after loading the assigned modules' tool entrypoints. A module whose contributor throws is
|
||||
* skipped with its error surfaced, never taking the others down.
|
||||
*/
|
||||
export function collectTools(env: NodeJS.ProcessEnv = process.env): { module: string; tools: ToolDefinition[] }[] {
|
||||
return registrations.map(({ module, contribute }) => {
|
||||
try {
|
||||
return { module, tools: contribute(env) };
|
||||
} catch (err) {
|
||||
console.error(`[tools] ${module}: contributor failed, exposing none: ${err}`);
|
||||
return { module, tools: [] };
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** Testing/inspection: drop all registrations. */
|
||||
export function resetTools(): void {
|
||||
registrations.length = 0;
|
||||
}
|
||||
Reference in New Issue
Block a user