@goplausible/openclaw-algorand-plugin 1.9.1 → 1.9.3
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/index.ts +102 -32
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/skills/algorand-interaction/SKILL.md +13 -1
package/index.ts
CHANGED
|
@@ -231,47 +231,117 @@ function ensureWorkspaceMemoryIndex(workspacePath: string): { success: boolean;
|
|
|
231
231
|
return { success: true, message: `Added NEVER FORGET section to ${existingPath}` };
|
|
232
232
|
}
|
|
233
233
|
|
|
234
|
-
// NEVER FORGET exists —
|
|
235
|
-
//
|
|
236
|
-
const
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
const fingerprint = line.slice(2, 52).trim();
|
|
252
|
-
if (!existingNFContent.includes(fingerprint)) {
|
|
253
|
-
newLines.push(line);
|
|
234
|
+
// NEVER FORGET exists — update each subsection individually
|
|
235
|
+
// Parse template into subsections: { header: string, content: string }[]
|
|
236
|
+
const parseSubsections = (text: string): { header: string; content: string }[] => {
|
|
237
|
+
const sections: { header: string; content: string }[] = [];
|
|
238
|
+
const lines = text.split("\n");
|
|
239
|
+
let currentHeader = "";
|
|
240
|
+
let currentLines: string[] = [];
|
|
241
|
+
|
|
242
|
+
for (const line of lines) {
|
|
243
|
+
if (line.startsWith("### ")) {
|
|
244
|
+
if (currentHeader) {
|
|
245
|
+
sections.push({ header: currentHeader, content: currentLines.join("\n").trimEnd() });
|
|
246
|
+
}
|
|
247
|
+
currentHeader = line;
|
|
248
|
+
currentLines = [];
|
|
249
|
+
} else if (currentHeader) {
|
|
250
|
+
currentLines.push(line);
|
|
254
251
|
}
|
|
255
252
|
}
|
|
256
|
-
|
|
253
|
+
if (currentHeader) {
|
|
254
|
+
sections.push({ header: currentHeader, content: currentLines.join("\n").trimEnd() });
|
|
255
|
+
}
|
|
256
|
+
return sections;
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
const templateSections = parseSubsections(templateNeverForget);
|
|
257
260
|
|
|
258
|
-
|
|
261
|
+
// Extract existing NEVER FORGET section boundaries
|
|
262
|
+
const nfSectionMatch = existing.match(/(## NEVER FORGET\n)([\s\S]*?)(?=\n## (?!#)|$)/);
|
|
263
|
+
if (!nfSectionMatch) {
|
|
259
264
|
return { success: true, message: `NEVER FORGET section in ${existingPath} is up to date` };
|
|
260
265
|
}
|
|
261
266
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
if (
|
|
267
|
-
|
|
268
|
-
const
|
|
269
|
-
|
|
270
|
-
|
|
267
|
+
let nfContent = nfSectionMatch[2];
|
|
268
|
+
let updated = false;
|
|
269
|
+
|
|
270
|
+
for (const templateSec of templateSections) {
|
|
271
|
+
if (templateSec.header === "### Never Do This") {
|
|
272
|
+
// Special handling: merge individual bullet items
|
|
273
|
+
const neverDoRegex = new RegExp(
|
|
274
|
+
"(### Never Do This\\n)([\\s\\S]*?)(?=\\n### |$)"
|
|
275
|
+
);
|
|
276
|
+
const existingNeverDoMatch = nfContent.match(neverDoRegex);
|
|
277
|
+
|
|
278
|
+
if (!existingNeverDoMatch) {
|
|
279
|
+
// Section doesn't exist — append it
|
|
280
|
+
nfContent = nfContent.trimEnd() + "\n\n" + templateSec.header + "\n" + templateSec.content + "\n";
|
|
281
|
+
updated = true;
|
|
282
|
+
} else {
|
|
283
|
+
// Section exists — check each bullet item
|
|
284
|
+
let existingBullets = existingNeverDoMatch[2];
|
|
285
|
+
const templateBullets = templateSec.content.split("\n").filter((l: string) => l.startsWith("* "));
|
|
286
|
+
const existingBulletLines = existingBullets.split("\n").filter((l: string) => l.startsWith("* "));
|
|
287
|
+
|
|
288
|
+
for (const bullet of templateBullets) {
|
|
289
|
+
// Use first 50 chars after "* " as fingerprint for matching
|
|
290
|
+
const fingerprint = bullet.slice(2, 52).trim();
|
|
291
|
+
const existingMatch = existingBulletLines.find(l => l.includes(fingerprint));
|
|
292
|
+
|
|
293
|
+
if (existingMatch) {
|
|
294
|
+
// Item exists — overwrite with template version
|
|
295
|
+
if (existingMatch !== bullet) {
|
|
296
|
+
nfContent = nfContent.replace(existingMatch, bullet);
|
|
297
|
+
updated = true;
|
|
298
|
+
}
|
|
299
|
+
} else {
|
|
300
|
+
// Item doesn't exist — append it
|
|
301
|
+
existingBullets = existingBullets.trimEnd() + "\n" + bullet;
|
|
302
|
+
nfContent = nfContent.replace(existingNeverDoMatch[2], existingBullets);
|
|
303
|
+
updated = true;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
} else {
|
|
308
|
+
// Non-"Never Do This" subsections: overwrite entire subsection if exists, add if not
|
|
309
|
+
const sectionRegex = new RegExp(
|
|
310
|
+
"(" + templateSec.header.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + "\\n)([\\s\\S]*?)(?=\\n### |$)"
|
|
311
|
+
);
|
|
312
|
+
const existingSecMatch = nfContent.match(sectionRegex);
|
|
313
|
+
|
|
314
|
+
if (existingSecMatch) {
|
|
315
|
+
// Section exists — overwrite its content
|
|
316
|
+
if (existingSecMatch[2].trimEnd() !== templateSec.content) {
|
|
317
|
+
nfContent = nfContent.replace(
|
|
318
|
+
existingSecMatch[0],
|
|
319
|
+
templateSec.header + "\n" + templateSec.content
|
|
320
|
+
);
|
|
321
|
+
updated = true;
|
|
322
|
+
}
|
|
323
|
+
} else {
|
|
324
|
+
// Section doesn't exist — insert before "### Never Do This" or append
|
|
325
|
+
const neverDoPos = nfContent.indexOf("### Never Do This");
|
|
326
|
+
if (neverDoPos !== -1) {
|
|
327
|
+
nfContent = nfContent.slice(0, neverDoPos) + templateSec.header + "\n" + templateSec.content + "\n\n" + nfContent.slice(neverDoPos);
|
|
328
|
+
} else {
|
|
329
|
+
nfContent = nfContent.trimEnd() + "\n\n" + templateSec.header + "\n" + templateSec.content + "\n";
|
|
330
|
+
}
|
|
331
|
+
updated = true;
|
|
332
|
+
}
|
|
271
333
|
}
|
|
272
334
|
}
|
|
273
335
|
|
|
274
|
-
|
|
336
|
+
if (!updated) {
|
|
337
|
+
return { success: true, message: `NEVER FORGET section in ${existingPath} is up to date` };
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// Replace the NEVER FORGET content in the full file
|
|
341
|
+
existing = existing.replace(nfSectionMatch[2], nfContent);
|
|
342
|
+
writeFileSync(existingPath, existing);
|
|
343
|
+
|
|
344
|
+
return { success: true, message: `Updated NEVER FORGET subsections in ${existingPath}` };
|
|
275
345
|
}
|
|
276
346
|
|
|
277
347
|
function checkMcpBinary(): { available: boolean; path?: string } {
|
package/openclaw.plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "openclaw-algorand-plugin",
|
|
3
3
|
"name": "Algorand Integration",
|
|
4
4
|
"description": "Algorand blockchain integration with MCP and skills — by GoPlausible",
|
|
5
|
-
"version": "1.9.
|
|
5
|
+
"version": "1.9.3",
|
|
6
6
|
"skills": [
|
|
7
7
|
"skills/algorand-development",
|
|
8
8
|
"skills/algorand-typescript",
|
package/package.json
CHANGED
|
@@ -211,7 +211,19 @@ All prices and quantities use **microunits** (1,000,000 = $1.00 or 1 share). Ord
|
|
|
211
211
|
|
|
212
212
|
## QR Code Display (ARC-26 URI)
|
|
213
213
|
|
|
214
|
-
|
|
214
|
+
`generate_algorand_qrcode` generates an Algorand payment URI and QR code per ARC-26 specification via QRClaw service.
|
|
215
|
+
|
|
216
|
+
**Parameters:**
|
|
217
|
+
| Parameter | Required | Description |
|
|
218
|
+
|-----------|----------|-------------|
|
|
219
|
+
| `address` | Yes | Receiver Algorand address |
|
|
220
|
+
| `label` | No | Payment label |
|
|
221
|
+
| `amount` | No | Amount in microunits (e.g. 1000000 = 1 ALGO or 1 USDC) |
|
|
222
|
+
| `asset` | No | ASA ID for asset transfers; omit or 0 for ALGO |
|
|
223
|
+
| `note` | No | Payment note |
|
|
224
|
+
| `xnote` | No | Exclusive immutable note |
|
|
225
|
+
|
|
226
|
+
**Returns:**
|
|
215
227
|
- `qr` — UTF-8 text QR code (terminal-friendly)
|
|
216
228
|
- `uri` — the `algorand://` URI string
|
|
217
229
|
- `link` — shareable hosted QR URL (via QRClaw service)
|