@cfio/cohort-sync 0.31.6 → 0.31.8

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 CHANGED
@@ -11741,7 +11741,7 @@ function checkRateLimit() {
11741
11741
  return true;
11742
11742
  }
11743
11743
  var MAX_CRON_MESSAGE_LENGTH = 1e3;
11744
- async function executeCommand(cmd, gwClient, cfg, resolveAgentName, logger, cronTimestampTracker) {
11744
+ async function executeCommand(cmd, gwClient, cfg, resolveAgentName, logger, cronTimestampTracker, injection) {
11745
11745
  logger.info(`cohort-sync: executing command type=${cmd.type} id=${cmd._id}`);
11746
11746
  if (!checkRateLimit()) {
11747
11747
  logger.warn(`cohort-sync: rate limit exceeded (>${RATE_LIMIT_MAX} commands/min), rejecting command ${cmd._id}`);
@@ -11764,6 +11764,23 @@ async function executeCommand(cmd, gwClient, cfg, resolveAgentName, logger, cron
11764
11764
  process.kill(process.pid, "SIGUSR1");
11765
11765
  return;
11766
11766
  }
11767
+ if (cmd.type === "briefingGenerate") {
11768
+ const requestId = cmd.payload?.briefingRequestId;
11769
+ if (!requestId) {
11770
+ throw new Error("briefingRequestId is required for briefingGenerate");
11771
+ }
11772
+ if (!injection?.port || !injection.hooksToken) {
11773
+ throw new Error("Gateway hooks transport is not available for briefing generation");
11774
+ }
11775
+ const agentName = cmd.payload?.agentId ?? "main";
11776
+ const agentId = reverseResolveAgentName(agentName, cfg.agentNameMap ?? {});
11777
+ await injectBriefingGeneration(injection.port, injection.hooksToken, {
11778
+ requestId,
11779
+ agentId,
11780
+ agentName
11781
+ });
11782
+ return;
11783
+ }
11767
11784
  if (cmd.type.startsWith("cron")) {
11768
11785
  if (!gwClient || !gwClient.isAlive()) {
11769
11786
  logger.warn(`cohort-sync: no gateway client, cannot execute ${cmd.type}`);
@@ -11971,6 +11988,7 @@ var acknowledgeCommandRef = makeFunctionReference("gatewayCommands:acknowledgeCo
11971
11988
  var failCommandRef = makeFunctionReference("gatewayCommands:failCommand");
11972
11989
  var getChannelsForPlugin = makeFunctionReference("cloudGatewayChannels:listForPlugin");
11973
11990
  var addCommentFromPluginRef = makeFunctionReference("comments:addCommentFromPlugin");
11991
+ var transitionFromPluginRef = makeFunctionReference("tasks:transitionFromPlugin");
11974
11992
  async function pushTelemetry(apiKey2, data) {
11975
11993
  if (authCircuitOpen) return;
11976
11994
  const c = getClient();
@@ -12073,6 +12091,30 @@ async function callAddCommentFromPlugin(apiKey2, args) {
12073
12091
  throw err;
12074
12092
  }
12075
12093
  }
12094
+ async function callTransitionFromPlugin(apiKey2, args) {
12095
+ if (authCircuitOpen) {
12096
+ throw new Error(
12097
+ 'cohort-sync: API key rejected \u2014 all outbound mutations disabled until gateway restart.\n 1. Create a new key at https://my.cohort.bot/settings/api-keys\n 2. Run: openclaw config set plugins.entries.cohort-sync.config.apiKey "ch_live_..."'
12098
+ );
12099
+ }
12100
+ const c = getClient();
12101
+ if (!c) {
12102
+ throw new Error("Convex client not initialized \u2014 subscription may not be active");
12103
+ }
12104
+ try {
12105
+ return await c.mutation(transitionFromPluginRef, {
12106
+ apiKeyHash: hashApiKey(apiKey2),
12107
+ taskNumber: args.taskNumber,
12108
+ agentName: args.agentName,
12109
+ targetStatus: args.targetStatus
12110
+ });
12111
+ } catch (err) {
12112
+ if (isUnauthorizedError(err)) {
12113
+ tripAuthCircuit();
12114
+ }
12115
+ throw err;
12116
+ }
12117
+ }
12076
12118
  var DEFAULT_BEHAVIORAL_PROMPT = `BEFORE RESPONDING:
12077
12119
  - Does your planned response address the task's stated scope? If not, do not comment.
12078
12120
  - Do not post acknowledgment-only responses ("got it", "sounds good", "confirmed"). If you have no new information to add, do not comment.
@@ -12184,6 +12226,46 @@ async function injectNotification(port, hooksToken, n, agentId = "main") {
12184
12226
  throw new Error(`/hooks/agent returned ${response.status} ${response.statusText}`);
12185
12227
  }
12186
12228
  }
12229
+ function buildBriefingGenerationMessage(args) {
12230
+ return `Generate the Cohort Home briefing requested for ${args.agentName}.
12231
+
12232
+ Use your own voice and persona from SOUL.md, IDENTITY.md, and the rest of your agent instructions. First call cohort_briefing_context with request_id "${args.requestId}" to read the prepared workspace context. Then write the final briefing and submit it with cohort_briefing.
12233
+
12234
+ Final briefing requirements:
12235
+ - Write exactly two short paragraphs.
12236
+ - No bullet points or numbered lists.
12237
+ - Do not mention "this briefing".
12238
+ - Avoid colon-heavy phrasing.
12239
+ - Include one concrete high-leverage thing the reader should direct attention to next.
12240
+ - Keep it useful, personal, and alive without sounding theatrical.
12241
+
12242
+ TOOLS:
12243
+ - cohort_briefing_context(request_id) \u2014 fetch the prepared briefing context.
12244
+ - cohort_briefing(request_id, content) \u2014 submit the final Home briefing.`;
12245
+ }
12246
+ async function injectBriefingGeneration(port, hooksToken, args) {
12247
+ const response = await fetch(`http://localhost:${port}/hooks/agent`, {
12248
+ method: "POST",
12249
+ headers: {
12250
+ "Content-Type": "application/json",
12251
+ "Authorization": `Bearer ${hooksToken}`
12252
+ },
12253
+ body: JSON.stringify({
12254
+ message: buildBriefingGenerationMessage({
12255
+ requestId: args.requestId,
12256
+ agentName: args.agentName
12257
+ }),
12258
+ name: "Cohort",
12259
+ agentId: args.agentId,
12260
+ deliver: false,
12261
+ sessionKey: args.agentId === "main" ? `hook:cohort:briefing-${args.requestId}` : `agent:${args.agentId}:hook:cohort:briefing-${args.requestId}`
12262
+ }),
12263
+ signal: AbortSignal.timeout(1e4)
12264
+ });
12265
+ if (!response.ok) {
12266
+ throw new Error(`/hooks/agent returned ${response.status} ${response.statusText}`);
12267
+ }
12268
+ }
12187
12269
  var deliveryFailures = /* @__PURE__ */ new Map();
12188
12270
  var MAX_DELIVERY_ATTEMPTS = 3;
12189
12271
  async function startNotificationSubscription(port, cfg, hooksToken, logger, gwClient, resolvedNameMap) {
@@ -12273,7 +12355,7 @@ async function startNotificationSubscription(port, cfg, hooksToken, logger, gwCl
12273
12355
  unsubscribers.push(unsubscribe);
12274
12356
  }
12275
12357
  }
12276
- function startCommandSubscription(cfg, logger, resolveAgentName, gwClient, cronTimestampTracker) {
12358
+ function startCommandSubscription(cfg, logger, resolveAgentName, gwClient, cronTimestampTracker, injection) {
12277
12359
  const c = getClient();
12278
12360
  if (!c) {
12279
12361
  logger.warn("cohort-sync: no ConvexClient \u2014 command subscription skipped");
@@ -12296,7 +12378,15 @@ function startCommandSubscription(cfg, logger, resolveAgentName, gwClient, cronT
12296
12378
  commandId: cmd._id,
12297
12379
  apiKeyHash
12298
12380
  });
12299
- await executeCommand(cmd, gwClient, cfg, resolveAgentName, logger, cronTimestampTracker);
12381
+ await executeCommand(
12382
+ cmd,
12383
+ gwClient,
12384
+ cfg,
12385
+ resolveAgentName,
12386
+ logger,
12387
+ cronTimestampTracker,
12388
+ injection
12389
+ );
12300
12390
  if (cmd.type === "restart") return;
12301
12391
  } catch (err) {
12302
12392
  if (isUnauthorizedError(err)) {
@@ -13640,7 +13730,7 @@ function dumpEvent(event) {
13640
13730
  function positiveNumber(value) {
13641
13731
  return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
13642
13732
  }
13643
- var PLUGIN_VERSION = true ? "0.31.6" : "unknown";
13733
+ var PLUGIN_VERSION = true ? "0.31.8" : "unknown";
13644
13734
  function resolveGatewayToken(api) {
13645
13735
  const token2 = api.config?.gateway?.auth?.token;
13646
13736
  return typeof token2 === "string" ? token2 : null;
@@ -13839,7 +13929,14 @@ async function handleGatewayStart(event, state) {
13839
13929
  state.commandUnsubscriber();
13840
13930
  state.commandUnsubscriber = null;
13841
13931
  }
13842
- const unsub = startCommandSubscription(cfg, logger, state.resolveAgentName, state.persistentGwClient, state.cronTimestampTracker);
13932
+ const unsub = startCommandSubscription(
13933
+ cfg,
13934
+ logger,
13935
+ state.resolveAgentName,
13936
+ state.persistentGwClient,
13937
+ state.cronTimestampTracker,
13938
+ { port: state.gatewayPort, hooksToken: state.gatewayToken }
13939
+ );
13843
13940
  state.commandUnsubscriber = unsub;
13844
13941
  } catch (err) {
13845
13942
  logger.debug("cohort-sync: gateway client connect failed", { error: String(err) });
@@ -14169,7 +14266,14 @@ function registerHookHandlers(api, logger, getState) {
14169
14266
  state.commandUnsubscriber();
14170
14267
  state.commandUnsubscriber = null;
14171
14268
  }
14172
- const unsub = startCommandSubscription(cfg, log, state.resolveAgentName, state.persistentGwClient, state.cronTimestampTracker);
14269
+ const unsub = startCommandSubscription(
14270
+ cfg,
14271
+ log,
14272
+ state.resolveAgentName,
14273
+ state.persistentGwClient,
14274
+ state.cronTimestampTracker,
14275
+ { port: state.gatewayPort, hooksToken: state.gatewayToken }
14276
+ );
14173
14277
  state.commandUnsubscriber = unsub;
14174
14278
  } catch (err) {
14175
14279
  log.debug("cohort-sync: gateway client lazy init failed", { error: String(err) });
@@ -14485,7 +14589,14 @@ function initializeHookState(api, cfg) {
14485
14589
  persistentGwClient = client2;
14486
14590
  gwClientInitialized = true;
14487
14591
  }
14488
- const commandUnsub = startCommandSubscription(cfg, logger, resolveAgentName, persistentGwClient, cronTimestampTracker);
14592
+ const commandUnsub = startCommandSubscription(
14593
+ cfg,
14594
+ logger,
14595
+ resolveAgentName,
14596
+ persistentGwClient,
14597
+ cronTimestampTracker,
14598
+ { port: gatewayPort, hooksToken: gatewayToken }
14599
+ );
14489
14600
  setToolRuntime({
14490
14601
  apiKey: cfg.apiKey,
14491
14602
  apiUrl: cfg.apiUrl,
@@ -14769,6 +14880,86 @@ Do not attempt more comments until tomorrow.`);
14769
14880
  }
14770
14881
  };
14771
14882
  });
14883
+ api.registerTool((toolCtx) => {
14884
+ const agentId = toolCtx.agentId ?? "main";
14885
+ return {
14886
+ name: "cohort_briefing_context",
14887
+ label: "cohort_briefing_context",
14888
+ description: "Fetch the prepared workspace context for a Cohort Home briefing request.",
14889
+ parameters: Type.Object({
14890
+ request_id: Type.String({ description: "Briefing request ID supplied by Cohort." })
14891
+ }),
14892
+ async execute(_toolCallId, params) {
14893
+ const rt = getToolRuntime();
14894
+ if (!rt.isReady) {
14895
+ return textResult("cohort_briefing_context is not ready yet \u2014 the plugin is still starting up.");
14896
+ }
14897
+ try {
14898
+ const response = await fetch(
14899
+ `${rt.apiUrl}/api/v1/briefings/${encodeURIComponent(params.request_id)}/context`,
14900
+ {
14901
+ method: "GET",
14902
+ headers: { "Authorization": `Bearer ${rt.apiKey}` },
14903
+ signal: AbortSignal.timeout(1e4)
14904
+ }
14905
+ );
14906
+ const body = await response.text();
14907
+ if (!response.ok) {
14908
+ return textResult(`Failed to fetch briefing context: ${response.status} ${body.slice(0, 300)}`);
14909
+ }
14910
+ const agentName = rt.resolveAgentName(agentId);
14911
+ return textResult(
14912
+ `Briefing context for ${agentName}:
14913
+
14914
+ ${body}`,
14915
+ JSON.parse(body)
14916
+ );
14917
+ } catch (err) {
14918
+ return textResult(`Failed to fetch briefing context: ${err instanceof Error ? err.message : String(err)}`);
14919
+ }
14920
+ }
14921
+ };
14922
+ });
14923
+ api.registerTool((toolCtx) => {
14924
+ const agentId = toolCtx.agentId ?? "main";
14925
+ return {
14926
+ name: "cohort_briefing",
14927
+ label: "cohort_briefing",
14928
+ description: "Submit the final generated text for a Cohort Home briefing request.",
14929
+ parameters: Type.Object({
14930
+ request_id: Type.String({ description: "Briefing request ID supplied by Cohort." }),
14931
+ content: Type.String({ description: "Final briefing text. Use exactly two short paragraphs." })
14932
+ }),
14933
+ async execute(_toolCallId, params) {
14934
+ const rt = getToolRuntime();
14935
+ if (!rt.isReady) {
14936
+ return textResult("cohort_briefing is not ready yet \u2014 the plugin is still starting up.");
14937
+ }
14938
+ const agentName = rt.resolveAgentName(agentId);
14939
+ try {
14940
+ const response = await fetch(
14941
+ `${rt.apiUrl}/api/v1/briefings/${encodeURIComponent(params.request_id)}`,
14942
+ {
14943
+ method: "POST",
14944
+ headers: {
14945
+ "Authorization": `Bearer ${rt.apiKey}`,
14946
+ "Content-Type": "application/json"
14947
+ },
14948
+ body: JSON.stringify({ agentName, content: params.content }),
14949
+ signal: AbortSignal.timeout(1e4)
14950
+ }
14951
+ );
14952
+ const body = await response.text();
14953
+ if (!response.ok) {
14954
+ return textResult(`Failed to submit briefing: ${response.status} ${body.slice(0, 300)}`);
14955
+ }
14956
+ return textResult("Briefing submitted.", JSON.parse(body));
14957
+ } catch (err) {
14958
+ return textResult(`Failed to submit briefing: ${err instanceof Error ? err.message : String(err)}`);
14959
+ }
14960
+ }
14961
+ };
14962
+ });
14772
14963
  api.registerTool(() => {
14773
14964
  return {
14774
14965
  name: "cohort_task",
@@ -14832,7 +15023,8 @@ Do not attempt more comments until tomorrow.`);
14832
15023
  }
14833
15024
  };
14834
15025
  });
14835
- api.registerTool(() => {
15026
+ api.registerTool((toolCtx) => {
15027
+ const agentId = toolCtx.agentId ?? "main";
14836
15028
  return {
14837
15029
  name: "cohort_transition",
14838
15030
  label: "cohort_transition",
@@ -14850,21 +15042,13 @@ Do not attempt more comments until tomorrow.`);
14850
15042
  if (!validStatuses.includes(params.status)) {
14851
15043
  return textResult(`Invalid status "${params.status}". Valid statuses: ${validStatuses.join(", ")}`);
14852
15044
  }
15045
+ const agentName = rt.resolveAgentName(agentId);
14853
15046
  try {
14854
- const res = await fetch(`${rt.apiUrl}/api/v1/tasks/${params.task_number}/transition`, {
14855
- method: "POST",
14856
- headers: {
14857
- "Authorization": `Bearer ${rt.apiKey}`,
14858
- "Content-Type": "application/json"
14859
- },
14860
- body: JSON.stringify({ to: params.status }),
14861
- signal: AbortSignal.timeout(1e4)
15047
+ await callTransitionFromPlugin(rt.apiKey, {
15048
+ taskNumber: params.task_number,
15049
+ agentName,
15050
+ targetStatus: params.status
14862
15051
  });
14863
- if (!res.ok) {
14864
- const body = await res.text();
14865
- return textResult(`Failed to transition task #${params.task_number} to "${params.status}": ${res.status} ${body.slice(0, 200)}`);
14866
- }
14867
- const task = await res.json();
14868
15052
  return textResult(`Task #${params.task_number} transitioned to "${params.status}".`);
14869
15053
  } catch (err) {
14870
15054
  return textResult(`Failed to transition task #${params.task_number}: ${err instanceof Error ? err.message : String(err)}`);
@@ -14872,8 +15056,7 @@ Do not attempt more comments until tomorrow.`);
14872
15056
  }
14873
15057
  };
14874
15058
  });
14875
- api.registerTool((toolCtx) => {
14876
- const agentId = toolCtx.agentId ?? "main";
15059
+ api.registerTool(() => {
14877
15060
  return {
14878
15061
  name: "cohort_assign",
14879
15062
  label: "cohort_assign",
@@ -14905,7 +15088,7 @@ Do not attempt more comments until tomorrow.`);
14905
15088
  const body = await res.text();
14906
15089
  return textResult(`Failed to assign task #${params.task_number}: ${res.status} ${body.slice(0, 200)}`);
14907
15090
  }
14908
- const task = await res.json();
15091
+ await res.json();
14909
15092
  const msg = assignee ? `Task #${params.task_number} assigned to ${assignee}.` : `Task #${params.task_number} unassigned.`;
14910
15093
  return textResult(msg);
14911
15094
  } catch (err) {
@@ -72,5 +72,5 @@
72
72
  }
73
73
  }
74
74
  },
75
- "version": "0.31.6"
75
+ "version": "0.31.8"
76
76
  }
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cfio/cohort-sync",
3
- "version": "0.31.6",
3
+ "version": "0.31.8",
4
4
  "description": "OpenClaw plugin — syncs agent telemetry, sessions, and activity to the Cohort dashboard",
5
5
  "type": "module",
6
6
  "main": "index.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cfio/cohort-sync",
3
- "version": "0.31.6",
3
+ "version": "0.31.8",
4
4
  "description": "OpenClaw plugin — syncs agent telemetry, sessions, and activity to the Cohort dashboard",
5
5
  "license": "MIT",
6
6
  "homepage": "https://docs.cohort.bot/gateway",