@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 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 — merge template items that are missing
235
- // Extract existing NEVER FORGET section content
236
- const existingNFMatch = existing.match(/## NEVER FORGET\n([\s\S]*?)(?=\n## (?!#)|$)/);
237
- const existingNFContent = existingNFMatch ? existingNFMatch[1] : "";
238
-
239
- // Extract individual items (lines starting with *) from template, grouped by subsection
240
- const templateLines = templateNeverForget.split("\n");
241
- const newLines: string[] = [];
242
-
243
- for (const line of templateLines) {
244
- // Add subsection headers and bullet items that don't exist in existing content
245
- if (line.startsWith("### ")) {
246
- if (!existingNFContent.includes(line)) {
247
- newLines.push(line);
248
- }
249
- } else if (line.startsWith("* ")) {
250
- // Check if this bullet's key content already exists (first 50 chars as fingerprint)
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
- if (newLines.length === 0) {
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
- // Append new items at the end of existing NEVER FORGET section
263
- const nfEnd = existing.search(/## NEVER FORGET\n[\s\S]*?(?=\n## (?!#)|$)/);
264
- if (nfEnd !== -1) {
265
- const sectionMatch = existing.match(/## NEVER FORGET\n([\s\S]*?)(?=\n## (?!#)|$)/);
266
- if (sectionMatch) {
267
- const sectionEnd = (sectionMatch.index ?? 0) + sectionMatch[0].length;
268
- const insertion = "\n" + newLines.join("\n") + "\n";
269
- existing = existing.slice(0, sectionEnd) + insertion + existing.slice(sectionEnd);
270
- writeFileSync(existingPath, existing);
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
- return { success: true, message: `Updated NEVER FORGET section in ${existingPath} (added ${newLines.length} items)` };
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 } {
@@ -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.1",
5
+ "version": "1.9.3",
6
6
  "skills": [
7
7
  "skills/algorand-development",
8
8
  "skills/algorand-typescript",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goplausible/openclaw-algorand-plugin",
3
- "version": "1.9.1",
3
+ "version": "1.9.3",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -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
- When generating QR codes with `generate_algorand_qrcode`, the tool returns:
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)