@goplausible/openclaw-algorand-plugin 1.8.7 → 1.8.8

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
@@ -184,6 +184,96 @@ function writeMemoryFile(workspacePath: string): { success: boolean; message: st
184
184
  return { success: true, message: `Plugin memory written to ${targetFile}` };
185
185
  }
186
186
 
187
+ function ensureWorkspaceMemoryIndex(workspacePath: string): { success: boolean; message: string } {
188
+ const templateFile = join(__dirname, "memory", "MEMORY.md");
189
+
190
+ if (!existsSync(templateFile)) {
191
+ return { success: false, message: "Template MEMORY.md not found in plugin" };
192
+ }
193
+
194
+ const templateContent = readFileSync(templateFile, "utf-8");
195
+
196
+ // Extract NEVER FORGET section from template (everything between ## NEVER FORGET and next ## or EOF)
197
+ const neverForgetMatch = templateContent.match(/## NEVER FORGET\n([\s\S]*?)(?=\n## (?!NEVER)|$)/);
198
+ if (!neverForgetMatch) {
199
+ return { success: false, message: "No NEVER FORGET section found in template MEMORY.md" };
200
+ }
201
+ const templateNeverForget = neverForgetMatch[1].trimEnd();
202
+
203
+ // Check for MEMORY.md or memory.md at workspace root
204
+ const memoryMdPath = join(workspacePath, "MEMORY.md");
205
+ const memoryMdLower = join(workspacePath, "memory.md");
206
+
207
+ const existingPath = existsSync(memoryMdPath) ? memoryMdPath
208
+ : existsSync(memoryMdLower) ? memoryMdLower
209
+ : null;
210
+
211
+ if (!existingPath) {
212
+ // No MEMORY.md exists — create from template
213
+ writeFileSync(memoryMdPath, templateContent);
214
+ return { success: true, message: `Created ${memoryMdPath} with NEVER FORGET section` };
215
+ }
216
+
217
+ // MEMORY.md exists — check for NEVER FORGET header
218
+ let existing = readFileSync(existingPath, "utf-8");
219
+
220
+ if (!/## NEVER FORGET/i.test(existing)) {
221
+ // No NEVER FORGET section — insert after first # heading
222
+ const firstHeadingEnd = existing.match(/^# .+\n/m);
223
+ if (firstHeadingEnd) {
224
+ const insertPos = (firstHeadingEnd.index ?? 0) + firstHeadingEnd[0].length;
225
+ existing = existing.slice(0, insertPos) + "\n## NEVER FORGET\n" + templateNeverForget + "\n\n" + existing.slice(insertPos);
226
+ } else {
227
+ // No heading at all — prepend
228
+ existing = "# OpenClaw Agent Long-Term Memory\n\n## NEVER FORGET\n" + templateNeverForget + "\n\n" + existing;
229
+ }
230
+ writeFileSync(existingPath, existing);
231
+ return { success: true, message: `Added NEVER FORGET section to ${existingPath}` };
232
+ }
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);
254
+ }
255
+ }
256
+ }
257
+
258
+ if (newLines.length === 0) {
259
+ return { success: true, message: `NEVER FORGET section in ${existingPath} is up to date` };
260
+ }
261
+
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);
271
+ }
272
+ }
273
+
274
+ return { success: true, message: `Updated NEVER FORGET section in ${existingPath} (added ${newLines.length} items)` };
275
+ }
276
+
187
277
  function checkMcpBinary(): { available: boolean; path?: string } {
188
278
  try {
189
279
  const path = execSync("which algorand-mcp", { encoding: "utf-8" }).trim();
@@ -281,6 +371,14 @@ export default function register(api: PluginApi) {
281
371
  console.error(` ❌ ${memResult.message}`);
282
372
  }
283
373
 
374
+ // Step 1b: Ensure MEMORY.md exists at workspace root with NEVER FORGET section
375
+ const memIndexResult = ensureWorkspaceMemoryIndex(workspacePath);
376
+ if (memIndexResult.success) {
377
+ console.log(` ✅ ${memIndexResult.message}`);
378
+ } else {
379
+ console.error(` ❌ ${memIndexResult.message}`);
380
+ }
381
+
284
382
  // Step 2: Stop any existing algorand-mcp processes
285
383
  const stopResult = stopExistingMcpProcesses();
286
384
  if (stopResult.stopped > 0) {
@@ -415,6 +513,14 @@ export default function register(api: PluginApi) {
415
513
  console.log(" This plugin provides:");
416
514
  console.log(" • 9 Algorand skills (Algorand development in TS and Python, x402, MCP interaction, alpha arcade interaction, haystack router development and interaction)");
417
515
  console.log(" • algorand-mcp server (~100 blockchain tools via mcporter)\n");
516
+
517
+ // Ensure MEMORY.md exists at workspace root
518
+ const workspacePath = getWorkspacePath(api);
519
+ const memIndexResult = ensureWorkspaceMemoryIndex(workspacePath);
520
+ if (memIndexResult.success) {
521
+ console.log(` ✅ ${memIndexResult.message}`);
522
+ }
523
+
418
524
  // Keyring persistence warning for headless Linux
419
525
  try {
420
526
  const scriptPath = join(__dirname, "scripts", "setup-keyring.sh");
@@ -0,0 +1,38 @@
1
+ # OpenClaw Agent Long-Term Memory
2
+
3
+ ## NEVER FORGET
4
+
5
+ ### Algorand Plugin Memory
6
+ * ALWAYS read `memory/algorand-plugin.md` first for anything Algorand-related — it contains skill routing, MCP tool categories, common workflows, asset tables, and external resources.
7
+
8
+ ### Wallet
9
+ * ALWAYS check wallet with `wallet_get_info` before any blockchain operation.
10
+ * `create_account` only generates a keypair and returns it — nothing is stored. Use `wallet_add_account` to create a persistent agent wallet account with a nickname and spending limits. Make sure you notify user about this if they prompt for account creation without mentioning wallet.
11
+ * Default network is mainnet. ALWAYS remind users to specify `testnet` in their prompts if they intend to work on testnet.
12
+
13
+ ### Skill Routing — Load the Right Skill
14
+ * `algorand-interaction` — ALWAYS load when using Algorand MCP tools for blockchain queries, transactions, swaps, x402 payments, or wallet operations.
15
+ * `algorand-development` — Load for AlgoKit CLI, project setup, example search, and general development workflows.
16
+ * `algorand-typescript` — Load for TypeScript/PuyaTs smart contract development, testing with Vitest, typed clients, React frontends.
17
+ * `algorand-python` — Load for Python/PuyaPy smart contract development, algopy decorators, Python AlgoKit Utils.
18
+ * `algorand-x402-typescript` — Load for building x402 payment apps in TypeScript (clients, servers, facilitators, paywalls, Next.js).
19
+ * `algorand-x402-python` — Load for building x402 payment apps in Python (clients, servers, facilitators, Bazaar discovery).
20
+ * `algorand-interaction` also covers x402 payment workflows — ALWAYS load it on HTTP 402 responses to follow the atomic group payment pattern.
21
+ * `haystack-router-interaction` — Load for best-price token swaps via MCP tools (DEX aggregation across Tinyman, Pact, Folks).
22
+ * `haystack-router-development` — Load for building swap UIs with `@txnlab/haystack-router` SDK (React, Node.js).
23
+ * `alpha-arcade-interaction` — Load for prediction market trading via MCP tools (browse markets, place orders, manage positions).
24
+
25
+ ### QR Codes
26
+ * When calling `generate_algorand_qrcode`, **USE THE --RAW FLAG** with mcporter to get full output including base64 PNG. Always include UTF-8 QR block, PNG image, and URI string in your response. Copy the ENTIRE base64 string exactly — do not reformat or edit.
27
+
28
+ ### Documentation
29
+ * Use `get_knowledge_doc` MCP tool for Algorand developer documentation (categories: arcs, sdks, algokit, algokit-utils, tealscript, puya, liquid-auth, python, developers, clis, nodes, details).
30
+
31
+ ### Never Do This
32
+ * NEVER attempt any Algorand blockchain interaction without loading and reading the `algorand-interaction` skill first.
33
+ * NEVER use PyTEAL or Beaker — these are legacy. Use Algorand TypeScript (PuyaTs) or Algorand Python (PuyaPy).
34
+ * NEVER use AlgoExplorer — it is obsolete. Use Allo.info for block/account/transaction/asset/application explorer.
35
+ * NEVER attempt x402 payments without loading the `algorand-interaction` skill first — the x402 payment workflow and atomic group pattern are documented there.
36
+
37
+
38
+
@@ -33,7 +33,7 @@ mcporter list algorand-mcp
33
33
 
34
34
  # Call a tool
35
35
  mcporter call algorand-mcp.wallet_get_info
36
- mcporter call algorand-mcp.get_account_info address=XXXXX network=testnet
36
+ mcporter call algorand-mcp.generate_algorand_qrcode --raw address=XXXXX network=testnet asset=0 amount=1000000
37
37
  mcporter call algorand-mcp.search_assets name=USDC network=mainnet
38
38
  ```
39
39
 
@@ -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.8.7",
5
+ "version": "1.8.8",
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.8.7",
3
+ "version": "1.8.8",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },