@alfe.ai/openclaw-google-chat 0.0.4 → 0.0.6
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/plugin2.cjs +41 -18
- package/dist/plugin2.js +41 -18
- package/package.json +1 -1
package/dist/plugin2.cjs
CHANGED
|
@@ -156,9 +156,36 @@ async function listMembers(token, spaceName) {
|
|
|
156
156
|
} while (pageToken);
|
|
157
157
|
return allMembers;
|
|
158
158
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
159
|
+
//#endregion
|
|
160
|
+
//#region src/markdown-to-gchat.ts
|
|
161
|
+
/**
|
|
162
|
+
* Convert standard Markdown to Google Chat text formatting.
|
|
163
|
+
*
|
|
164
|
+
* Google Chat supports: *bold*, _italic_, ~strikethrough~, `code`,
|
|
165
|
+
* ```code blocks```, but NOT standard Markdown syntax like **bold**,
|
|
166
|
+
* ## headings, or - bullet lists.
|
|
167
|
+
*/
|
|
168
|
+
const CODE_BLOCK_RE = /```[\s\S]*?```/g;
|
|
169
|
+
const INLINE_CODE_RE = /`[^`]+`/g;
|
|
170
|
+
function markdownToGChat(text) {
|
|
171
|
+
const preserved = [];
|
|
172
|
+
const placeholder = (i) => `\x00CODE${String(i)}\x00`;
|
|
173
|
+
let result = text.replace(CODE_BLOCK_RE, (match) => {
|
|
174
|
+
preserved.push(match);
|
|
175
|
+
return placeholder(preserved.length - 1);
|
|
176
|
+
});
|
|
177
|
+
result = result.replace(INLINE_CODE_RE, (match) => {
|
|
178
|
+
preserved.push(match);
|
|
179
|
+
return placeholder(preserved.length - 1);
|
|
180
|
+
});
|
|
181
|
+
result = result.replace(/^#{1,6}\s+(.+)$/gm, "*$1*");
|
|
182
|
+
result = result.replace(/\*\*(.+?)\*\*/g, "*$1*");
|
|
183
|
+
result = result.replace(/__(.+?)__/g, "*$1*");
|
|
184
|
+
result = result.replace(/~~(.+?)~~/g, "~$1~");
|
|
185
|
+
result = result.replace(/^[\s]*[-*]\s+/gm, "• ");
|
|
186
|
+
result = result.replace(/\[([^\]]+)\]\(([^)]+)\)/g, "$1 ($2)");
|
|
187
|
+
for (let i = preserved.length - 1; i >= 0; i--) result = result.replace(placeholder(i), () => preserved[i]);
|
|
188
|
+
return result;
|
|
162
189
|
}
|
|
163
190
|
//#endregion
|
|
164
191
|
//#region src/gchat-poller.ts
|
|
@@ -171,7 +198,6 @@ const WARM_THRESHOLD_MS = 1800 * 1e3;
|
|
|
171
198
|
const DORMANT_THRESHOLD_MS = 7200 * 1e3;
|
|
172
199
|
const DISCOVERY_INTERVAL_MS = 3e4;
|
|
173
200
|
const DEDUP_SIZE = 100;
|
|
174
|
-
const BACKFILL_COUNT = 20;
|
|
175
201
|
const MAX_RETRY_DELAY_MS = 6e4;
|
|
176
202
|
const BASE_RETRY_DELAY_MS = 2e3;
|
|
177
203
|
var GChatPoller = class {
|
|
@@ -254,13 +280,7 @@ var GChatPoller = class {
|
|
|
254
280
|
} catch (err) {
|
|
255
281
|
this.log.warn(`Failed to resolve members for ${spaceName}: ${err instanceof Error ? err.message : String(err)}`);
|
|
256
282
|
}
|
|
257
|
-
|
|
258
|
-
try {
|
|
259
|
-
const recent = await listRecentMessages(token, spaceName, BACKFILL_COUNT);
|
|
260
|
-
if (recent.length > 0) lastSeenTimestamp = recent[recent.length - 1].createTime;
|
|
261
|
-
} catch (err) {
|
|
262
|
-
this.log.warn(`Backfill failed for ${spaceName}: ${err instanceof Error ? err.message : String(err)}`);
|
|
263
|
-
}
|
|
283
|
+
const lastSeenTimestamp = this.stateManager.getLastSeenTimestamp(spaceName) || (/* @__PURE__ */ new Date()).toISOString();
|
|
264
284
|
this.stateManager.updateSpace(spaceName, {
|
|
265
285
|
lastSeenTimestamp,
|
|
266
286
|
agentUserId,
|
|
@@ -355,7 +375,9 @@ var GChatPoller = class {
|
|
|
355
375
|
return;
|
|
356
376
|
}
|
|
357
377
|
const conversationId = `alfe:gchat:${state.spaceName}`;
|
|
358
|
-
const
|
|
378
|
+
const senderName = message.sender.name || state.peerUserId;
|
|
379
|
+
const senderDisplayName = message.sender.displayName;
|
|
380
|
+
const peerLabel = senderDisplayName || state.peerDisplayName || "User";
|
|
359
381
|
this.log.info(`Dispatching message from ${peerLabel} in ${state.spaceName}`);
|
|
360
382
|
try {
|
|
361
383
|
const cfg = this.runtime.config.loadConfig();
|
|
@@ -367,10 +389,10 @@ var GChatPoller = class {
|
|
|
367
389
|
accountId: "default",
|
|
368
390
|
peer: {
|
|
369
391
|
kind: "direct",
|
|
370
|
-
id: `gchat:${
|
|
392
|
+
id: `gchat:${senderName}:conv:${conversationId}`
|
|
371
393
|
},
|
|
372
|
-
senderId: `gchat:${
|
|
373
|
-
senderAddress: `user:gchat:${
|
|
394
|
+
senderId: `gchat:${senderName}`,
|
|
395
|
+
senderAddress: `user:gchat:${senderName}`,
|
|
374
396
|
recipientAddress: "agent",
|
|
375
397
|
conversationLabel: `[Google Chat] ${peerLabel}`,
|
|
376
398
|
rawBody: message.text,
|
|
@@ -379,11 +401,12 @@ var GChatPoller = class {
|
|
|
379
401
|
extraContext: {
|
|
380
402
|
ChannelMode: "gchat",
|
|
381
403
|
ConversationId: conversationId,
|
|
382
|
-
...
|
|
404
|
+
...senderDisplayName ? { SenderName: senderDisplayName } : {}
|
|
383
405
|
},
|
|
384
406
|
deliver: async (payload) => {
|
|
385
|
-
const
|
|
386
|
-
if (!
|
|
407
|
+
const raw = payload.text ?? "";
|
|
408
|
+
if (!raw) return;
|
|
409
|
+
const text = markdownToGChat(raw);
|
|
387
410
|
try {
|
|
388
411
|
await sendMessage(await this.tokenManager.getAccessToken(), state.spaceName, text);
|
|
389
412
|
} catch (err) {
|
package/dist/plugin2.js
CHANGED
|
@@ -156,9 +156,36 @@ async function listMembers(token, spaceName) {
|
|
|
156
156
|
} while (pageToken);
|
|
157
157
|
return allMembers;
|
|
158
158
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
159
|
+
//#endregion
|
|
160
|
+
//#region src/markdown-to-gchat.ts
|
|
161
|
+
/**
|
|
162
|
+
* Convert standard Markdown to Google Chat text formatting.
|
|
163
|
+
*
|
|
164
|
+
* Google Chat supports: *bold*, _italic_, ~strikethrough~, `code`,
|
|
165
|
+
* ```code blocks```, but NOT standard Markdown syntax like **bold**,
|
|
166
|
+
* ## headings, or - bullet lists.
|
|
167
|
+
*/
|
|
168
|
+
const CODE_BLOCK_RE = /```[\s\S]*?```/g;
|
|
169
|
+
const INLINE_CODE_RE = /`[^`]+`/g;
|
|
170
|
+
function markdownToGChat(text) {
|
|
171
|
+
const preserved = [];
|
|
172
|
+
const placeholder = (i) => `\x00CODE${String(i)}\x00`;
|
|
173
|
+
let result = text.replace(CODE_BLOCK_RE, (match) => {
|
|
174
|
+
preserved.push(match);
|
|
175
|
+
return placeholder(preserved.length - 1);
|
|
176
|
+
});
|
|
177
|
+
result = result.replace(INLINE_CODE_RE, (match) => {
|
|
178
|
+
preserved.push(match);
|
|
179
|
+
return placeholder(preserved.length - 1);
|
|
180
|
+
});
|
|
181
|
+
result = result.replace(/^#{1,6}\s+(.+)$/gm, "*$1*");
|
|
182
|
+
result = result.replace(/\*\*(.+?)\*\*/g, "*$1*");
|
|
183
|
+
result = result.replace(/__(.+?)__/g, "*$1*");
|
|
184
|
+
result = result.replace(/~~(.+?)~~/g, "~$1~");
|
|
185
|
+
result = result.replace(/^[\s]*[-*]\s+/gm, "• ");
|
|
186
|
+
result = result.replace(/\[([^\]]+)\]\(([^)]+)\)/g, "$1 ($2)");
|
|
187
|
+
for (let i = preserved.length - 1; i >= 0; i--) result = result.replace(placeholder(i), () => preserved[i]);
|
|
188
|
+
return result;
|
|
162
189
|
}
|
|
163
190
|
//#endregion
|
|
164
191
|
//#region src/gchat-poller.ts
|
|
@@ -171,7 +198,6 @@ const WARM_THRESHOLD_MS = 1800 * 1e3;
|
|
|
171
198
|
const DORMANT_THRESHOLD_MS = 7200 * 1e3;
|
|
172
199
|
const DISCOVERY_INTERVAL_MS = 3e4;
|
|
173
200
|
const DEDUP_SIZE = 100;
|
|
174
|
-
const BACKFILL_COUNT = 20;
|
|
175
201
|
const MAX_RETRY_DELAY_MS = 6e4;
|
|
176
202
|
const BASE_RETRY_DELAY_MS = 2e3;
|
|
177
203
|
var GChatPoller = class {
|
|
@@ -254,13 +280,7 @@ var GChatPoller = class {
|
|
|
254
280
|
} catch (err) {
|
|
255
281
|
this.log.warn(`Failed to resolve members for ${spaceName}: ${err instanceof Error ? err.message : String(err)}`);
|
|
256
282
|
}
|
|
257
|
-
|
|
258
|
-
try {
|
|
259
|
-
const recent = await listRecentMessages(token, spaceName, BACKFILL_COUNT);
|
|
260
|
-
if (recent.length > 0) lastSeenTimestamp = recent[recent.length - 1].createTime;
|
|
261
|
-
} catch (err) {
|
|
262
|
-
this.log.warn(`Backfill failed for ${spaceName}: ${err instanceof Error ? err.message : String(err)}`);
|
|
263
|
-
}
|
|
283
|
+
const lastSeenTimestamp = this.stateManager.getLastSeenTimestamp(spaceName) || (/* @__PURE__ */ new Date()).toISOString();
|
|
264
284
|
this.stateManager.updateSpace(spaceName, {
|
|
265
285
|
lastSeenTimestamp,
|
|
266
286
|
agentUserId,
|
|
@@ -355,7 +375,9 @@ var GChatPoller = class {
|
|
|
355
375
|
return;
|
|
356
376
|
}
|
|
357
377
|
const conversationId = `alfe:gchat:${state.spaceName}`;
|
|
358
|
-
const
|
|
378
|
+
const senderName = message.sender.name || state.peerUserId;
|
|
379
|
+
const senderDisplayName = message.sender.displayName;
|
|
380
|
+
const peerLabel = senderDisplayName || state.peerDisplayName || "User";
|
|
359
381
|
this.log.info(`Dispatching message from ${peerLabel} in ${state.spaceName}`);
|
|
360
382
|
try {
|
|
361
383
|
const cfg = this.runtime.config.loadConfig();
|
|
@@ -367,10 +389,10 @@ var GChatPoller = class {
|
|
|
367
389
|
accountId: "default",
|
|
368
390
|
peer: {
|
|
369
391
|
kind: "direct",
|
|
370
|
-
id: `gchat:${
|
|
392
|
+
id: `gchat:${senderName}:conv:${conversationId}`
|
|
371
393
|
},
|
|
372
|
-
senderId: `gchat:${
|
|
373
|
-
senderAddress: `user:gchat:${
|
|
394
|
+
senderId: `gchat:${senderName}`,
|
|
395
|
+
senderAddress: `user:gchat:${senderName}`,
|
|
374
396
|
recipientAddress: "agent",
|
|
375
397
|
conversationLabel: `[Google Chat] ${peerLabel}`,
|
|
376
398
|
rawBody: message.text,
|
|
@@ -379,11 +401,12 @@ var GChatPoller = class {
|
|
|
379
401
|
extraContext: {
|
|
380
402
|
ChannelMode: "gchat",
|
|
381
403
|
ConversationId: conversationId,
|
|
382
|
-
...
|
|
404
|
+
...senderDisplayName ? { SenderName: senderDisplayName } : {}
|
|
383
405
|
},
|
|
384
406
|
deliver: async (payload) => {
|
|
385
|
-
const
|
|
386
|
-
if (!
|
|
407
|
+
const raw = payload.text ?? "";
|
|
408
|
+
if (!raw) return;
|
|
409
|
+
const text = markdownToGChat(raw);
|
|
387
410
|
try {
|
|
388
411
|
await sendMessage(await this.tokenManager.getAccessToken(), state.spaceName, text);
|
|
389
412
|
} catch (err) {
|
package/package.json
CHANGED