@cfio/cohort-sync 0.16.0 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +138 -3
- package/dist/openclaw.plugin.json +1 -1
- package/dist/package.json +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -11861,7 +11861,10 @@ function closeBridge() {
|
|
|
11861
11861
|
}
|
|
11862
11862
|
var authCircuitOpen = false;
|
|
11863
11863
|
function isUnauthorizedError(err) {
|
|
11864
|
-
|
|
11864
|
+
if (!(err instanceof ConvexError)) return false;
|
|
11865
|
+
const data = err.data;
|
|
11866
|
+
if (!data || typeof data !== "object") return false;
|
|
11867
|
+
return data.code === "UNAUTHORIZED";
|
|
11865
11868
|
}
|
|
11866
11869
|
function tripAuthCircuit() {
|
|
11867
11870
|
if (authCircuitOpen) return;
|
|
@@ -11880,6 +11883,7 @@ var markDeliveredByPlugin = makeFunctionReference("notifications:markDeliveredBy
|
|
|
11880
11883
|
var getPendingCommandsForPlugin = makeFunctionReference("gatewayCommands:getPendingForPlugin");
|
|
11881
11884
|
var acknowledgeCommandRef = makeFunctionReference("gatewayCommands:acknowledgeCommand");
|
|
11882
11885
|
var failCommandRef = makeFunctionReference("gatewayCommands:failCommand");
|
|
11886
|
+
var getChannelsForPlugin = makeFunctionReference("cloudGatewayChannels:listForPlugin");
|
|
11883
11887
|
var addCommentFromPluginRef = makeFunctionReference("comments:addCommentFromPlugin");
|
|
11884
11888
|
async function pushTelemetry(apiKey2, data) {
|
|
11885
11889
|
if (authCircuitOpen) return;
|
|
@@ -12210,6 +12214,41 @@ function startCommandSubscription(cfg, logger, resolveAgentName, gwClient) {
|
|
|
12210
12214
|
logger.info("cohort-sync: command subscription active");
|
|
12211
12215
|
return unsubscribe;
|
|
12212
12216
|
}
|
|
12217
|
+
function subscribeChannels(apiKey2, onUpdate, logger) {
|
|
12218
|
+
const c = getClient();
|
|
12219
|
+
if (!c) {
|
|
12220
|
+
(logger ?? getLogger()).warn(
|
|
12221
|
+
"cohort-sync: no ConvexClient \u2014 channels subscription skipped"
|
|
12222
|
+
);
|
|
12223
|
+
return null;
|
|
12224
|
+
}
|
|
12225
|
+
const apiKeyHash = hashApiKey(apiKey2);
|
|
12226
|
+
const unsubscribe = c.onUpdate(
|
|
12227
|
+
getChannelsForPlugin,
|
|
12228
|
+
{ apiKeyHash },
|
|
12229
|
+
(rows) => {
|
|
12230
|
+
try {
|
|
12231
|
+
onUpdate(rows);
|
|
12232
|
+
} catch (err) {
|
|
12233
|
+
(logger ?? getLogger()).error(
|
|
12234
|
+
`cohort-sync: channels onUpdate handler threw: ${String(err)}`
|
|
12235
|
+
);
|
|
12236
|
+
}
|
|
12237
|
+
},
|
|
12238
|
+
(err) => {
|
|
12239
|
+
if (isUnauthorizedError(err)) {
|
|
12240
|
+
tripAuthCircuit();
|
|
12241
|
+
return;
|
|
12242
|
+
}
|
|
12243
|
+
(logger ?? getLogger()).error(
|
|
12244
|
+
`cohort-sync: channels subscription error: ${String(err)}`
|
|
12245
|
+
);
|
|
12246
|
+
}
|
|
12247
|
+
);
|
|
12248
|
+
unsubscribers.push(unsubscribe);
|
|
12249
|
+
(logger ?? getLogger()).info("cohort-sync: channels subscription active");
|
|
12250
|
+
return unsubscribe;
|
|
12251
|
+
}
|
|
12213
12252
|
|
|
12214
12253
|
// src/gateway-client.ts
|
|
12215
12254
|
import crypto2 from "node:crypto";
|
|
@@ -12305,7 +12344,13 @@ var ALLOWED_METHODS = /* @__PURE__ */ new Set([
|
|
|
12305
12344
|
"agent",
|
|
12306
12345
|
"snapshot",
|
|
12307
12346
|
"system.presence",
|
|
12308
|
-
"gateway.restart"
|
|
12347
|
+
"gateway.restart",
|
|
12348
|
+
// `secrets.reload` re-resolves SecretRefs and atomically swaps the runtime
|
|
12349
|
+
// snapshot. The plugin's `cohort-sync/secrets-reload` gateway-method wrapper
|
|
12350
|
+
// (see `gateway-methods.ts`) proxies inbound calls to this outbound RPC so
|
|
12351
|
+
// the Cohort web app (and #608 channel attach/detach flows) can trigger a
|
|
12352
|
+
// reload without minting an admin-scope key.
|
|
12353
|
+
"secrets.reload"
|
|
12309
12354
|
]);
|
|
12310
12355
|
function buildConnectFrame(id, token, pluginVersion, identity, nonce) {
|
|
12311
12356
|
const signedAtMs = Date.now();
|
|
@@ -13378,7 +13423,7 @@ function dumpCtx(ctx) {
|
|
|
13378
13423
|
function dumpEvent(event) {
|
|
13379
13424
|
return dumpCtx(event);
|
|
13380
13425
|
}
|
|
13381
|
-
var PLUGIN_VERSION = true ? "0.
|
|
13426
|
+
var PLUGIN_VERSION = true ? "0.17.0" : "unknown";
|
|
13382
13427
|
function resolveGatewayToken(api) {
|
|
13383
13428
|
const token = api.config?.gateway?.auth?.token;
|
|
13384
13429
|
return typeof token === "string" ? token : null;
|
|
@@ -13507,6 +13552,19 @@ function initGatewayClient(port, token, cfg, resolveAgentName, logger) {
|
|
|
13507
13552
|
});
|
|
13508
13553
|
return client2;
|
|
13509
13554
|
}
|
|
13555
|
+
function applyChannelRowsToBridge(rows, setChannel, resolveAgentName) {
|
|
13556
|
+
let count = 0;
|
|
13557
|
+
for (const row of rows) {
|
|
13558
|
+
const agentName = resolveAgentName(row.agentId);
|
|
13559
|
+
setChannel(row.kind, agentName);
|
|
13560
|
+
count++;
|
|
13561
|
+
if (row.accountId) {
|
|
13562
|
+
setChannel(`${row.kind}:${row.accountId}`, agentName);
|
|
13563
|
+
count++;
|
|
13564
|
+
}
|
|
13565
|
+
}
|
|
13566
|
+
return count;
|
|
13567
|
+
}
|
|
13510
13568
|
async function handleGatewayStart(event, state) {
|
|
13511
13569
|
if (!state) {
|
|
13512
13570
|
return;
|
|
@@ -13567,6 +13625,39 @@ async function handleGatewayStart(event, state) {
|
|
|
13567
13625
|
for (const agentId of allAgentIds) {
|
|
13568
13626
|
resolvedNameMap[agentId] = state.resolveAgentName(agentId);
|
|
13569
13627
|
}
|
|
13628
|
+
if (state.channelsUnsubscriber) {
|
|
13629
|
+
state.channelsUnsubscriber();
|
|
13630
|
+
state.channelsUnsubscriber = null;
|
|
13631
|
+
}
|
|
13632
|
+
try {
|
|
13633
|
+
const unsubChannels = subscribeChannels(
|
|
13634
|
+
cfg.apiKey,
|
|
13635
|
+
(rows) => {
|
|
13636
|
+
try {
|
|
13637
|
+
const count = applyChannelRowsToBridge(
|
|
13638
|
+
rows,
|
|
13639
|
+
setChannelAgent,
|
|
13640
|
+
state.resolveAgentName
|
|
13641
|
+
);
|
|
13642
|
+
logger.debug("cohort-sync: channels snapshot applied", {
|
|
13643
|
+
rowCount: rows.length,
|
|
13644
|
+
bridgeEntries: count,
|
|
13645
|
+
bridge: Object.fromEntries(getChannelAgentBridge())
|
|
13646
|
+
});
|
|
13647
|
+
} catch (err) {
|
|
13648
|
+
logger.warn(
|
|
13649
|
+
`cohort-sync: applyChannelRowsToBridge failed: ${String(err)}`
|
|
13650
|
+
);
|
|
13651
|
+
}
|
|
13652
|
+
},
|
|
13653
|
+
logger
|
|
13654
|
+
);
|
|
13655
|
+
if (unsubChannels) state.channelsUnsubscriber = unsubChannels;
|
|
13656
|
+
} catch (err) {
|
|
13657
|
+
logger.warn(
|
|
13658
|
+
`cohort-sync: channels subscription init failed: ${String(err)}`
|
|
13659
|
+
);
|
|
13660
|
+
}
|
|
13570
13661
|
await startNotificationSubscription(
|
|
13571
13662
|
event.port,
|
|
13572
13663
|
cfg,
|
|
@@ -14009,6 +14100,13 @@ function registerHookHandlers(api, logger, getState) {
|
|
|
14009
14100
|
clearInterval(state.keepaliveInterval);
|
|
14010
14101
|
state.keepaliveInterval = null;
|
|
14011
14102
|
}
|
|
14103
|
+
if (state.channelsUnsubscriber) {
|
|
14104
|
+
try {
|
|
14105
|
+
state.channelsUnsubscriber();
|
|
14106
|
+
} catch {
|
|
14107
|
+
}
|
|
14108
|
+
state.channelsUnsubscriber = null;
|
|
14109
|
+
}
|
|
14012
14110
|
state.activityBatch.drain();
|
|
14013
14111
|
if (!isRestart) {
|
|
14014
14112
|
const shutdownConfigIds = (config?.agents?.list ?? []).map((a) => a.id);
|
|
@@ -14156,11 +14254,47 @@ function initializeHookState(api, cfg) {
|
|
|
14156
14254
|
gwClientInitialized,
|
|
14157
14255
|
keepaliveInterval: null,
|
|
14158
14256
|
commandUnsubscriber: commandUnsub,
|
|
14257
|
+
channelsUnsubscriber: null,
|
|
14159
14258
|
api,
|
|
14160
14259
|
latestPluginVersion: null
|
|
14161
14260
|
};
|
|
14162
14261
|
}
|
|
14163
14262
|
|
|
14263
|
+
// src/gateway-methods.ts
|
|
14264
|
+
async function invokeSecretsReload(gwClient) {
|
|
14265
|
+
if (!gwClient || !gwClient.isAlive()) {
|
|
14266
|
+
return { ok: false, error: "gateway client not connected" };
|
|
14267
|
+
}
|
|
14268
|
+
try {
|
|
14269
|
+
const result = await gwClient.request(
|
|
14270
|
+
"secrets.reload",
|
|
14271
|
+
void 0,
|
|
14272
|
+
3e4
|
|
14273
|
+
// Channel restart can take a few seconds — give it headroom.
|
|
14274
|
+
);
|
|
14275
|
+
const warningCount = typeof result?.warningCount === "number" ? result.warningCount : 0;
|
|
14276
|
+
return { ok: true, warningCount };
|
|
14277
|
+
} catch (err) {
|
|
14278
|
+
return {
|
|
14279
|
+
ok: false,
|
|
14280
|
+
error: err instanceof Error ? err.message : String(err)
|
|
14281
|
+
};
|
|
14282
|
+
}
|
|
14283
|
+
}
|
|
14284
|
+
function registerGatewayMethods(api, getGatewayClient) {
|
|
14285
|
+
api.registerGatewayMethod(
|
|
14286
|
+
"cohort-sync/secrets-reload",
|
|
14287
|
+
async ({ respond }) => {
|
|
14288
|
+
const result = await invokeSecretsReload(getGatewayClient());
|
|
14289
|
+
respond(true, result);
|
|
14290
|
+
},
|
|
14291
|
+
// operator.write is the channel attach/detach surface — same scope used
|
|
14292
|
+
// for any write-side channels operation. Admins also pass (admin is a
|
|
14293
|
+
// superset).
|
|
14294
|
+
{ scope: "operator.write" }
|
|
14295
|
+
);
|
|
14296
|
+
}
|
|
14297
|
+
|
|
14164
14298
|
// src/pocket-guide.ts
|
|
14165
14299
|
var POCKET_GUIDE = `# Cohort Agent Guide (Pocket Version)
|
|
14166
14300
|
|
|
@@ -14236,6 +14370,7 @@ var plugin = {
|
|
|
14236
14370
|
return;
|
|
14237
14371
|
}
|
|
14238
14372
|
registerHookHandlers(api, api.logger, () => sharedHookState);
|
|
14373
|
+
registerGatewayMethods(api, () => sharedHookState?.persistentGwClient ?? null);
|
|
14239
14374
|
const gatewayPort = api.config?.gateway?.port ?? 18789;
|
|
14240
14375
|
api.registerHook(
|
|
14241
14376
|
"gateway:startup",
|
package/dist/package.json
CHANGED
package/package.json
CHANGED