@analyticscli/growth-engineer 0.1.1-preview.13 → 0.1.1-preview.14
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.
|
@@ -140,12 +140,20 @@ function printMessages(messages) {
|
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
-
function
|
|
143
|
+
function truncateDiscordText(value, maxLength) {
|
|
144
|
+
const text = String(value || "").trim();
|
|
145
|
+
if (text.length <= maxLength) {
|
|
146
|
+
return text;
|
|
147
|
+
}
|
|
148
|
+
return `${text.slice(0, Math.max(0, maxLength - 3)).trim()}...`;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function chunkEmbedDescription(content) {
|
|
144
152
|
const chunks = [];
|
|
145
|
-
const maxLength =
|
|
146
|
-
let remaining = content.trim();
|
|
153
|
+
const maxLength = 4000;
|
|
154
|
+
let remaining = String(content || "").trim();
|
|
147
155
|
|
|
148
|
-
while (remaining.length > maxLength) {
|
|
156
|
+
while (remaining.length > maxLength && chunks.length < 9) {
|
|
149
157
|
let splitAt = remaining.lastIndexOf("\n", maxLength);
|
|
150
158
|
if (splitAt < maxLength * 0.5) {
|
|
151
159
|
splitAt = remaining.lastIndexOf(" ", maxLength);
|
|
@@ -158,27 +166,69 @@ function chunkMessage(content) {
|
|
|
158
166
|
}
|
|
159
167
|
|
|
160
168
|
if (remaining) {
|
|
161
|
-
chunks.push(remaining);
|
|
169
|
+
chunks.push(truncateDiscordText(remaining, maxLength));
|
|
162
170
|
}
|
|
163
|
-
return chunks;
|
|
171
|
+
return chunks.slice(0, 10);
|
|
164
172
|
}
|
|
165
173
|
|
|
166
|
-
function
|
|
167
|
-
|
|
174
|
+
function plainTextToEmbedPayload(input) {
|
|
175
|
+
const text = String(input || "").trim();
|
|
176
|
+
if (!text) {
|
|
168
177
|
return null;
|
|
169
178
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
179
|
+
|
|
180
|
+
const lines = text.split(/\r?\n/);
|
|
181
|
+
const firstLineIndex = Math.max(0, lines.findIndex((line) => line.trim()));
|
|
182
|
+
const firstLine = lines[firstLineIndex]?.trim() || "OpenClaw update";
|
|
183
|
+
const title = truncateDiscordText(firstLine, 256);
|
|
184
|
+
const body = lines.slice(firstLineIndex + 1).join("\n").trim();
|
|
185
|
+
const descriptionChunks = chunkEmbedDescription(body || (firstLine.length > 256 ? firstLine : ""));
|
|
186
|
+
const embeds = [];
|
|
187
|
+
|
|
188
|
+
if (descriptionChunks.length === 0) {
|
|
189
|
+
embeds.push({
|
|
190
|
+
title,
|
|
191
|
+
color: 0x2f81f7,
|
|
192
|
+
timestamp: new Date().toISOString(),
|
|
193
|
+
});
|
|
194
|
+
} else {
|
|
195
|
+
for (const [index, description] of descriptionChunks.entries()) {
|
|
196
|
+
embeds.push({
|
|
197
|
+
...(index === 0 ? { title } : {}),
|
|
198
|
+
description,
|
|
199
|
+
color: 0x2f81f7,
|
|
200
|
+
timestamp: new Date().toISOString(),
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return {
|
|
206
|
+
content: "",
|
|
207
|
+
embeds,
|
|
208
|
+
fallbackText: text,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function normalizeEmbedPayload(input) {
|
|
213
|
+
const raw = String(input || "");
|
|
214
|
+
if (process.env.OPENCLAW_DISCORD_DELIVERY_FORMAT === "embed" || process.argv.includes("--json") || raw.trim().startsWith("{")) {
|
|
215
|
+
try {
|
|
216
|
+
const payload = JSON.parse(raw);
|
|
217
|
+
const embeds = Array.isArray(payload.embeds) ? payload.embeds : [];
|
|
218
|
+
if (embeds.length > 0) {
|
|
219
|
+
return {
|
|
220
|
+
content: String(payload.content || "").slice(0, 2000),
|
|
221
|
+
embeds: embeds.slice(0, 10),
|
|
222
|
+
fallbackText: String(payload.fallbackText || payload.fallback_text || "").trim(),
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
} catch {
|
|
226
|
+
if (process.argv.includes("--json")) {
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
181
230
|
}
|
|
231
|
+
return plainTextToEmbedPayload(raw);
|
|
182
232
|
}
|
|
183
233
|
|
|
184
234
|
async function sendDiscordPayload(payload) {
|
|
@@ -204,26 +254,7 @@ async function sendMessage(content) {
|
|
|
204
254
|
return await sendDiscordPayload(embedPayload);
|
|
205
255
|
}
|
|
206
256
|
|
|
207
|
-
|
|
208
|
-
if (chunks.length === 0) {
|
|
209
|
-
throw new Error("Refusing to send an empty message.");
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
const sent = [];
|
|
213
|
-
for (const target of DISCORD_TARGETS) {
|
|
214
|
-
await validateTargetChannel(target);
|
|
215
|
-
for (const chunk of chunks) {
|
|
216
|
-
const message = await discordFetch(`/channels/${target.channelId}/messages`, {
|
|
217
|
-
method: "POST",
|
|
218
|
-
body: JSON.stringify({
|
|
219
|
-
allowed_mentions: { parse: [], users: target.allowedMentionUsers },
|
|
220
|
-
content: chunk,
|
|
221
|
-
}),
|
|
222
|
-
});
|
|
223
|
-
sent.push({ target, message });
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
return sent;
|
|
257
|
+
throw new Error("Refusing to send an empty message.");
|
|
227
258
|
}
|
|
228
259
|
|
|
229
260
|
async function readStdin() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@analyticscli/growth-engineer",
|
|
3
|
-
"version": "0.1.1-preview.
|
|
3
|
+
"version": "0.1.1-preview.14",
|
|
4
4
|
"description": "Growth Engineer CLI for connector setup, scheduling, health checks, and OpenClaw-compatible growth runs.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|