feat(channel-meta): expose globalThis.__fabric.getChannelType for narrow gating
Inbound `message.created` already carries `xType` (dm / triage / group /
broadcast / etc.) — record it in a per-channel cache so other plugins
can answer "is this channel a DM?" without poking the Center API.
New module src/channel-meta.ts:
- in-memory Map<channelId, xType>
- lazily loaded from ~/.openclaw/fabric-channel-meta.json on first
access (so first-ever DM after a fresh gateway start still hits
cache from the previous run)
- debounced 250ms flush on dirty; force-flush on gateway_stop
- recordChannelType(channelId, xType): called from inbound
- getChannelType(channelId): null if unknown — caller MUST treat null
as "don't know", NOT as "assume DM" (would re-introduce the false-
positive on group channels we're trying to eliminate)
Wiring:
- inbound.ts socket.on('message.created'): records xType BEFORE the
self-author / dedup gates (channel type is observer-agnostic)
- index.ts: installs globalThis.__fabric = { getChannelType } on
registerFull(); flushes on gateway_stop
Consumer: ClawPrompts' fabric-chat-injector will start gating its prompt
injection on getChannelType(channelId) === 'dm' (companion PR on
ClawPrompts). Removes the phase-1 "any fabric channel" false-positive.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
24
dist/fabric/index.js
vendored
24
dist/fabric/index.js
vendored
@@ -6,6 +6,7 @@
|
||||
import { defineChannelPluginEntry } from 'openclaw/plugin-sdk/core';
|
||||
import { fabricChannelPlugin } from './src/channel.js';
|
||||
import { flushAllFabric } from './src/coalesce.js';
|
||||
import { getChannelType, flushChannelMeta } from './src/channel-meta.js';
|
||||
import { FabricInbound } from './src/inbound.js';
|
||||
import { listEnabledFabricAccounts } from './src/accounts.js';
|
||||
import { registerFabricTools } from './src/tools.js';
|
||||
@@ -43,6 +44,29 @@ export default defineChannelPluginEntry({
|
||||
const client = new FabricClient(centerApiBase);
|
||||
const identity = new IdentityRegistry(idFile);
|
||||
registerFabricTools({ registerTool: (d) => api.registerTool(d), logger: api.logger }, client, identity);
|
||||
// Cross-plugin API: globalThis.__fabric
|
||||
// Consumed by ClawPrompts' fabric-chat-injector to narrow its prompt
|
||||
// injection to DM-typed channels only. The channel-meta cache is
|
||||
// populated lazily from inbound (message.created carries xType) and
|
||||
// persisted to ~/.openclaw/fabric-channel-meta.json — so even the
|
||||
// very first DM after a fresh gateway start hits cache from the
|
||||
// previous run rather than firing the injector on the wrong type.
|
||||
//
|
||||
// null return = channel never seen (cache cold). Callers MUST NOT
|
||||
// fall back to "assume DM" — fail closed on unknown.
|
||||
{
|
||||
const _G = globalThis;
|
||||
_G['__fabric'] = { getChannelType };
|
||||
// Flush channel-meta cache when the gateway shuts down so
|
||||
// recently-recorded xType entries don't get lost.
|
||||
api.on('gateway_stop', () => {
|
||||
try {
|
||||
flushChannelMeta();
|
||||
}
|
||||
catch { /* ignore */ }
|
||||
});
|
||||
api.logger.info('fabric: __fabric cross-plugin API installed (getChannelType)');
|
||||
}
|
||||
api.on('gateway_start', () => {
|
||||
const _G = globalThis;
|
||||
if (_G._fabricInboundStarted)
|
||||
|
||||
Reference in New Issue
Block a user