feat(gateway): register fabric.register gateway method for live no-restart registration

Recruitment's register-agent step is a plain shell step (no LLM turn), so it
cannot invoke the `fabric-register` TOOL (tool only fires inside an agent
turn) and there is no `openclaw tools call` CLI. It previously fell back to
the standalone bootstrap binary, which writes fabric-identity.json but cannot
notify the running plugin -> the new agent's inbound socket only came up after
a gateway restart.

This adds an in-process gateway method `fabric.register` (scope:
operator.write) whose handler runs inbound.addAccount: validates the key,
persists identity, and brings the inbound socket up immediately. The script
now calls `openclaw gateway call fabric.register --params ...` and only falls
back to the bootstrap binary if the method is unavailable.

Also resyncs committed dist/ to source (sub-discussion-hook/store + tools/
inbound were source-committed but their dist artifacts were stale).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
h z
2026-06-07 21:04:38 +01:00
parent 40c9cb5740
commit f8c8c21727
7 changed files with 737 additions and 21 deletions

View File

@@ -49,6 +49,18 @@ export default defineChannelPluginEntry({
logger: { info: (m: string) => void; warn: (m: string) => void };
on: (ev: string, fn: (...args: unknown[]) => unknown) => void;
registerTool: (d: unknown) => void;
registerGatewayMethod: (
method: string,
handler: (req: {
params?: unknown;
respond: (
ok: boolean,
data?: unknown,
error?: { code: string; message: string },
) => void;
}) => void | Promise<void>,
opts?: { scope?: string },
) => void;
};
const cfg = (api.config ?? {}) as {
channels?: { fabric?: { centerApiBase?: string; commandsSyncKey?: string } };
@@ -121,6 +133,33 @@ export default defineChannelPluginEntry({
api.logger.info('fabric: __fabric cross-plugin API installed (getChannelType + addAccount + removeAccount)');
}
// CLI-invocable live registration, callable from a shell script via
// openclaw gateway call fabric.register --params '{"agentId":"…","apiKey":"fak_…"}'
// The `fabric-register` TOOL only fires inside an agent turn, and there is
// no `openclaw tools call` CLI — so recruitment's `register-agent` script
// (a plain shell step, no LLM turn) had to fall back to the standalone
// binary, which can't notify the running plugin → needed a gateway
// restart. This gateway method runs in-process: inbound.addAccount
// validates the key, persists identity, and brings the socket up live —
// no restart.
api.registerGatewayMethod('fabric.register', async ({ params, respond }) => {
const p = (params ?? {}) as { agentId?: string; apiKey?: string };
if (!p.agentId || !p.apiKey) {
respond(false, { ok: false }, { code: 'INVALID_REQUEST', message: 'agentId and apiKey required' });
return;
}
if (!inbound) {
respond(false, { ok: false }, { code: 'UNAVAILABLE', message: 'fabric inbound not ready (gateway still starting?)' });
return;
}
try {
await inbound.addAccount({ agentId: p.agentId, fabricApiKey: p.apiKey });
respond(true, { ok: true, agentId: p.agentId });
} catch (err) {
respond(false, { ok: false }, { code: 'UNAVAILABLE', message: `fabric-register failed: ${String(err)}` });
}
}, { scope: 'operator.write' });
api.on('gateway_start', () => {
const _G = globalThis as Record<string, unknown>;
if (_G._fabricInboundStarted) return;