clawmoney 0.9.4 → 0.9.6
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/commands/hub.js +32 -2
- package/dist/hub/executor.js +56 -13
- package/dist/index.js +4 -1
- package/package.json +1 -1
package/dist/commands/hub.js
CHANGED
|
@@ -141,6 +141,28 @@ export async function hubSearchCommand(options) {
|
|
|
141
141
|
throw err;
|
|
142
142
|
}
|
|
143
143
|
}
|
|
144
|
+
// ── poll order result ──
|
|
145
|
+
async function pollOrderResult(orderId, apiKey, timeoutS, spinner) {
|
|
146
|
+
const POLL_INTERVAL = 3000;
|
|
147
|
+
const deadline = Date.now() + timeoutS * 1000;
|
|
148
|
+
while (Date.now() < deadline) {
|
|
149
|
+
const resp = await apiGet(`/api/v1/hub/orders/${orderId}`, apiKey);
|
|
150
|
+
if (!resp.ok) {
|
|
151
|
+
throw new Error(`Failed to poll order: ${resp.status}`);
|
|
152
|
+
}
|
|
153
|
+
const order = resp.data;
|
|
154
|
+
const status = order.status;
|
|
155
|
+
if (status === "completed") {
|
|
156
|
+
return order;
|
|
157
|
+
}
|
|
158
|
+
if (status === "failed" || status === "timeout") {
|
|
159
|
+
throw new Error(order.error_message || `Order ${status}`);
|
|
160
|
+
}
|
|
161
|
+
spinner.text = `Waiting for result... (${Math.round((deadline - Date.now()) / 1000)}s left)`;
|
|
162
|
+
await new Promise((r) => setTimeout(r, POLL_INTERVAL));
|
|
163
|
+
}
|
|
164
|
+
throw new Error("Timed out waiting for result");
|
|
165
|
+
}
|
|
144
166
|
export async function hubCallCommand(options) {
|
|
145
167
|
const config = requireConfig();
|
|
146
168
|
let inputData = {};
|
|
@@ -202,7 +224,11 @@ export async function hubCallCommand(options) {
|
|
|
202
224
|
spinner.fail(chalk.red(`Call failed (${resp.status}): ${detail}`));
|
|
203
225
|
process.exit(1);
|
|
204
226
|
}
|
|
205
|
-
const
|
|
227
|
+
const invokeResult = resp.data;
|
|
228
|
+
const orderId = invokeResult.id;
|
|
229
|
+
spinner.text = `Order ${orderId?.slice(0, 8)}... submitted, waiting for result...`;
|
|
230
|
+
// Poll for completion
|
|
231
|
+
const result = await pollOrderResult(orderId, config.api_key, timeout, spinner);
|
|
206
232
|
spinner.succeed(chalk.green("Call completed (x402 paid)!"));
|
|
207
233
|
console.log("");
|
|
208
234
|
console.log(` ${chalk.bold("Order:")} ${result.id ?? "-"}`);
|
|
@@ -229,7 +255,11 @@ export async function hubCallCommand(options) {
|
|
|
229
255
|
spinner.fail(chalk.red(`Call failed (${resp.status}): ${detail}`));
|
|
230
256
|
process.exit(1);
|
|
231
257
|
}
|
|
232
|
-
const
|
|
258
|
+
const invokeResult = resp.data;
|
|
259
|
+
const orderId = invokeResult.id;
|
|
260
|
+
spinner.text = `Order ${orderId?.slice(0, 8)}... submitted, waiting for result...`;
|
|
261
|
+
// Poll for completion
|
|
262
|
+
const result = await pollOrderResult(orderId, config.api_key, timeout, spinner);
|
|
233
263
|
spinner.succeed(chalk.green("Call completed!"));
|
|
234
264
|
console.log("");
|
|
235
265
|
console.log(` ${chalk.bold("Order:")} ${result.id ?? "-"}`);
|
package/dist/hub/executor.js
CHANGED
|
@@ -11,7 +11,7 @@ function buildPrompt(call, config) {
|
|
|
11
11
|
.replace("{{skill}}", call.skill)
|
|
12
12
|
.replace("{{input}}", JSON.stringify(call.input, null, 2));
|
|
13
13
|
}
|
|
14
|
-
|
|
14
|
+
const lines = [
|
|
15
15
|
"You received a paid service request via ClawMoney Hub.",
|
|
16
16
|
`Skill: ${call.skill}`,
|
|
17
17
|
`Category: ${call.category}`,
|
|
@@ -19,10 +19,13 @@ function buildPrompt(call, config) {
|
|
|
19
19
|
`Price: $${call.price}`,
|
|
20
20
|
`Input: ${JSON.stringify(call.input, null, 2)}`,
|
|
21
21
|
"",
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
];
|
|
23
|
+
// Category-specific instructions
|
|
24
|
+
if (call.category?.startsWith("generation/image")) {
|
|
25
|
+
lines.push("IMPORTANT: You MUST use an image generation tool (e.g. Gemini/Nano Banana image generation) to create a real image file.", "Do NOT write SVG, HTML, or any code to fake an image. If you do not have an image generation tool available, return {\"success\": false, \"error\": \"No image generation tool available\"}.", "Save the generated image and include the file path in your output.");
|
|
26
|
+
}
|
|
27
|
+
lines.push("Execute this task and return the result as JSON.", "If you generate any files (images, videos, etc.), save them and include their file paths in the output.", "Return ONLY the JSON result, no other text.");
|
|
28
|
+
return lines.join("\n");
|
|
26
29
|
}
|
|
27
30
|
// ── CLI execution (openclaw agent / claude -p) ──
|
|
28
31
|
function runCli(command, prompt, timeoutMs, orderId) {
|
|
@@ -202,18 +205,44 @@ export class Executor {
|
|
|
202
205
|
});
|
|
203
206
|
return;
|
|
204
207
|
}
|
|
208
|
+
// Also extract file paths from nested result.files / result.primary_file
|
|
209
|
+
const allFiles = [...ocResult.files];
|
|
210
|
+
const nested = output.result;
|
|
211
|
+
if (nested && typeof nested === "object") {
|
|
212
|
+
const nestedFiles = nested.files;
|
|
213
|
+
if (Array.isArray(nestedFiles)) {
|
|
214
|
+
for (const f of nestedFiles) {
|
|
215
|
+
if (typeof f === "string" && f.startsWith("/") && !allFiles.includes(f)) {
|
|
216
|
+
allFiles.push(f);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
for (const key of ["primary_file", "image_path", "file_path"]) {
|
|
221
|
+
const val = nested[key];
|
|
222
|
+
if (typeof val === "string" && val.startsWith("/") && !allFiles.includes(val)) {
|
|
223
|
+
allFiles.push(val);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
205
227
|
// Upload local files to R2
|
|
206
|
-
for (const filePath of
|
|
228
|
+
for (const filePath of allFiles) {
|
|
207
229
|
const cdnUrl = await uploadFile(filePath, this.config);
|
|
208
230
|
if (cdnUrl) {
|
|
209
|
-
// Replace local path with CDN URL in output
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
231
|
+
// Replace local path with CDN URL in output (top-level and nested)
|
|
232
|
+
const replaceInArray = (arr) => {
|
|
233
|
+
const idx = arr.indexOf(filePath);
|
|
234
|
+
if (idx >= 0)
|
|
235
|
+
arr[idx] = cdnUrl;
|
|
236
|
+
};
|
|
237
|
+
if (Array.isArray(output.files))
|
|
238
|
+
replaceInArray(output.files);
|
|
239
|
+
if (nested && Array.isArray(nested.files)) {
|
|
240
|
+
replaceInArray(nested.files);
|
|
241
|
+
}
|
|
242
|
+
if (nested && nested.primary_file === filePath) {
|
|
243
|
+
nested.primary_file = cdnUrl;
|
|
215
244
|
}
|
|
216
|
-
//
|
|
245
|
+
// Set convenience url key
|
|
217
246
|
if (!output.image_url && filePath.match(/\.(png|jpg|jpeg|webp|gif)$/i)) {
|
|
218
247
|
output.image_url = cdnUrl;
|
|
219
248
|
}
|
|
@@ -222,6 +251,20 @@ export class Executor {
|
|
|
222
251
|
}
|
|
223
252
|
}
|
|
224
253
|
}
|
|
254
|
+
// Validate: generation/image must produce real image files, not SVG/code
|
|
255
|
+
if (call.category?.startsWith("generation/image")) {
|
|
256
|
+
const hasRealImage = allFiles.some((f) => /\.(png|jpg|jpeg|webp|gif)$/i.test(f));
|
|
257
|
+
if (!hasRealImage) {
|
|
258
|
+
const errMsg = "No real image generated. Image generation tool may not be available.";
|
|
259
|
+
logger.error(`Validation failed for order=${call.order_id}: ${errMsg}`);
|
|
260
|
+
this.send({
|
|
261
|
+
event: "deliver",
|
|
262
|
+
order_id: call.order_id,
|
|
263
|
+
error: errMsg,
|
|
264
|
+
});
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
225
268
|
// Attach compact meta
|
|
226
269
|
if (ocResult.meta) {
|
|
227
270
|
output._meta = ocResult.meta;
|
package/dist/index.js
CHANGED
|
@@ -7,11 +7,14 @@ import { walletStatusCommand, walletBalanceCommand, walletAddressCommand, wallet
|
|
|
7
7
|
import { tweetCommand } from './commands/tweet.js';
|
|
8
8
|
import { gigCreateCommand, gigBrowseCommand, gigDetailCommand, gigAcceptCommand, gigDeliverCommand, gigApproveCommand, gigDisputeCommand, } from './commands/gig.js';
|
|
9
9
|
import { hubStartCommand, hubStopCommand, hubStatusCommand, hubSearchCommand, hubCallCommand, hubRegisterCommand, hubSkillsCommand, } from './commands/hub.js';
|
|
10
|
+
import { createRequire } from 'node:module';
|
|
11
|
+
const require = createRequire(import.meta.url);
|
|
12
|
+
const pkg = require('../package.json');
|
|
10
13
|
const program = new Command();
|
|
11
14
|
program
|
|
12
15
|
.name('clawmoney')
|
|
13
16
|
.description('ClawMoney CLI -- Earn rewards with your AI agent')
|
|
14
|
-
.version(
|
|
17
|
+
.version(pkg.version);
|
|
15
18
|
// setup
|
|
16
19
|
program
|
|
17
20
|
.command('setup')
|