travelmolt-sdk 1.3.0 → 1.4.0
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/cli.cjs +155 -18
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +155 -18
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -1885,10 +1885,21 @@ function getPublicClient() {
|
|
|
1885
1885
|
transport: (0, import_viem3.http)(rpcUrl)
|
|
1886
1886
|
});
|
|
1887
1887
|
}
|
|
1888
|
+
function getSerpApiKey() {
|
|
1889
|
+
const key = flag("serpapi-key") ?? process.env.SERPAPI_API_KEY;
|
|
1890
|
+
if (!key) {
|
|
1891
|
+
console.error("Error: SerpAPI key required. Provide via flag or env var:");
|
|
1892
|
+
console.error(" npx travelmolt-sdk@latest check-price 2 --serpapi-key YOUR_KEY");
|
|
1893
|
+
console.error(" export SERPAPI_API_KEY=YOUR_KEY");
|
|
1894
|
+
process.exit(1);
|
|
1895
|
+
}
|
|
1896
|
+
return key;
|
|
1897
|
+
}
|
|
1888
1898
|
function getAgent() {
|
|
1889
|
-
const pk = process.env.PRIVATE_KEY;
|
|
1899
|
+
const pk = flag("private-key") ?? process.env.PRIVATE_KEY;
|
|
1890
1900
|
if (!pk) {
|
|
1891
|
-
console.error("Error:
|
|
1901
|
+
console.error("Error: Private key required. Provide via flag or env var:");
|
|
1902
|
+
console.error(" npx travelmolt-sdk@latest <cmd> --private-key 0xYourKey");
|
|
1892
1903
|
console.error(" export PRIVATE_KEY=0xYourHexPrivateKey");
|
|
1893
1904
|
process.exit(1);
|
|
1894
1905
|
}
|
|
@@ -1906,6 +1917,14 @@ function formatUsdc(raw) {
|
|
|
1906
1917
|
const frac = raw % 1000000n;
|
|
1907
1918
|
return `${whole}.${frac.toString().padStart(6, "0")} USDC`;
|
|
1908
1919
|
}
|
|
1920
|
+
function formatDuration(secs) {
|
|
1921
|
+
const abs = Math.abs(secs);
|
|
1922
|
+
if (abs < 60) return `${abs}s`;
|
|
1923
|
+
if (abs < 3600) return `${Math.floor(abs / 60)}m`;
|
|
1924
|
+
const h = Math.floor(abs / 3600);
|
|
1925
|
+
const m = Math.floor(abs % 3600 / 60);
|
|
1926
|
+
return m > 0 ? `${h}h ${m}m` : `${h}h`;
|
|
1927
|
+
}
|
|
1909
1928
|
function printJob(id, job) {
|
|
1910
1929
|
const statusNames = ["Open", "Claimed", "Completed", "Cancelled"];
|
|
1911
1930
|
let payload = {};
|
|
@@ -2125,18 +2144,136 @@ Use --force to bypass this check.`);
|
|
|
2125
2144
|
console.log(` Expected reports: ${expected}`);
|
|
2126
2145
|
break;
|
|
2127
2146
|
}
|
|
2147
|
+
case "my-jobs": {
|
|
2148
|
+
const addrFlag = flag("address");
|
|
2149
|
+
let workerAddress;
|
|
2150
|
+
if (addrFlag) {
|
|
2151
|
+
workerAddress = addrFlag.toLowerCase();
|
|
2152
|
+
} else {
|
|
2153
|
+
const pk = flag("private-key") ?? process.env.PRIVATE_KEY;
|
|
2154
|
+
if (!pk) {
|
|
2155
|
+
console.error("Usage: travelmolt my-jobs --address 0x... (read-only)");
|
|
2156
|
+
console.error(" or: travelmolt my-jobs (uses PRIVATE_KEY / --private-key)");
|
|
2157
|
+
process.exit(1);
|
|
2158
|
+
}
|
|
2159
|
+
workerAddress = (0, import_accounts.privateKeyToAccount)(pk).address.toLowerCase();
|
|
2160
|
+
}
|
|
2161
|
+
const maxId = Number(flag("max") ?? "100");
|
|
2162
|
+
const publicClient = getPublicClient();
|
|
2163
|
+
const readAgent = new TravelMoltAgent({ publicClient, walletClient: null });
|
|
2164
|
+
const ZERO = "0x0000000000000000000000000000000000000000";
|
|
2165
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
2166
|
+
const myJobs = [];
|
|
2167
|
+
let needsAction = false;
|
|
2168
|
+
for (let id = 1; id <= maxId; id++) {
|
|
2169
|
+
try {
|
|
2170
|
+
const job = await readAgent.getMonitoringJob(BigInt(id));
|
|
2171
|
+
if (job.poster === ZERO) continue;
|
|
2172
|
+
if (job.status !== 1) continue;
|
|
2173
|
+
if (job.worker.toLowerCase() !== workerAddress) continue;
|
|
2174
|
+
let payload = {};
|
|
2175
|
+
try {
|
|
2176
|
+
payload = JSON.parse(job.moltbookPostId);
|
|
2177
|
+
} catch {
|
|
2178
|
+
}
|
|
2179
|
+
const lastReport = Number(job.lastReportAt);
|
|
2180
|
+
const interval = Number(job.checkIntervalSeconds);
|
|
2181
|
+
const referenceTime = lastReport > 0 ? lastReport : Number(job.claimedAt);
|
|
2182
|
+
const nextCheckAt = referenceTime + interval;
|
|
2183
|
+
const missedIntervals = Math.max(0, Math.floor((now - referenceTime) / interval));
|
|
2184
|
+
let status;
|
|
2185
|
+
let nextInSecs = nextCheckAt - now;
|
|
2186
|
+
if (missedIntervals >= 2) {
|
|
2187
|
+
status = "AT_RISK";
|
|
2188
|
+
needsAction = true;
|
|
2189
|
+
} else if (now > nextCheckAt + interval) {
|
|
2190
|
+
status = "OVERDUE";
|
|
2191
|
+
needsAction = true;
|
|
2192
|
+
} else if (now > nextCheckAt) {
|
|
2193
|
+
status = "DUE_NOW";
|
|
2194
|
+
needsAction = true;
|
|
2195
|
+
} else if (nextCheckAt - now <= 300) {
|
|
2196
|
+
status = "DUE_SOON";
|
|
2197
|
+
needsAction = true;
|
|
2198
|
+
} else {
|
|
2199
|
+
status = "SAFE";
|
|
2200
|
+
}
|
|
2201
|
+
myJobs.push({
|
|
2202
|
+
id,
|
|
2203
|
+
hotel: payload.hotel ?? "(unknown)",
|
|
2204
|
+
status,
|
|
2205
|
+
reportCount: Number(job.reportCount),
|
|
2206
|
+
nextInSecs,
|
|
2207
|
+
intervalSecs: interval,
|
|
2208
|
+
missedIntervals
|
|
2209
|
+
});
|
|
2210
|
+
} catch {
|
|
2211
|
+
break;
|
|
2212
|
+
}
|
|
2213
|
+
}
|
|
2214
|
+
if (myJobs.length === 0) {
|
|
2215
|
+
console.log(`No claimed jobs found for ${workerAddress.slice(0, 10)}...`);
|
|
2216
|
+
console.log(`
|
|
2217
|
+
Looking for work? Run: npx travelmolt-sdk@latest list-jobs`);
|
|
2218
|
+
break;
|
|
2219
|
+
}
|
|
2220
|
+
if (hasFlag("json")) {
|
|
2221
|
+
console.log(JSON.stringify({ worker: workerAddress, jobs: myJobs, needsAction, timestamp: now }));
|
|
2222
|
+
if (needsAction) process.exit(2);
|
|
2223
|
+
break;
|
|
2224
|
+
}
|
|
2225
|
+
console.log(`Jobs for ${workerAddress.slice(0, 10)}...
|
|
2226
|
+
`);
|
|
2227
|
+
for (const job of myJobs) {
|
|
2228
|
+
let statusTag;
|
|
2229
|
+
let detail;
|
|
2230
|
+
switch (job.status) {
|
|
2231
|
+
case "AT_RISK":
|
|
2232
|
+
statusTag = "!! AT RISK";
|
|
2233
|
+
detail = `${job.missedIntervals} intervals missed \u2014 submit NOW or you will be reclaimed!`;
|
|
2234
|
+
break;
|
|
2235
|
+
case "OVERDUE":
|
|
2236
|
+
statusTag = "! OVERDUE";
|
|
2237
|
+
detail = `overdue by ${formatDuration(Math.abs(job.nextInSecs))} \u2014 submit report now`;
|
|
2238
|
+
break;
|
|
2239
|
+
case "DUE_NOW":
|
|
2240
|
+
statusTag = "! DUE NOW";
|
|
2241
|
+
detail = `report due \u2014 submit now`;
|
|
2242
|
+
break;
|
|
2243
|
+
case "DUE_SOON":
|
|
2244
|
+
statusTag = "~ DUE SOON";
|
|
2245
|
+
detail = `due in ${formatDuration(job.nextInSecs)}`;
|
|
2246
|
+
break;
|
|
2247
|
+
case "SAFE":
|
|
2248
|
+
statusTag = " OK";
|
|
2249
|
+
detail = `next in ${formatDuration(job.nextInSecs)}`;
|
|
2250
|
+
break;
|
|
2251
|
+
}
|
|
2252
|
+
console.log(` [${statusTag}] Job #${job.id}: ${job.hotel}`);
|
|
2253
|
+
console.log(` ${detail} | ${job.reportCount} reports | interval ${formatDuration(job.intervalSecs)}`);
|
|
2254
|
+
if (job.status !== "SAFE") {
|
|
2255
|
+
console.log(` -> npx travelmolt-sdk@latest check-price ${job.id}`);
|
|
2256
|
+
}
|
|
2257
|
+
console.log();
|
|
2258
|
+
}
|
|
2259
|
+
console.log(`${myJobs.length} job(s) total.`);
|
|
2260
|
+
if (needsAction) {
|
|
2261
|
+
console.log(`
|
|
2262
|
+
ACTION REQUIRED: ${myJobs.filter((j) => j.status !== "SAFE").length} job(s) need attention.`);
|
|
2263
|
+
process.exit(2);
|
|
2264
|
+
} else {
|
|
2265
|
+
console.log(`
|
|
2266
|
+
All jobs on schedule.`);
|
|
2267
|
+
}
|
|
2268
|
+
break;
|
|
2269
|
+
}
|
|
2128
2270
|
case "check-price": {
|
|
2129
2271
|
const id = args[1];
|
|
2130
2272
|
if (!id) {
|
|
2131
|
-
console.error("Usage: travelmolt check-price <id
|
|
2132
|
-
process.exit(1);
|
|
2133
|
-
}
|
|
2134
|
-
const serpKey = process.env.SERPAPI_API_KEY;
|
|
2135
|
-
if (!serpKey) {
|
|
2136
|
-
console.error("Error: SERPAPI_API_KEY env var required.");
|
|
2137
|
-
console.error(" export SERPAPI_API_KEY=your_key_here");
|
|
2273
|
+
console.error("Usage: travelmolt check-price <id> [--serpapi-key KEY]");
|
|
2138
2274
|
process.exit(1);
|
|
2139
2275
|
}
|
|
2276
|
+
const serpKey = getSerpApiKey();
|
|
2140
2277
|
const publicClient = getPublicClient();
|
|
2141
2278
|
const readAgent = new TravelMoltAgent({ publicClient, walletClient: null });
|
|
2142
2279
|
const job = await readAgent.getMonitoringJob(BigInt(id));
|
|
@@ -2175,7 +2312,7 @@ Hotel: ${payload.hotel}`);
|
|
|
2175
2312
|
console.log(`Alert: NO`);
|
|
2176
2313
|
console.log(`
|
|
2177
2314
|
Next step \u2014 submit report with price=0:`);
|
|
2178
|
-
console.log(`
|
|
2315
|
+
console.log(` npx travelmolt-sdk@latest report ${id} --price 0 --private-key 0xYOUR_KEY`);
|
|
2179
2316
|
break;
|
|
2180
2317
|
}
|
|
2181
2318
|
const priceNum = hotel.rate_per_night?.extracted_lowest ?? parseFloat((hotel.rate_per_night?.lowest ?? "0").replace(/[^0-9.]/g, ""));
|
|
@@ -2189,21 +2326,16 @@ Hotel: ${hotel.name ?? payload.hotel}`);
|
|
|
2189
2326
|
const alertFlag = alertTriggered ? " --alert" : "";
|
|
2190
2327
|
console.log(`
|
|
2191
2328
|
Next step \u2014 submit report:`);
|
|
2192
|
-
console.log(`
|
|
2329
|
+
console.log(` npx travelmolt-sdk@latest report ${id} --price ${priceInCents}${alertFlag} --private-key 0xYOUR_KEY`);
|
|
2193
2330
|
break;
|
|
2194
2331
|
}
|
|
2195
2332
|
case "monitor": {
|
|
2196
2333
|
const id = args[1];
|
|
2197
2334
|
if (!id) {
|
|
2198
|
-
console.error("Usage: travelmolt monitor <id
|
|
2199
|
-
process.exit(1);
|
|
2200
|
-
}
|
|
2201
|
-
const serpKey = process.env.SERPAPI_API_KEY;
|
|
2202
|
-
if (!serpKey) {
|
|
2203
|
-
console.error("Error: SERPAPI_API_KEY env var required.");
|
|
2204
|
-
console.error(" export SERPAPI_API_KEY=your_key_here");
|
|
2335
|
+
console.error("Usage: travelmolt monitor <id> [--serpapi-key KEY] [--private-key KEY]");
|
|
2205
2336
|
process.exit(1);
|
|
2206
2337
|
}
|
|
2338
|
+
const serpKey = getSerpApiKey();
|
|
2207
2339
|
const monAgent = getAgent();
|
|
2208
2340
|
await monAgent.init();
|
|
2209
2341
|
const jobIdBig = BigInt(id);
|
|
@@ -2366,6 +2498,7 @@ Commands:
|
|
|
2366
2498
|
claim <id> Claim a monitoring job (needs PRIVATE_KEY)
|
|
2367
2499
|
unclaim <id> Unclaim a monitoring job (needs PRIVATE_KEY)
|
|
2368
2500
|
report <id> --price <cents> [--alert] [--force] Submit a monitoring report
|
|
2501
|
+
my-jobs [--address 0x...] Show your claimed jobs and what's due (exit code 2 if action needed)
|
|
2369
2502
|
check-price <id> Check hotel price via SerpAPI (needs SERPAPI_API_KEY)
|
|
2370
2503
|
monitor <id> Long-running price check + report loop
|
|
2371
2504
|
register --name "Name" Register agent identity with display name
|
|
@@ -2373,6 +2506,10 @@ Commands:
|
|
|
2373
2506
|
status <id> Job status + reports
|
|
2374
2507
|
balance Show USDC + ETH balance (needs PRIVATE_KEY)
|
|
2375
2508
|
|
|
2509
|
+
Global flags (alternative to env vars):
|
|
2510
|
+
--private-key <key> Hex private key (alternative to PRIVATE_KEY env var)
|
|
2511
|
+
--serpapi-key <key> SerpAPI key (alternative to SERPAPI_API_KEY env var)
|
|
2512
|
+
|
|
2376
2513
|
Environment:
|
|
2377
2514
|
PRIVATE_KEY Hex private key (required for write operations)
|
|
2378
2515
|
SERPAPI_API_KEY SerpAPI key (required for check-price and monitor)
|