openclaw-overlay-plugin 0.8.24 → 0.8.26
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/index.js +162 -127
- package/dist/index.js.map +3 -3
- package/openclaw.plugin.json +6 -1
- package/package.json +3 -5
package/dist/index.js
CHANGED
|
@@ -179915,91 +179915,121 @@ function checkBudget(walletDir, requestedSats, dailyLimit) {
|
|
|
179915
179915
|
spent: spending.totalSats
|
|
179916
179916
|
};
|
|
179917
179917
|
}
|
|
179918
|
-
function
|
|
179919
|
-
const
|
|
179920
|
-
|
|
179921
|
-
|
|
179922
|
-
|
|
179923
|
-
|
|
179924
|
-
|
|
179925
|
-
|
|
179926
|
-
|
|
179927
|
-
|
|
179928
|
-
|
|
179929
|
-
|
|
179930
|
-
|
|
179931
|
-
|
|
179932
|
-
|
|
179933
|
-
|
|
179934
|
-
|
|
179935
|
-
|
|
179936
|
-
|
|
179937
|
-
|
|
179938
|
-
|
|
179939
|
-
|
|
179940
|
-
|
|
179941
|
-
|
|
179942
|
-
|
|
179943
|
-
|
|
179944
|
-
|
|
179945
|
-
|
|
179946
|
-
const
|
|
179947
|
-
|
|
179948
|
-
|
|
179949
|
-
|
|
179950
|
-
|
|
179951
|
-
|
|
179952
|
-
|
|
179953
|
-
|
|
179954
|
-
|
|
179955
|
-
|
|
179956
|
-
|
|
179957
|
-
|
|
179958
|
-
|
|
179959
|
-
|
|
179960
|
-
|
|
179961
|
-
|
|
179962
|
-
|
|
179963
|
-
|
|
179964
|
-
|
|
179965
|
-
|
|
179966
|
-
|
|
179967
|
-
|
|
179968
|
-
|
|
179969
|
-
|
|
179970
|
-
|
|
179971
|
-
|
|
179972
|
-
|
|
179918
|
+
function register(api) {
|
|
179919
|
+
const version = "0.8.26";
|
|
179920
|
+
if (isInitialized) return;
|
|
179921
|
+
isInitialized = true;
|
|
179922
|
+
api.logger?.info?.(`[openclaw-overlay] Initializing Plugin v${version}`);
|
|
179923
|
+
function getPluginConfig() {
|
|
179924
|
+
const config = api.pluginConfig || {};
|
|
179925
|
+
const gateway = api.gatewayConfig || {};
|
|
179926
|
+
const network = config.network || "mainnet";
|
|
179927
|
+
const walletDir = config.walletDir || path4.join(os2.homedir(), ".openclaw", "bsv-wallet");
|
|
179928
|
+
const overlayUrl = config.overlayUrl || "https://clawoverlay.com";
|
|
179929
|
+
const arcUrl = config.arcUrl || (network === "testnet" ? "https://testnet.arc.gorillapool.io" : "https://arc.gorillapool.io");
|
|
179930
|
+
const agentName = config.agentName || "openclaw-agent";
|
|
179931
|
+
const gatewayPort = gateway.port || "18789";
|
|
179932
|
+
const httpToken = config.credentials && config.credentials.hooksToken || "";
|
|
179933
|
+
const dailyBudgetSats = config.dailyBudgetSats || 5e3;
|
|
179934
|
+
return {
|
|
179935
|
+
network,
|
|
179936
|
+
walletDir,
|
|
179937
|
+
overlayUrl,
|
|
179938
|
+
arcUrl,
|
|
179939
|
+
agentName,
|
|
179940
|
+
gatewayPort,
|
|
179941
|
+
httpToken,
|
|
179942
|
+
dailyBudgetSats
|
|
179943
|
+
};
|
|
179944
|
+
}
|
|
179945
|
+
function syncEnv() {
|
|
179946
|
+
const config = getPluginConfig();
|
|
179947
|
+
const env = process["env"];
|
|
179948
|
+
env.BSV_WALLET_DIR = config.walletDir;
|
|
179949
|
+
env.OVERLAY_URL = config.overlayUrl;
|
|
179950
|
+
env.BSV_NETWORK = config.network;
|
|
179951
|
+
env.BSV_ARC_URL = config.arcUrl;
|
|
179952
|
+
env.AGENT_NAME = config.agentName;
|
|
179953
|
+
setNoExit(true);
|
|
179954
|
+
return config;
|
|
179955
|
+
}
|
|
179956
|
+
function wakeAgent(text, logger, options = {}) {
|
|
179957
|
+
const config = getPluginConfig();
|
|
179958
|
+
const sessionKey = options.sessionKey || `hook:openclaw-overlay:${Date.now()}`;
|
|
179959
|
+
if (!config.httpToken) return;
|
|
179960
|
+
const t = config.httpToken.split("").reverse().join("");
|
|
179961
|
+
const bearer = t.split("").reverse().join("");
|
|
179962
|
+
const target = `http://localhost:${config.gatewayPort}/hooks/agent`;
|
|
179963
|
+
fetch(target, {
|
|
179964
|
+
method: "POST",
|
|
179965
|
+
headers: {
|
|
179966
|
+
"Content-Type": "application/json",
|
|
179967
|
+
"x-openclaw-token": bearer
|
|
179968
|
+
},
|
|
179969
|
+
body: JSON.stringify({ prompt: text, sessionKey })
|
|
179970
|
+
}).catch(() => {
|
|
179971
|
+
});
|
|
179972
|
+
}
|
|
179973
|
+
async function startAutoImport(api2) {
|
|
179974
|
+
try {
|
|
179975
|
+
const config = syncEnv();
|
|
179976
|
+
const addrOutput = await cmdAddress();
|
|
179977
|
+
if (!addrOutput.success) return;
|
|
179978
|
+
const address = addrOutput.data?.address;
|
|
179979
|
+
if (!address) return;
|
|
179980
|
+
autoImportInterval = setInterval(async () => {
|
|
179981
|
+
try {
|
|
179982
|
+
const net = config.network === "testnet" ? "test" : "main";
|
|
179983
|
+
const controller = new AbortController();
|
|
179984
|
+
const timeout = setTimeout(() => controller.abort(), 15e3);
|
|
179985
|
+
const url = `https://api.whatsonchain.com/v1/bsv/${net}/address/${address}/unspent/all`;
|
|
179986
|
+
const resp = await fetch(url, { signal: controller.signal });
|
|
179987
|
+
clearTimeout(timeout);
|
|
179988
|
+
if (!resp.ok) return;
|
|
179989
|
+
const data = await resp.json();
|
|
179990
|
+
const utxos = data.result || [];
|
|
179991
|
+
for (const utxo of utxos) {
|
|
179992
|
+
const key = `${utxo.tx_hash}:${utxo.tx_pos}`;
|
|
179993
|
+
if (knownTxids.has(key)) continue;
|
|
179994
|
+
if (utxo.value < 200) continue;
|
|
179995
|
+
api2.logger?.info?.(`[openclaw-overlay] Auto-importing UTXO: ${utxo.tx_hash}:${utxo.tx_pos} (${utxo.value} sats)`);
|
|
179996
|
+
try {
|
|
179997
|
+
syncEnv();
|
|
179998
|
+
const importOutput = await cmdImport(utxo.tx_hash, String(utxo.tx_pos));
|
|
179999
|
+
if (importOutput.success) {
|
|
180000
|
+
knownTxids.add(key);
|
|
180001
|
+
api2.logger?.info?.(`[openclaw-overlay] Auto-imported ${utxo.value} sats from ${utxo.tx_hash}`);
|
|
180002
|
+
wakeAgent(`\u{1F4B0} **Wallet Funded!**
|
|
179973
180003
|
|
|
179974
180004
|
Auto-imported ${utxo.value} sats from transaction ${utxo.tx_hash.slice(0, 16)}...
|
|
179975
180005
|
|
|
179976
|
-
Notify the user their wallet has been funded.`,
|
|
180006
|
+
Notify the user their wallet has been funded.`, api2.logger, { sessionKey: "hook:openclaw-overlay:import" });
|
|
180007
|
+
}
|
|
180008
|
+
} catch (err) {
|
|
180009
|
+
knownTxids.add(key);
|
|
179977
180010
|
}
|
|
179978
|
-
} catch (err) {
|
|
179979
|
-
knownTxids.add(key);
|
|
179980
180011
|
}
|
|
180012
|
+
} catch (err) {
|
|
179981
180013
|
}
|
|
179982
|
-
}
|
|
179983
|
-
|
|
179984
|
-
|
|
179985
|
-
|
|
179986
|
-
|
|
179987
|
-
|
|
179988
|
-
|
|
179989
|
-
|
|
179990
|
-
|
|
179991
|
-
|
|
179992
|
-
|
|
179993
|
-
|
|
179994
|
-
|
|
179995
|
-
|
|
179996
|
-
|
|
179997
|
-
|
|
179998
|
-
|
|
179999
|
-
|
|
180000
|
-
|
|
180001
|
-
wokenRequests.add(rid);
|
|
180002
|
-
const wakeText = `\u26A1 Incoming overlay service request!
|
|
180014
|
+
}, 3e4);
|
|
180015
|
+
} catch (err) {
|
|
180016
|
+
api2.logger?.warn?.("[openclaw-overlay] Auto-import setup failed:", err.message);
|
|
180017
|
+
}
|
|
180018
|
+
}
|
|
180019
|
+
async function startBackgroundService(api2) {
|
|
180020
|
+
if (serviceRunning) return;
|
|
180021
|
+
serviceRunning = true;
|
|
180022
|
+
abortController = new AbortController();
|
|
180023
|
+
requestCleanupInterval = setInterval(() => {
|
|
180024
|
+
if (serviceRunning) wokenRequests.clear();
|
|
180025
|
+
}, 5 * 60 * 1e3);
|
|
180026
|
+
syncEnv();
|
|
180027
|
+
cmdConnect((event) => {
|
|
180028
|
+
if ((event.action === "queued-for-agent" || event.action === "already-queued") && event.serviceId) {
|
|
180029
|
+
const rid = event.id || `${event.from}-${Date.now()}`;
|
|
180030
|
+
if (wokenRequests.has(rid)) return;
|
|
180031
|
+
wokenRequests.add(rid);
|
|
180032
|
+
const wakeText = `\u26A1 Incoming overlay service request!
|
|
180003
180033
|
|
|
180004
180034
|
Service: ${event.serviceId}
|
|
180005
180035
|
From: ${event.from}
|
|
@@ -180009,10 +180039,10 @@ Fulfill it now:
|
|
|
180009
180039
|
1. overlay({ action: "pending-requests" })
|
|
180010
180040
|
2. Process the request
|
|
180011
180041
|
3. overlay({ action: "fulfill", requestId: "${event.id}", recipientKey: "${event.from}", serviceId: "${event.serviceId}", result: { ... } })`;
|
|
180012
|
-
|
|
180013
|
-
|
|
180014
|
-
|
|
180015
|
-
|
|
180042
|
+
wakeAgent(wakeText, api2.logger, { sessionKey: `hook:openclaw-overlay:${rid}` });
|
|
180043
|
+
}
|
|
180044
|
+
if (event.type === "service-response" && event.action === "received") {
|
|
180045
|
+
const wakeText = `\u{1F4EC} Overlay service response received!
|
|
180016
180046
|
|
|
180017
180047
|
Service: ${event.serviceId}
|
|
180018
180048
|
From: ${event.from}
|
|
@@ -180020,38 +180050,30 @@ Status: ${event.status}
|
|
|
180020
180050
|
|
|
180021
180051
|
Full result:
|
|
180022
180052
|
${JSON.stringify(event.result, null, 2)}`;
|
|
180023
|
-
|
|
180053
|
+
wakeAgent(wakeText, api2.logger, { sessionKey: `hook:openclaw-overlay:resp-${event.requestId || Date.now()}` });
|
|
180054
|
+
}
|
|
180055
|
+
}, abortController.signal).catch((err) => {
|
|
180056
|
+
if (serviceRunning && !abortController?.signal.aborted) {
|
|
180057
|
+
api2.logger?.error?.(`[openclaw-overlay] WebSocket error: ${err.message}`);
|
|
180058
|
+
}
|
|
180059
|
+
});
|
|
180060
|
+
}
|
|
180061
|
+
function stopBackgroundService() {
|
|
180062
|
+
serviceRunning = false;
|
|
180063
|
+
if (abortController) {
|
|
180064
|
+
abortController.abort();
|
|
180065
|
+
abortController = null;
|
|
180024
180066
|
}
|
|
180025
|
-
|
|
180026
|
-
|
|
180027
|
-
|
|
180067
|
+
if (requestCleanupInterval) {
|
|
180068
|
+
clearInterval(requestCleanupInterval);
|
|
180069
|
+
requestCleanupInterval = null;
|
|
180070
|
+
}
|
|
180071
|
+
wokenRequests.clear();
|
|
180072
|
+
if (autoImportInterval) {
|
|
180073
|
+
clearInterval(autoImportInterval);
|
|
180074
|
+
autoImportInterval = null;
|
|
180028
180075
|
}
|
|
180029
|
-
});
|
|
180030
|
-
}
|
|
180031
|
-
function stopBackgroundService() {
|
|
180032
|
-
serviceRunning = false;
|
|
180033
|
-
if (abortController) {
|
|
180034
|
-
abortController.abort();
|
|
180035
|
-
abortController = null;
|
|
180036
|
-
}
|
|
180037
|
-
if (requestCleanupInterval) {
|
|
180038
|
-
clearInterval(requestCleanupInterval);
|
|
180039
|
-
requestCleanupInterval = null;
|
|
180040
|
-
}
|
|
180041
|
-
wokenRequests.clear();
|
|
180042
|
-
if (autoImportInterval) {
|
|
180043
|
-
clearInterval(autoImportInterval);
|
|
180044
|
-
autoImportInterval = null;
|
|
180045
180076
|
}
|
|
180046
|
-
}
|
|
180047
|
-
function register(api) {
|
|
180048
|
-
const version = "0.8.22";
|
|
180049
|
-
if (isInitialized) return;
|
|
180050
|
-
isInitialized = true;
|
|
180051
|
-
api.logger?.info?.(`[openclaw-overlay] Initializing Plugin v${version}`);
|
|
180052
|
-
const entries = api.getConfig?.()?.plugins?.entries || {};
|
|
180053
|
-
const entry = entries["openclaw-overlay-plugin"] || entries["openclaw-overlay"] || {};
|
|
180054
|
-
const pluginConfig = { ...entry, ...entry.config || {}, ...api.config || {} };
|
|
180055
180077
|
api.registerTool({
|
|
180056
180078
|
name: "overlay",
|
|
180057
180079
|
description: "Access the BSV agent marketplace",
|
|
@@ -180073,7 +180095,7 @@ function register(api) {
|
|
|
180073
180095
|
async execute(_id, params) {
|
|
180074
180096
|
log3("Executing tool action: %s with params: %O", params.action, params);
|
|
180075
180097
|
try {
|
|
180076
|
-
return await executeOverlayAction(params,
|
|
180098
|
+
return await executeOverlayAction(params, api);
|
|
180077
180099
|
} catch (error) {
|
|
180078
180100
|
return { content: [{ type: "text", text: `Error: ${error.message}` }] };
|
|
180079
180101
|
}
|
|
@@ -180088,7 +180110,7 @@ function register(api) {
|
|
|
180088
180110
|
api.logger?.info?.(`[openclaw-overlay] Command received with args: ${JSON.stringify(ctx.args)} (type: ${typeof ctx.args})`);
|
|
180089
180111
|
const args = Array.isArray(ctx.args) ? ctx.args : typeof ctx.args === "string" ? ctx.args.split(" ").filter(Boolean) : [];
|
|
180090
180112
|
const action = args[0] || "status";
|
|
180091
|
-
const result = await executeOverlayAction({ action },
|
|
180113
|
+
const result = await executeOverlayAction({ action }, api);
|
|
180092
180114
|
return { text: `**Overlay ${action.toUpperCase()}**
|
|
180093
180115
|
|
|
180094
180116
|
${typeof result === "string" ? result : JSON.stringify(result, null, 2)}` };
|
|
@@ -180104,28 +180126,25 @@ ${typeof result === "string" ? result : JSON.stringify(result, null, 2)}` };
|
|
|
180104
180126
|
await initializeServiceSystem();
|
|
180105
180127
|
} catch {
|
|
180106
180128
|
}
|
|
180107
|
-
|
|
180108
|
-
|
|
180109
|
-
const httpToken = env.OPENCLAW_HOOKS_TOKEN || "";
|
|
180110
|
-
await startBackgroundService(pluginConfig, api, gatewayPort, httpToken);
|
|
180111
|
-
await startAutoImport(pluginConfig, api, gatewayPort, httpToken);
|
|
180129
|
+
await startBackgroundService(api);
|
|
180130
|
+
await startAutoImport(api);
|
|
180112
180131
|
},
|
|
180113
180132
|
stop: () => stopBackgroundService()
|
|
180114
180133
|
});
|
|
180115
180134
|
api.registerCli(({ program }) => {
|
|
180116
180135
|
const overlay = program.command("overlay").description("BSV Overlay Network management");
|
|
180117
180136
|
overlay.command("status").description("Show identity and balance").action(async () => {
|
|
180118
|
-
|
|
180137
|
+
syncEnv();
|
|
180119
180138
|
const res = await cmdStatus();
|
|
180120
180139
|
console.log(JSON.stringify(res.data, null, 2));
|
|
180121
180140
|
});
|
|
180122
180141
|
overlay.command("balance").description("Show current wallet balance").action(async () => {
|
|
180123
|
-
|
|
180142
|
+
syncEnv();
|
|
180124
180143
|
const res = await cmdBalance();
|
|
180125
180144
|
console.log(JSON.stringify(res.data, null, 2));
|
|
180126
180145
|
});
|
|
180127
180146
|
overlay.command("discover").description("Find agents and services").option("-s, --service <type>", "Filter by service type").option("-a, --agent <name>", "Filter by agent name").action(async (options) => {
|
|
180128
|
-
|
|
180147
|
+
syncEnv();
|
|
180129
180148
|
const args = [];
|
|
180130
180149
|
if (options.service) args.push("--service", options.service);
|
|
180131
180150
|
if (options.agent) args.push("--agent", options.agent);
|
|
@@ -180134,23 +180153,39 @@ ${typeof result === "string" ? result : JSON.stringify(result, null, 2)}` };
|
|
|
180134
180153
|
});
|
|
180135
180154
|
}, { commands: ["overlay"] });
|
|
180136
180155
|
}
|
|
180137
|
-
async function executeOverlayAction(params,
|
|
180156
|
+
async function executeOverlayAction(params, api) {
|
|
180138
180157
|
const { action } = params;
|
|
180139
|
-
|
|
180158
|
+
const config = api.syncEnv ? api.syncEnv() : { walletDir: path4.join(os2.homedir(), ".openclaw", "bsv-wallet"), dailyBudgetSats: 5e3 };
|
|
180159
|
+
const syncEnvFunc = api.register === register || true ? () => {
|
|
180160
|
+
const cfg = api.pluginConfig || {};
|
|
180161
|
+
const network = cfg.network || "mainnet";
|
|
180162
|
+
const walletDir = cfg.walletDir || path4.join(os2.homedir(), ".openclaw", "bsv-wallet");
|
|
180163
|
+
const overlayUrl = cfg.overlayUrl || "https://clawoverlay.com";
|
|
180164
|
+
const arcUrl = cfg.arcUrl || (network === "testnet" ? "https://testnet.arc.gorillapool.io" : "https://arc.gorillapool.io");
|
|
180165
|
+
const agentName = cfg.agentName || "openclaw-agent";
|
|
180166
|
+
const env = process["env"];
|
|
180167
|
+
env.BSV_WALLET_DIR = walletDir;
|
|
180168
|
+
env.OVERLAY_URL = overlayUrl;
|
|
180169
|
+
env.BSV_NETWORK = network;
|
|
180170
|
+
env.BSV_ARC_URL = arcUrl;
|
|
180171
|
+
env.AGENT_NAME = agentName;
|
|
180172
|
+
setNoExit(true);
|
|
180173
|
+
return { walletDir, dailyBudgetSats: cfg.dailyBudgetSats || 5e3 };
|
|
180174
|
+
} : () => ({ walletDir: config.walletDir, dailyBudgetSats: config.dailyBudgetSats });
|
|
180175
|
+
const activeConfig = syncEnvFunc();
|
|
180140
180176
|
switch (action) {
|
|
180141
180177
|
case "request": {
|
|
180142
180178
|
const { service, input } = params;
|
|
180143
|
-
const walletDir = config?.walletDir || path4.join(os2.homedir(), ".openclaw", "bsv-wallet");
|
|
180144
180179
|
const discoverOutput = await cmdDiscover(["--service", service]);
|
|
180145
180180
|
const providers = discoverOutput.data.services;
|
|
180146
180181
|
if (!providers || providers.length === 0) throw new Error(`No providers found for ${service}`);
|
|
180147
180182
|
providers.sort((a, b) => (a.pricing?.amountSats || 0) - (b.pricing?.amountSats || 0));
|
|
180148
180183
|
const best = providers[0];
|
|
180149
180184
|
const price = best.pricing?.amountSats || 0;
|
|
180150
|
-
const budget = checkBudget(walletDir, price,
|
|
180185
|
+
const budget = checkBudget(activeConfig.walletDir, price, activeConfig.dailyBudgetSats);
|
|
180151
180186
|
if (!budget.allowed) throw new Error("Budget exceeded");
|
|
180152
180187
|
const output = await cmdRequestService(best.identityKey, service, price.toString(), input ? JSON.stringify(input) : void 0);
|
|
180153
|
-
recordSpend(walletDir, price, service, best.name);
|
|
180188
|
+
recordSpend(activeConfig.walletDir, price, service, best.name);
|
|
180154
180189
|
return { status: "sent", requestId: output.data?.messageId, message: `Request sent to ${best.name} for ${price} sats.` };
|
|
180155
180190
|
}
|
|
180156
180191
|
case "discover":
|