openclaw-remote 0.5.2 → 0.5.4

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.
Files changed (2) hide show
  1. package/dist/index.js +82 -55
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2798,6 +2798,24 @@ var { setRuntime: setRemoteRuntime, getRuntime: getRemoteRuntime } = createPlugi
2798
2798
  );
2799
2799
 
2800
2800
  // src/channel.ts
2801
+ function readJsonBody(req) {
2802
+ return new Promise((resolve, reject) => {
2803
+ const chunks = [];
2804
+ req.on("data", (chunk) => chunks.push(chunk));
2805
+ req.on("end", () => {
2806
+ try {
2807
+ resolve(JSON.parse(Buffer.concat(chunks).toString("utf-8")));
2808
+ } catch {
2809
+ resolve(null);
2810
+ }
2811
+ });
2812
+ req.on("error", reject);
2813
+ });
2814
+ }
2815
+ function respondJson(res, status, data) {
2816
+ res.writeHead(status, { "Content-Type": "application/json" });
2817
+ res.end(JSON.stringify(data));
2818
+ }
2801
2819
  var CHANNEL_ID = "remote";
2802
2820
  var activeRouteUnregisters = /* @__PURE__ */ new Map();
2803
2821
  function waitUntilAbort(signal, onAbort) {
@@ -2996,62 +3014,62 @@ function createRemotePlugin() {
2996
3014
  log?.info?.(
2997
3015
  `Starting Remote channel (account: ${accountId}, webhookPath: ${account.webhookPath})`
2998
3016
  );
2999
- const handler = async (req) => {
3017
+ const handler = async (req, res) => {
3000
3018
  if (req.method !== "POST") {
3001
- return { status: 405, body: { error: "Method not allowed" } };
3019
+ respondJson(res, 405, { error: "Method not allowed" });
3020
+ return;
3002
3021
  }
3003
- const payload = req.body;
3022
+ const payload = await readJsonBody(req);
3004
3023
  if (!payload || !payload.event || !payload.task_id) {
3005
- return { status: 400, body: { error: "Invalid payload: missing event or task_id" } };
3024
+ respondJson(res, 400, { error: "Invalid payload: missing event or task_id" });
3025
+ return;
3006
3026
  }
3007
3027
  log?.info?.(`Webhook received: ${payload.event} for task ${payload.task_id} (agent: ${payload.agent_name})`);
3028
+ respondJson(res, 200, { ok: true, event: payload.event });
3008
3029
  const body = formatWebhookEvent(payload);
3009
3030
  const sessionKey = `remote:${account.accountId}:${payload.task_id}`;
3010
- (async () => {
3011
- try {
3012
- const rt = getRemoteRuntime();
3013
- const currentCfg = await rt.config.loadConfig();
3014
- const msgCtx = rt.channel.reply.finalizeInboundContext({
3015
- Body: body,
3016
- RawBody: body,
3017
- CommandBody: body,
3018
- From: `remote:${payload.task_id}`,
3019
- To: `remote:${account.accountId}`,
3020
- SessionKey: sessionKey,
3021
- AccountId: account.accountId,
3022
- OriginatingChannel: CHANNEL_ID,
3023
- OriginatingTo: `remote:${payload.task_id}`,
3024
- ChatType: "direct",
3025
- SenderName: payload.author_name || "Remote Board",
3026
- SenderId: payload.task_id,
3027
- Provider: CHANNEL_ID,
3028
- Surface: CHANNEL_ID,
3029
- ConversationLabel: payload.task_title || `Task ${payload.task_id}`,
3030
- Timestamp: Date.now()
3031
- });
3032
- await rt.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
3033
- ctx: msgCtx,
3034
- cfg: currentCfg,
3035
- dispatcherOptions: {
3036
- deliver: async (deliverPayload) => {
3037
- if (deliverPayload.isReasoning) return;
3038
- const text = deliverPayload?.text ?? deliverPayload?.body;
3039
- if (text) {
3040
- await postComment(account, payload.task_id, text);
3041
- }
3042
- },
3043
- onReplyStart: () => {
3044
- log?.info?.(`Agent reply started for task ${payload.task_id}`);
3031
+ try {
3032
+ const rt = getRemoteRuntime();
3033
+ const currentCfg = await rt.config.loadConfig();
3034
+ const msgCtx = rt.channel.reply.finalizeInboundContext({
3035
+ Body: body,
3036
+ RawBody: body,
3037
+ CommandBody: body,
3038
+ From: `remote:${payload.task_id}`,
3039
+ To: `remote:${account.accountId}`,
3040
+ SessionKey: sessionKey,
3041
+ AccountId: account.accountId,
3042
+ OriginatingChannel: CHANNEL_ID,
3043
+ OriginatingTo: `remote:${payload.task_id}`,
3044
+ ChatType: "direct",
3045
+ SenderName: payload.author_name || "Remote Board",
3046
+ SenderId: payload.task_id,
3047
+ Provider: CHANNEL_ID,
3048
+ Surface: CHANNEL_ID,
3049
+ ConversationLabel: payload.task_title || `Task ${payload.task_id}`,
3050
+ Timestamp: Date.now()
3051
+ });
3052
+ await rt.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
3053
+ ctx: msgCtx,
3054
+ cfg: currentCfg,
3055
+ dispatcherOptions: {
3056
+ deliver: async (deliverPayload) => {
3057
+ if (deliverPayload.isReasoning) return;
3058
+ const text = deliverPayload?.text ?? deliverPayload?.body;
3059
+ if (text) {
3060
+ await postComment(account, payload.task_id, text);
3045
3061
  }
3062
+ },
3063
+ onReplyStart: () => {
3064
+ log?.info?.(`Agent reply started for task ${payload.task_id}`);
3046
3065
  }
3047
- });
3048
- } catch (err) {
3049
- log?.error?.(
3050
- `Error dispatching webhook event: ${err instanceof Error ? err.message : String(err)}`
3051
- );
3052
- }
3053
- })();
3054
- return { status: 200, body: { ok: true, event: payload.event } };
3066
+ }
3067
+ });
3068
+ } catch (err) {
3069
+ log?.error?.(
3070
+ `Error dispatching webhook event: ${err instanceof Error ? err.message : String(err)}`
3071
+ );
3072
+ }
3055
3073
  };
3056
3074
  const routeKey = `${accountId}:${account.webhookPath}`;
3057
3075
  const prevUnregister = activeRouteUnregisters.get(routeKey);
@@ -3083,6 +3101,15 @@ function createRemotePlugin() {
3083
3101
  },
3084
3102
  agentTools: ((params) => {
3085
3103
  const cfg = params.cfg;
3104
+ const resolveToolAccount = () => {
3105
+ if (params.accountId) return resolveAccount(cfg ?? {}, params.accountId);
3106
+ const ids = listAccountIds(cfg ?? {});
3107
+ for (const id of ids) {
3108
+ const acct = resolveAccount(cfg ?? {}, id);
3109
+ if (acct.enabled && acct.apiKey) return acct;
3110
+ }
3111
+ return resolveAccount(cfg ?? {});
3112
+ };
3086
3113
  return [
3087
3114
  // 1. remote_create_task
3088
3115
  {
@@ -3106,7 +3133,7 @@ function createRemotePlugin() {
3106
3133
  )
3107
3134
  }),
3108
3135
  execute: async (_toolCallId, args) => {
3109
- const account = resolveAccount(cfg ?? {});
3136
+ const account = resolveToolAccount();
3110
3137
  const result = await createTask(account, {
3111
3138
  title: args.title,
3112
3139
  description: args.description,
@@ -3165,7 +3192,7 @@ function createRemotePlugin() {
3165
3192
  )
3166
3193
  }),
3167
3194
  execute: async (_toolCallId, args) => {
3168
- const account = resolveAccount(cfg ?? {});
3195
+ const account = resolveToolAccount();
3169
3196
  const { task_id, ...updates } = args;
3170
3197
  const result = await updateTask(account, task_id, updates);
3171
3198
  if (!result.ok) {
@@ -3202,7 +3229,7 @@ function createRemotePlugin() {
3202
3229
  )
3203
3230
  }),
3204
3231
  execute: async (_toolCallId, args) => {
3205
- const account = resolveAccount(cfg ?? {});
3232
+ const account = resolveToolAccount();
3206
3233
  const result = await listTasks(account, {
3207
3234
  status: args.status,
3208
3235
  assigned_to: args.assigned_to
@@ -3251,7 +3278,7 @@ function createRemotePlugin() {
3251
3278
  description: "Get board health and statistics from the Remote project board: pending tasks, in-progress tasks, unassigned tasks, recent activity, and your roles.",
3252
3279
  parameters: Type.Object({}),
3253
3280
  execute: async (_toolCallId, _args) => {
3254
- const account = resolveAccount(cfg ?? {});
3281
+ const account = resolveToolAccount();
3255
3282
  const result = await getBoardHealth(account);
3256
3283
  if (!result.ok) {
3257
3284
  const legacyResult = await getHeartbeat(account);
@@ -3320,7 +3347,7 @@ function createRemotePlugin() {
3320
3347
  description: "List project roles with assignment info. Use to find valid assigned_role_id values for task creation.",
3321
3348
  parameters: Type.Object({}),
3322
3349
  execute: async (_toolCallId, _args) => {
3323
- const account = resolveAccount(cfg ?? {});
3350
+ const account = resolveToolAccount();
3324
3351
  const result = await listRoles(account);
3325
3352
  if (!result.ok) {
3326
3353
  return {
@@ -3354,7 +3381,7 @@ function createRemotePlugin() {
3354
3381
  description: "List epics for the project. Use to find valid epic_id values for task grouping.",
3355
3382
  parameters: Type.Object({}),
3356
3383
  execute: async (_toolCallId, _args) => {
3357
- const account = resolveAccount(cfg ?? {});
3384
+ const account = resolveToolAccount();
3358
3385
  const result = await listEpics(account);
3359
3386
  if (!result.ok) {
3360
3387
  return {
@@ -3394,7 +3421,7 @@ function createRemotePlugin() {
3394
3421
  color: Type.Optional(Type.String({ description: "Epic color (hex, e.g. #6366f1)" }))
3395
3422
  }),
3396
3423
  execute: async (_toolCallId, args) => {
3397
- const account = resolveAccount(cfg ?? {});
3424
+ const account = resolveToolAccount();
3398
3425
  const result = await createEpic(account, {
3399
3426
  name: args.name,
3400
3427
  description: args.description,
@@ -3426,7 +3453,7 @@ function createRemotePlugin() {
3426
3453
  description: "List all team members (humans and agents) with their roles and @mention handles. Use to find who to tag in comments or assign tasks to.",
3427
3454
  parameters: Type.Object({}),
3428
3455
  execute: async (_toolCallId, _args) => {
3429
- const account = resolveAccount(cfg ?? {});
3456
+ const account = resolveToolAccount();
3430
3457
  const result = await getTeam(account);
3431
3458
  if (!result.ok) {
3432
3459
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openclaw-remote",
3
- "version": "0.5.2",
3
+ "version": "0.5.4",
4
4
  "description": "Remote project board channel plugin for OpenClaw",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",