travelmolt-sdk 1.3.1 → 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 CHANGED
@@ -1917,6 +1917,14 @@ function formatUsdc(raw) {
1917
1917
  const frac = raw % 1000000n;
1918
1918
  return `${whole}.${frac.toString().padStart(6, "0")} USDC`;
1919
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
+ }
1920
1928
  function printJob(id, job) {
1921
1929
  const statusNames = ["Open", "Claimed", "Completed", "Cancelled"];
1922
1930
  let payload = {};
@@ -2136,6 +2144,129 @@ Use --force to bypass this check.`);
2136
2144
  console.log(` Expected reports: ${expected}`);
2137
2145
  break;
2138
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
+ }
2139
2270
  case "check-price": {
2140
2271
  const id = args[1];
2141
2272
  if (!id) {
@@ -2367,6 +2498,7 @@ Commands:
2367
2498
  claim <id> Claim a monitoring job (needs PRIVATE_KEY)
2368
2499
  unclaim <id> Unclaim a monitoring job (needs PRIVATE_KEY)
2369
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)
2370
2502
  check-price <id> Check hotel price via SerpAPI (needs SERPAPI_API_KEY)
2371
2503
  monitor <id> Long-running price check + report loop
2372
2504
  register --name "Name" Register agent identity with display name