unbrowse 3.0.2 → 3.1.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.js +276 -73
- package/dist/mcp.js +76 -37
- package/package.json +1 -1
- package/runtime-src/api/routes.ts +25 -2
- package/runtime-src/build-info.generated.ts +4 -4
- package/runtime-src/cli.ts +26 -0
- package/runtime-src/client/index.ts +28 -12
- package/runtime-src/execution/index.ts +33 -21
- package/runtime-src/kuri/client.ts +5 -1
- package/runtime-src/mcp.ts +82 -33
- package/runtime-src/orchestrator/index.ts +7 -3
- package/runtime-src/payments/lobster-pay.ts +182 -0
- package/vendor/kuri/darwin-arm64/kuri +0 -0
- package/vendor/kuri/darwin-x64/kuri +0 -0
- package/vendor/kuri/linux-arm64/kuri +0 -0
- package/vendor/kuri/linux-x64/kuri +0 -0
- package/vendor/kuri/manifest.json +10 -6
- package/vendor/kuri/win-x64/kuri.exe +0 -0
package/dist/cli.js
CHANGED
|
@@ -17,12 +17,21 @@ var __toESM = (mod, isNodeMode, target) => {
|
|
|
17
17
|
});
|
|
18
18
|
return to;
|
|
19
19
|
};
|
|
20
|
+
var __export = (target, all) => {
|
|
21
|
+
for (var name in all)
|
|
22
|
+
__defProp(target, name, {
|
|
23
|
+
get: all[name],
|
|
24
|
+
enumerable: true,
|
|
25
|
+
configurable: true,
|
|
26
|
+
set: (newValue) => all[name] = () => newValue
|
|
27
|
+
});
|
|
28
|
+
};
|
|
20
29
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
21
30
|
var __promiseAll = (args) => Promise.all(args);
|
|
22
31
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
23
32
|
|
|
24
33
|
// ../../src/build-info.generated.ts
|
|
25
|
-
var BUILD_RELEASE_VERSION = "3.0
|
|
34
|
+
var BUILD_RELEASE_VERSION = "3.1.0", BUILD_GIT_SHA = "c9f9ce0e5cb1", BUILD_CODE_HASH = "1488fc1d92b7", BUILD_RELEASE_MANIFEST_BASE64 = "eyJzY2hlbWFfdmVyc2lvbiI6MSwicmVsZWFzZV92ZXJzaW9uIjoiMy4xLjAiLCJnaXRfc2hhIjoiYzlmOWNlMGU1Y2IxIiwiY29kZV9oYXNoIjoiMTQ4OGZjMWQ5MmI3IiwidHJhY2VfdmVyc2lvbiI6IjE0ODhmYzFkOTJiN0BjOWY5Y2UwZTVjYjEiLCJpc3N1ZWRfYXQiOiIyMDI2LTA0LTA1VDA2OjUwOjA4LjQzNVoifQ", BUILD_RELEASE_MANIFEST_SIGNATURE = "_2pdxyoIEYkKUHO0nXaXTubP5SrZCa-8CqStcPBsXxw", BUILD_DEFAULT_BACKEND_URL = "https://beta-api.unbrowse.ai";
|
|
26
35
|
|
|
27
36
|
// ../../src/version.ts
|
|
28
37
|
import { createHash } from "crypto";
|
|
@@ -284,8 +293,114 @@ var init_telemetry_attribution = __esm(() => {
|
|
|
284
293
|
];
|
|
285
294
|
});
|
|
286
295
|
|
|
296
|
+
// ../../src/payments/lobster-pay.ts
|
|
297
|
+
var exports_lobster_pay = {};
|
|
298
|
+
__export(exports_lobster_pay, {
|
|
299
|
+
payAndRetry: () => payAndRetry,
|
|
300
|
+
lobsterX402Fetch: () => lobsterX402Fetch,
|
|
301
|
+
isLobsterAvailable: () => isLobsterAvailable
|
|
302
|
+
});
|
|
303
|
+
import { execFile, execFileSync } from "node:child_process";
|
|
304
|
+
import { existsSync as existsSync3 } from "node:fs";
|
|
305
|
+
import { homedir as homedir2 } from "node:os";
|
|
306
|
+
import { join as join3 } from "node:path";
|
|
307
|
+
function getLobsterCommand() {
|
|
308
|
+
try {
|
|
309
|
+
execFileSync("lobstercash", ["--version"], { stdio: "ignore", timeout: 3000 });
|
|
310
|
+
return { cmd: "lobstercash", prefix: [] };
|
|
311
|
+
} catch (_e) {}
|
|
312
|
+
try {
|
|
313
|
+
const npmPrefix = execFileSync("npm", ["config", "get", "prefix"], { encoding: "utf8", timeout: 5000 }).trim();
|
|
314
|
+
const lobsterPath = join3(npmPrefix, "bin", "lobstercash");
|
|
315
|
+
if (existsSync3(lobsterPath)) {
|
|
316
|
+
execFileSync(lobsterPath, ["--version"], { stdio: "ignore", timeout: 3000 });
|
|
317
|
+
return { cmd: lobsterPath, prefix: [] };
|
|
318
|
+
}
|
|
319
|
+
} catch (_e) {}
|
|
320
|
+
return null;
|
|
321
|
+
}
|
|
322
|
+
function lobsterCmd() {
|
|
323
|
+
if (cachedCommand === undefined)
|
|
324
|
+
cachedCommand = getLobsterCommand();
|
|
325
|
+
return cachedCommand;
|
|
326
|
+
}
|
|
327
|
+
function isLobsterAvailable() {
|
|
328
|
+
const agentsPath = join3(process.env.HOME || homedir2(), ".lobster", "agents.json");
|
|
329
|
+
return existsSync3(agentsPath);
|
|
330
|
+
}
|
|
331
|
+
function lobsterX402Fetch(url, options) {
|
|
332
|
+
return new Promise((resolve) => {
|
|
333
|
+
const resolved = lobsterCmd();
|
|
334
|
+
if (!resolved) {
|
|
335
|
+
resolve({ success: false, body: "", error: "lobstercash CLI not in PATH" });
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
const { cmd, prefix } = resolved;
|
|
339
|
+
const args = [...prefix, "x402", "fetch", url, "--debug"];
|
|
340
|
+
if (options?.jsonBody) {
|
|
341
|
+
args.push("--json", options.jsonBody);
|
|
342
|
+
}
|
|
343
|
+
if (options?.headers) {
|
|
344
|
+
for (const [key, value] of Object.entries(options.headers)) {
|
|
345
|
+
args.push("--header", `${key}:${value}`);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
const timeout = options?.timeoutMs ?? LOBSTER_PAY_TIMEOUT_MS;
|
|
349
|
+
args.push("--timeout", String(timeout));
|
|
350
|
+
execFile(cmd, args, { timeout: timeout + 5000, maxBuffer: 1024 * 1024 }, (err, stdout, stderr) => {
|
|
351
|
+
if (err) {
|
|
352
|
+
const msg = stderr?.trim() || err.message;
|
|
353
|
+
console.warn(`[lobster-pay] x402 fetch failed: ${msg}`);
|
|
354
|
+
resolve({ success: false, body: "", error: msg });
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
if (stderr) {
|
|
358
|
+
for (const line of stderr.split(`
|
|
359
|
+
`).filter(Boolean)) {
|
|
360
|
+
console.log(`[lobster-pay] ${line}`);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
const statusMatch = stdout.match(/^Status:\s*(\d+)/m);
|
|
364
|
+
const statusCode = statusMatch ? parseInt(statusMatch[1], 10) : undefined;
|
|
365
|
+
if (statusCode && statusCode >= 400) {
|
|
366
|
+
resolve({ success: false, body: stdout, statusCode, error: `HTTP ${statusCode}` });
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
resolve({ success: true, body: stdout, statusCode });
|
|
370
|
+
});
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
async function payAndRetry(fullUrl, options) {
|
|
374
|
+
if (!isLobsterAvailable()) {
|
|
375
|
+
console.log("[lobster-pay] lobster.cash not configured — skipping payment");
|
|
376
|
+
return null;
|
|
377
|
+
}
|
|
378
|
+
console.log(`[lobster-pay] attempting x402 payment for ${fullUrl}`);
|
|
379
|
+
const result = await lobsterX402Fetch(fullUrl, {
|
|
380
|
+
jsonBody: options?.body ? JSON.stringify(options.body) : undefined,
|
|
381
|
+
headers: options?.headers
|
|
382
|
+
});
|
|
383
|
+
if (!result.success) {
|
|
384
|
+
console.warn(`[lobster-pay] payment failed: ${result.error}`);
|
|
385
|
+
return null;
|
|
386
|
+
}
|
|
387
|
+
try {
|
|
388
|
+
const raw = result.body;
|
|
389
|
+
const jsonStart = Math.min(...[raw.indexOf("{"), raw.indexOf("[")].filter((i) => i >= 0));
|
|
390
|
+
const jsonStr = jsonStart >= 0 ? raw.slice(jsonStart) : raw;
|
|
391
|
+
const data = JSON.parse(jsonStr);
|
|
392
|
+
console.log("[lobster-pay] payment successful — got paid response");
|
|
393
|
+
return { data, paid: true };
|
|
394
|
+
} catch (_e) {
|
|
395
|
+
console.warn("[lobster-pay] paid response was not valid JSON");
|
|
396
|
+
return null;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
var LOBSTER_PAY_TIMEOUT_MS = 30000, cachedCommand = undefined;
|
|
400
|
+
var init_lobster_pay = () => {};
|
|
401
|
+
|
|
287
402
|
// ../../src/runtime/paths.ts
|
|
288
|
-
import { existsSync as
|
|
403
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync2, realpathSync } from "node:fs";
|
|
289
404
|
import os from "node:os";
|
|
290
405
|
import path from "node:path";
|
|
291
406
|
import { createRequire as createRequire2 } from "node:module";
|
|
@@ -299,7 +414,7 @@ function getPackageRoot(metaUrl) {
|
|
|
299
414
|
let dir = getModuleDir(metaUrl);
|
|
300
415
|
const root = path.parse(dir).root;
|
|
301
416
|
while (dir !== root) {
|
|
302
|
-
if (
|
|
417
|
+
if (existsSync5(path.join(dir, "package.json")))
|
|
303
418
|
return dir;
|
|
304
419
|
dir = path.dirname(dir);
|
|
305
420
|
}
|
|
@@ -318,7 +433,7 @@ function runtimeArgsForEntrypoint(metaUrl, entrypoint) {
|
|
|
318
433
|
const req = createRequire2(metaUrl);
|
|
319
434
|
const tsxPkg = req.resolve("tsx/package.json");
|
|
320
435
|
const tsxLoader = path.join(path.dirname(tsxPkg), "dist", "loader.mjs");
|
|
321
|
-
if (
|
|
436
|
+
if (existsSync5(tsxLoader))
|
|
322
437
|
return ["--import", pathToFileURL(tsxLoader).href, entrypoint];
|
|
323
438
|
} catch {}
|
|
324
439
|
return ["--import", "tsx", entrypoint];
|
|
@@ -327,7 +442,7 @@ function getUnbrowseHome() {
|
|
|
327
442
|
return path.join(os.homedir(), ".unbrowse");
|
|
328
443
|
}
|
|
329
444
|
function ensureDir(dir) {
|
|
330
|
-
if (!
|
|
445
|
+
if (!existsSync5(dir))
|
|
331
446
|
mkdirSync2(dir, { recursive: true });
|
|
332
447
|
return dir;
|
|
333
448
|
}
|
|
@@ -470,8 +585,8 @@ var init_logger = __esm(() => {
|
|
|
470
585
|
});
|
|
471
586
|
|
|
472
587
|
// ../../src/kuri/client.ts
|
|
473
|
-
import { execFileSync, spawn as spawn2 } from "node:child_process";
|
|
474
|
-
import { existsSync as
|
|
588
|
+
import { execFileSync as execFileSync2, spawn as spawn2 } from "node:child_process";
|
|
589
|
+
import { existsSync as existsSync7 } from "node:fs";
|
|
475
590
|
import path5 from "node:path";
|
|
476
591
|
function createBrokerState(port = KURI_DEFAULT_PORT) {
|
|
477
592
|
return {
|
|
@@ -496,12 +611,14 @@ function currentBundledKuriTarget() {
|
|
|
496
611
|
return "linux-arm64";
|
|
497
612
|
if (process.platform === "linux" && process.arch === "x64")
|
|
498
613
|
return "linux-x64";
|
|
614
|
+
if (process.platform === "win32" && process.arch === "x64")
|
|
615
|
+
return "win-x64";
|
|
499
616
|
return null;
|
|
500
617
|
}
|
|
501
618
|
function resolveBinaryOnPath(name) {
|
|
502
619
|
const checker = process.platform === "win32" ? "where" : "which";
|
|
503
620
|
try {
|
|
504
|
-
const output =
|
|
621
|
+
const output = execFileSync2(checker, [name], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
|
|
505
622
|
const match = output.split(/\r?\n/).map((line) => line.trim()).find(Boolean);
|
|
506
623
|
return match || null;
|
|
507
624
|
} catch {
|
|
@@ -544,7 +661,7 @@ function findKuriBinary() {
|
|
|
544
661
|
if (process.env.KURI_BIN)
|
|
545
662
|
return process.env.KURI_BIN;
|
|
546
663
|
const candidates = getKuriBinaryCandidates();
|
|
547
|
-
return candidates.find((candidate) =>
|
|
664
|
+
return candidates.find((candidate) => existsSync7(candidate)) ?? candidates[0] ?? kuriBinaryName();
|
|
548
665
|
}
|
|
549
666
|
var KURI_DEFAULT_PORT = 7700, defaultBrokerState, brokerClients;
|
|
550
667
|
var init_client2 = __esm(() => {
|
|
@@ -584,11 +701,11 @@ var init_transform = __esm(() => {
|
|
|
584
701
|
});
|
|
585
702
|
|
|
586
703
|
// ../../src/debug-trace.ts
|
|
587
|
-
import { join as
|
|
704
|
+
import { join as join5 } from "node:path";
|
|
588
705
|
import { nanoid as nanoid3 } from "nanoid";
|
|
589
706
|
var TRACE_DIR;
|
|
590
707
|
var init_debug_trace = __esm(() => {
|
|
591
|
-
TRACE_DIR = process.env.TRACES_DIR ??
|
|
708
|
+
TRACE_DIR = process.env.TRACES_DIR ?? join5(process.cwd(), "traces");
|
|
592
709
|
});
|
|
593
710
|
|
|
594
711
|
// ../../src/publish/sanitize.ts
|
|
@@ -678,8 +795,8 @@ var init_bundle_scanner = __esm(() => {
|
|
|
678
795
|
});
|
|
679
796
|
|
|
680
797
|
// ../../src/vault/index.ts
|
|
681
|
-
import { join as
|
|
682
|
-
import { homedir as
|
|
798
|
+
import { join as join6 } from "path";
|
|
799
|
+
import { homedir as homedir4 } from "os";
|
|
683
800
|
function normalizeKeytarModule(mod) {
|
|
684
801
|
let candidate = mod;
|
|
685
802
|
for (let depth = 0;depth < 3; depth++) {
|
|
@@ -701,9 +818,9 @@ var init_vault = __esm(async () => {
|
|
|
701
818
|
try {
|
|
702
819
|
keytar = normalizeKeytarModule(await import("keytar"));
|
|
703
820
|
} catch {}
|
|
704
|
-
VAULT_DIR =
|
|
705
|
-
VAULT_FILE =
|
|
706
|
-
KEY_FILE =
|
|
821
|
+
VAULT_DIR = join6(homedir4(), ".unbrowse", "vault");
|
|
822
|
+
VAULT_FILE = join6(VAULT_DIR, "credentials.enc");
|
|
823
|
+
KEY_FILE = join6(VAULT_DIR, ".key");
|
|
707
824
|
vaultLock = Promise.resolve();
|
|
708
825
|
});
|
|
709
826
|
|
|
@@ -854,7 +971,7 @@ var init_schema_review = __esm(() => {
|
|
|
854
971
|
});
|
|
855
972
|
|
|
856
973
|
// ../../src/indexer/index.ts
|
|
857
|
-
import { join as
|
|
974
|
+
import { join as join7 } from "node:path";
|
|
858
975
|
var SKILL_SNAPSHOT_DIR, indexInFlight, pendingIndexJobs;
|
|
859
976
|
var init_indexer = __esm(async () => {
|
|
860
977
|
init_graph();
|
|
@@ -869,7 +986,7 @@ var init_indexer = __esm(async () => {
|
|
|
869
986
|
init_graph();
|
|
870
987
|
init_schema_review();
|
|
871
988
|
await init_orchestrator();
|
|
872
|
-
SKILL_SNAPSHOT_DIR = process.env.UNBROWSE_SKILL_SNAPSHOT_DIR ??
|
|
989
|
+
SKILL_SNAPSHOT_DIR = process.env.UNBROWSE_SKILL_SNAPSHOT_DIR ?? join7(process.env.HOME ?? "/tmp", ".unbrowse", "skill-snapshots");
|
|
873
990
|
indexInFlight = new Map;
|
|
874
991
|
pendingIndexJobs = new Map;
|
|
875
992
|
});
|
|
@@ -1046,8 +1163,8 @@ var init_routing_telemetry = __esm(() => {
|
|
|
1046
1163
|
});
|
|
1047
1164
|
// ../../src/orchestrator/index.ts
|
|
1048
1165
|
import { nanoid as nanoid9 } from "nanoid";
|
|
1049
|
-
import { existsSync as
|
|
1050
|
-
import { dirname as dirname2, join as
|
|
1166
|
+
import { existsSync as existsSync8, writeFileSync as writeFileSync3, readFileSync as readFileSync5, mkdirSync as mkdirSync4, readdirSync as readdirSync3 } from "node:fs";
|
|
1167
|
+
import { dirname as dirname2, join as join8 } from "node:path";
|
|
1051
1168
|
var LIVE_CAPTURE_TIMEOUT_MS, capturedDomainCache, captureInFlight, captureDomainLocks, skillRouteCache, ROUTE_CACHE_FILE, SKILL_SNAPSHOT_DIR2, domainSkillCache, DOMAIN_CACHE_FILE, _routeCacheDirty = false, routeCacheFlushTimer, routeResultCache, ROUTE_CACHE_TTL, MARKETPLACE_HYDRATE_LIMIT, MARKETPLACE_GET_SKILL_TIMEOUT_MS, MARKETPLACE_DOMAIN_SEARCH_K, MARKETPLACE_GLOBAL_SEARCH_K, SEARCH_INTENT_STOPWORDS;
|
|
1052
1169
|
var init_orchestrator = __esm(async () => {
|
|
1053
1170
|
init_client();
|
|
@@ -1077,12 +1194,12 @@ var init_orchestrator = __esm(async () => {
|
|
|
1077
1194
|
captureInFlight = new Map;
|
|
1078
1195
|
captureDomainLocks = new Map;
|
|
1079
1196
|
skillRouteCache = new Map;
|
|
1080
|
-
ROUTE_CACHE_FILE =
|
|
1081
|
-
SKILL_SNAPSHOT_DIR2 = process.env.UNBROWSE_SKILL_SNAPSHOT_DIR ??
|
|
1197
|
+
ROUTE_CACHE_FILE = join8(process.env.HOME ?? "/tmp", ".unbrowse", "route-cache.json");
|
|
1198
|
+
SKILL_SNAPSHOT_DIR2 = process.env.UNBROWSE_SKILL_SNAPSHOT_DIR ?? join8(process.env.HOME ?? "/tmp", ".unbrowse", "skill-snapshots");
|
|
1082
1199
|
domainSkillCache = new Map;
|
|
1083
|
-
DOMAIN_CACHE_FILE =
|
|
1200
|
+
DOMAIN_CACHE_FILE = join8(process.env.HOME ?? "/tmp", ".unbrowse", "domain-skill-cache.json");
|
|
1084
1201
|
try {
|
|
1085
|
-
if (
|
|
1202
|
+
if (existsSync8(DOMAIN_CACHE_FILE)) {
|
|
1086
1203
|
const data = JSON.parse(readFileSync5(DOMAIN_CACHE_FILE, "utf-8"));
|
|
1087
1204
|
for (const [k, v] of Object.entries(data)) {
|
|
1088
1205
|
const entry = v;
|
|
@@ -1099,7 +1216,7 @@ var init_orchestrator = __esm(async () => {
|
|
|
1099
1216
|
_routeCacheDirty = false;
|
|
1100
1217
|
try {
|
|
1101
1218
|
const dir = dirname2(ROUTE_CACHE_FILE);
|
|
1102
|
-
if (!
|
|
1219
|
+
if (!existsSync8(dir))
|
|
1103
1220
|
mkdirSync4(dir, { recursive: true });
|
|
1104
1221
|
const entries = Object.fromEntries(skillRouteCache);
|
|
1105
1222
|
writeFileSync3(ROUTE_CACHE_FILE, JSON.stringify(entries), "utf-8");
|
|
@@ -1107,7 +1224,7 @@ var init_orchestrator = __esm(async () => {
|
|
|
1107
1224
|
}, 5000);
|
|
1108
1225
|
routeCacheFlushTimer.unref?.();
|
|
1109
1226
|
try {
|
|
1110
|
-
if (
|
|
1227
|
+
if (existsSync8(ROUTE_CACHE_FILE)) {
|
|
1111
1228
|
const data = JSON.parse(readFileSync5(ROUTE_CACHE_FILE, "utf-8"));
|
|
1112
1229
|
for (const [k, v] of Object.entries(data)) {
|
|
1113
1230
|
const entry = v;
|
|
@@ -1198,6 +1315,60 @@ var init_orchestrator = __esm(async () => {
|
|
|
1198
1315
|
]);
|
|
1199
1316
|
});
|
|
1200
1317
|
|
|
1318
|
+
// ../../src/payments/wallet.ts
|
|
1319
|
+
var exports_wallet = {};
|
|
1320
|
+
__export(exports_wallet, {
|
|
1321
|
+
getWalletContext: () => getWalletContext2,
|
|
1322
|
+
checkWalletConfigured: () => checkWalletConfigured2
|
|
1323
|
+
});
|
|
1324
|
+
import { existsSync as existsSync12, readFileSync as readFileSync8 } from "node:fs";
|
|
1325
|
+
import { homedir as homedir5 } from "node:os";
|
|
1326
|
+
import { join as join10 } from "node:path";
|
|
1327
|
+
function asNonEmptyString2(value) {
|
|
1328
|
+
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
1329
|
+
}
|
|
1330
|
+
function getLobsterWalletFromLocalConfig2() {
|
|
1331
|
+
const agentsPath = join10(process.env.HOME || homedir5(), ".lobster", "agents.json");
|
|
1332
|
+
if (!existsSync12(agentsPath))
|
|
1333
|
+
return;
|
|
1334
|
+
try {
|
|
1335
|
+
const raw = JSON.parse(readFileSync8(agentsPath, "utf8"));
|
|
1336
|
+
const activeAgentId = asNonEmptyString2(raw.activeAgentId);
|
|
1337
|
+
const activeAgent = Array.isArray(raw.agents) ? raw.agents.find((agent) => asNonEmptyString2(agent.id) === activeAgentId) : activeAgentId ? raw.agents?.[activeAgentId] : undefined;
|
|
1338
|
+
return asNonEmptyString2(activeAgent?.authorizedWallets?.solana) ?? asNonEmptyString2(activeAgent?.walletAddress) ?? asNonEmptyString2(activeAgent?.wallet_address);
|
|
1339
|
+
} catch {
|
|
1340
|
+
return;
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
function getWalletContext2() {
|
|
1344
|
+
const lobsterWallet = asNonEmptyString2(process.env.LOBSTER_WALLET_ADDRESS);
|
|
1345
|
+
if (lobsterWallet) {
|
|
1346
|
+
return { wallet_address: lobsterWallet, wallet_provider: "lobster.cash" };
|
|
1347
|
+
}
|
|
1348
|
+
const genericWallet = asNonEmptyString2(process.env.AGENT_WALLET_ADDRESS);
|
|
1349
|
+
if (genericWallet) {
|
|
1350
|
+
return {
|
|
1351
|
+
wallet_address: genericWallet,
|
|
1352
|
+
wallet_provider: asNonEmptyString2(process.env.AGENT_WALLET_PROVIDER)
|
|
1353
|
+
};
|
|
1354
|
+
}
|
|
1355
|
+
const localLobsterWallet = getLobsterWalletFromLocalConfig2();
|
|
1356
|
+
if (localLobsterWallet) {
|
|
1357
|
+
return { wallet_address: localLobsterWallet, wallet_provider: "lobster.cash" };
|
|
1358
|
+
}
|
|
1359
|
+
return {};
|
|
1360
|
+
}
|
|
1361
|
+
function checkWalletConfigured2() {
|
|
1362
|
+
const wallet = getWalletContext2();
|
|
1363
|
+
if (!wallet.wallet_address)
|
|
1364
|
+
return { configured: false };
|
|
1365
|
+
return {
|
|
1366
|
+
configured: true,
|
|
1367
|
+
provider: wallet.wallet_provider ?? "unknown"
|
|
1368
|
+
};
|
|
1369
|
+
}
|
|
1370
|
+
var init_wallet2 = () => {};
|
|
1371
|
+
|
|
1201
1372
|
// ../../src/cli.ts
|
|
1202
1373
|
import { config as loadEnv } from "dotenv";
|
|
1203
1374
|
import { spawn as spawn3 } from "child_process";
|
|
@@ -1207,9 +1378,9 @@ init_version();
|
|
|
1207
1378
|
init_cascade();
|
|
1208
1379
|
init_wallet();
|
|
1209
1380
|
init_telemetry_attribution();
|
|
1210
|
-
import { readFileSync as readFileSync3, writeFileSync, existsSync as
|
|
1211
|
-
import { join as
|
|
1212
|
-
import { homedir as
|
|
1381
|
+
import { readFileSync as readFileSync3, writeFileSync, existsSync as existsSync4, mkdirSync, readdirSync as readdirSync2 } from "fs";
|
|
1382
|
+
import { join as join4 } from "path";
|
|
1383
|
+
import { homedir as homedir3, hostname } from "os";
|
|
1213
1384
|
import { randomBytes, createHash as createHash2 } from "crypto";
|
|
1214
1385
|
import { createInterface } from "readline";
|
|
1215
1386
|
var API_URL = process.env.UNBROWSE_BACKEND_URL || DEFAULT_BACKEND_URL;
|
|
@@ -1244,13 +1415,13 @@ function decodeBase64Json(value) {
|
|
|
1244
1415
|
function getConfigDir() {
|
|
1245
1416
|
if (process.env.UNBROWSE_CONFIG_DIR)
|
|
1246
1417
|
return process.env.UNBROWSE_CONFIG_DIR;
|
|
1247
|
-
return PROFILE_NAME ?
|
|
1418
|
+
return PROFILE_NAME ? join4(homedir3(), ".unbrowse", "profiles", PROFILE_NAME) : join4(homedir3(), ".unbrowse");
|
|
1248
1419
|
}
|
|
1249
1420
|
function getConfigPath() {
|
|
1250
|
-
return
|
|
1421
|
+
return join4(getConfigDir(), "config.json");
|
|
1251
1422
|
}
|
|
1252
1423
|
function getInstallTelemetryPath() {
|
|
1253
|
-
return
|
|
1424
|
+
return join4(getConfigDir(), "install-state.json");
|
|
1254
1425
|
}
|
|
1255
1426
|
function getLandingToken() {
|
|
1256
1427
|
const token = process.env.UNBROWSE_LANDING_TOKEN?.trim();
|
|
@@ -1265,7 +1436,7 @@ function getActiveProfile() {
|
|
|
1265
1436
|
function loadConfig() {
|
|
1266
1437
|
try {
|
|
1267
1438
|
const configPath = getConfigPath();
|
|
1268
|
-
if (
|
|
1439
|
+
if (existsSync4(configPath)) {
|
|
1269
1440
|
return JSON.parse(readFileSync3(configPath, "utf-8"));
|
|
1270
1441
|
}
|
|
1271
1442
|
} catch {}
|
|
@@ -1274,14 +1445,14 @@ function loadConfig() {
|
|
|
1274
1445
|
function saveConfig(config) {
|
|
1275
1446
|
const configDir = getConfigDir();
|
|
1276
1447
|
const configPath = getConfigPath();
|
|
1277
|
-
if (!
|
|
1448
|
+
if (!existsSync4(configDir))
|
|
1278
1449
|
mkdirSync(configDir, { recursive: true });
|
|
1279
1450
|
writeFileSync(configPath, JSON.stringify(config, null, 2), { mode: 384 });
|
|
1280
1451
|
}
|
|
1281
1452
|
function loadInstallTelemetryState() {
|
|
1282
1453
|
try {
|
|
1283
1454
|
const statePath = getInstallTelemetryPath();
|
|
1284
|
-
if (
|
|
1455
|
+
if (existsSync4(statePath)) {
|
|
1285
1456
|
return JSON.parse(readFileSync3(statePath, "utf-8"));
|
|
1286
1457
|
}
|
|
1287
1458
|
} catch {}
|
|
@@ -1290,7 +1461,7 @@ function loadInstallTelemetryState() {
|
|
|
1290
1461
|
function saveInstallTelemetryState(state) {
|
|
1291
1462
|
const configDir = getConfigDir();
|
|
1292
1463
|
const statePath = getInstallTelemetryPath();
|
|
1293
|
-
if (!
|
|
1464
|
+
if (!existsSync4(configDir))
|
|
1294
1465
|
mkdirSync(configDir, { recursive: true });
|
|
1295
1466
|
writeFileSync(statePath, JSON.stringify(state, null, 2), { mode: 384 });
|
|
1296
1467
|
}
|
|
@@ -1547,6 +1718,26 @@ async function apiRequest(method, path, body, opts) {
|
|
|
1547
1718
|
const paymentRequired = res.headers.get("PAYMENT-REQUIRED");
|
|
1548
1719
|
const legacyPaymentTerms = res.headers.get("X-Payment-Required");
|
|
1549
1720
|
const terms = paymentRequired ? decodeBase64Json(paymentRequired) : legacyPaymentTerms ? JSON.parse(legacyPaymentTerms) : data.terms;
|
|
1721
|
+
try {
|
|
1722
|
+
const { isLobsterAvailable: isLobsterAvailable2, payAndRetry: payAndRetry2 } = await Promise.resolve().then(() => (init_lobster_pay(), exports_lobster_pay));
|
|
1723
|
+
if (isLobsterAvailable2()) {
|
|
1724
|
+
const fullUrl = `${API_URL}${path}`;
|
|
1725
|
+
const paidResult = await payAndRetry2(fullUrl, {
|
|
1726
|
+
body,
|
|
1727
|
+
headers: {
|
|
1728
|
+
"Content-Type": "application/json",
|
|
1729
|
+
"Accept-Encoding": "gzip, deflate",
|
|
1730
|
+
...releaseAttestationHeaders,
|
|
1731
|
+
...key ? { Authorization: `Bearer ${key}` } : {}
|
|
1732
|
+
}
|
|
1733
|
+
});
|
|
1734
|
+
if (paidResult) {
|
|
1735
|
+
return { data: paidResult.data, headers: new Headers };
|
|
1736
|
+
}
|
|
1737
|
+
}
|
|
1738
|
+
} catch (payErr) {
|
|
1739
|
+
console.warn(`[x402] lobster pay-and-retry failed: ${payErr.message}`);
|
|
1740
|
+
}
|
|
1550
1741
|
const err = new Error(`Payment required: ${data.error ?? "This skill requires payment"}`);
|
|
1551
1742
|
err.x402 = true;
|
|
1552
1743
|
err.terms = terms;
|
|
@@ -1565,19 +1756,10 @@ async function api(method, path, body, opts) {
|
|
|
1565
1756
|
return data;
|
|
1566
1757
|
}
|
|
1567
1758
|
function parseInstallAttribution() {
|
|
1568
|
-
const result = {};
|
|
1569
|
-
const b64 = process.env.UNBROWSE_ATTRIBUTION_B64;
|
|
1570
|
-
if (b64) {
|
|
1571
|
-
try {
|
|
1572
|
-
const decoded = JSON.parse(Buffer.from(b64, "base64").toString("utf8"));
|
|
1573
|
-
if (decoded && typeof decoded === "object")
|
|
1574
|
-
result.install_attribution = decoded;
|
|
1575
|
-
} catch {}
|
|
1576
|
-
}
|
|
1577
1759
|
const token = process.env.UNBROWSE_LANDING_TOKEN;
|
|
1578
1760
|
if (token && token.length < 2048)
|
|
1579
|
-
|
|
1580
|
-
return
|
|
1761
|
+
return { landing_token: token };
|
|
1762
|
+
return {};
|
|
1581
1763
|
}
|
|
1582
1764
|
async function promptTosAcceptance(summary, tosUrl) {
|
|
1583
1765
|
if (process.env.UNBROWSE_NON_INTERACTIVE === "1") {
|
|
@@ -2159,7 +2341,7 @@ async function restartServer(baseUrl, metaUrl) {
|
|
|
2159
2341
|
}
|
|
2160
2342
|
|
|
2161
2343
|
// ../../src/runtime/paths.ts
|
|
2162
|
-
import { existsSync as
|
|
2344
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync3, realpathSync as realpathSync2 } from "node:fs";
|
|
2163
2345
|
import path3 from "node:path";
|
|
2164
2346
|
import { createRequire as createRequire3 } from "node:module";
|
|
2165
2347
|
import { fileURLToPath as fileURLToPath3, pathToFileURL as pathToFileURL2 } from "node:url";
|
|
@@ -2179,7 +2361,7 @@ function runtimeArgsForEntrypoint2(metaUrl, entrypoint) {
|
|
|
2179
2361
|
const req = createRequire3(metaUrl);
|
|
2180
2362
|
const tsxPkg = req.resolve("tsx/package.json");
|
|
2181
2363
|
const tsxLoader = path3.join(path3.dirname(tsxPkg), "dist", "loader.mjs");
|
|
2182
|
-
if (
|
|
2364
|
+
if (existsSync6(tsxLoader))
|
|
2183
2365
|
return ["--import", pathToFileURL2(tsxLoader).href, entrypoint];
|
|
2184
2366
|
} catch {}
|
|
2185
2367
|
return ["--import", "tsx", entrypoint];
|
|
@@ -2209,8 +2391,8 @@ init_publish();
|
|
|
2209
2391
|
init_settings();
|
|
2210
2392
|
init_graph();
|
|
2211
2393
|
init_schema_review();
|
|
2212
|
-
import { join as
|
|
2213
|
-
var SKILL_SNAPSHOT_DIR3 = process.env.UNBROWSE_SKILL_SNAPSHOT_DIR ??
|
|
2394
|
+
import { join as join9 } from "node:path";
|
|
2395
|
+
var SKILL_SNAPSHOT_DIR3 = process.env.UNBROWSE_SKILL_SNAPSHOT_DIR ?? join9(process.env.HOME ?? "/tmp", ".unbrowse", "skill-snapshots");
|
|
2214
2396
|
var indexInFlight2 = new Map;
|
|
2215
2397
|
var pendingIndexJobs2 = new Map;
|
|
2216
2398
|
async function drainPendingIndexJobs() {
|
|
@@ -2247,14 +2429,14 @@ init_paths();
|
|
|
2247
2429
|
init_client2();
|
|
2248
2430
|
init_logger();
|
|
2249
2431
|
init_wallet();
|
|
2250
|
-
import { execFileSync as
|
|
2251
|
-
import { existsSync as
|
|
2432
|
+
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
2433
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync6, writeFileSync as writeFileSync5 } from "node:fs";
|
|
2252
2434
|
import os4 from "node:os";
|
|
2253
2435
|
import path7 from "node:path";
|
|
2254
2436
|
|
|
2255
2437
|
// ../../src/runtime/update-hints.ts
|
|
2256
2438
|
init_paths();
|
|
2257
|
-
import { existsSync as
|
|
2439
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync5, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "node:fs";
|
|
2258
2440
|
import os3 from "node:os";
|
|
2259
2441
|
import path6 from "node:path";
|
|
2260
2442
|
var DEFAULT_INTERVAL_MS = 12 * 60 * 60 * 1000;
|
|
@@ -2268,7 +2450,7 @@ function getConfigDir2() {
|
|
|
2268
2450
|
return path6.join(getHomeDir(), ".unbrowse");
|
|
2269
2451
|
}
|
|
2270
2452
|
function ensureDir2(dir) {
|
|
2271
|
-
if (!
|
|
2453
|
+
if (!existsSync9(dir))
|
|
2272
2454
|
mkdirSync5(dir, { recursive: true });
|
|
2273
2455
|
return dir;
|
|
2274
2456
|
}
|
|
@@ -2291,7 +2473,7 @@ function detectRepoRoot(start2) {
|
|
|
2291
2473
|
let dir = path6.resolve(start2);
|
|
2292
2474
|
const root = path6.parse(dir).root;
|
|
2293
2475
|
while (dir !== root) {
|
|
2294
|
-
if (
|
|
2476
|
+
if (existsSync9(path6.join(dir, ".git")))
|
|
2295
2477
|
return dir;
|
|
2296
2478
|
dir = path6.dirname(dir);
|
|
2297
2479
|
}
|
|
@@ -2370,12 +2552,12 @@ codex_hooks = true
|
|
|
2370
2552
|
}
|
|
2371
2553
|
function writeCodexHook(metaUrl) {
|
|
2372
2554
|
const configPath = getCodexConfigPath();
|
|
2373
|
-
if (!
|
|
2555
|
+
if (!existsSync9(path6.dirname(configPath))) {
|
|
2374
2556
|
return { host: "codex", action: "not-detected", config_file: configPath };
|
|
2375
2557
|
}
|
|
2376
2558
|
try {
|
|
2377
2559
|
const hookScript = getHookScriptPath(metaUrl).replace(/\\/g, "/");
|
|
2378
|
-
const fileExistsBefore =
|
|
2560
|
+
const fileExistsBefore = existsSync9(configPath);
|
|
2379
2561
|
let content = fileExistsBefore ? readFileSync6(configPath, "utf8") : "";
|
|
2380
2562
|
const previous = content;
|
|
2381
2563
|
content = ensureCodexHooksFeature(content);
|
|
@@ -2410,13 +2592,13 @@ command = ${JSON.stringify(command)}
|
|
|
2410
2592
|
}
|
|
2411
2593
|
function writeClaudeHook(metaUrl) {
|
|
2412
2594
|
const settingsPath = getClaudeSettingsPath();
|
|
2413
|
-
if (!
|
|
2595
|
+
if (!existsSync9(path6.dirname(settingsPath))) {
|
|
2414
2596
|
return { host: "claude", action: "not-detected", config_file: settingsPath };
|
|
2415
2597
|
}
|
|
2416
2598
|
try {
|
|
2417
2599
|
const hookScript = getHookScriptPath(metaUrl).replace(/\\/g, "/");
|
|
2418
2600
|
const command = `node "${hookScript}"`;
|
|
2419
|
-
const fileExistsBefore =
|
|
2601
|
+
const fileExistsBefore = existsSync9(settingsPath);
|
|
2420
2602
|
const settings = readJsonFile(settingsPath) ?? {};
|
|
2421
2603
|
settings.hooks ??= {};
|
|
2422
2604
|
settings.hooks.SessionStart ??= [];
|
|
@@ -2454,7 +2636,7 @@ function configureUpdateHintHooks(metaUrl, install) {
|
|
|
2454
2636
|
function hasBinary(name) {
|
|
2455
2637
|
const checker = process.platform === "win32" ? "where" : "which";
|
|
2456
2638
|
try {
|
|
2457
|
-
|
|
2639
|
+
execFileSync3(checker, [name], { stdio: "ignore" });
|
|
2458
2640
|
return true;
|
|
2459
2641
|
} catch {
|
|
2460
2642
|
return false;
|
|
@@ -2481,7 +2663,7 @@ function getOpenCodeProjectCommandsDir(cwd) {
|
|
|
2481
2663
|
return path7.join(cwd, ".opencode", "commands");
|
|
2482
2664
|
}
|
|
2483
2665
|
function detectOpenCode(cwd) {
|
|
2484
|
-
return hasBinary("opencode") ||
|
|
2666
|
+
return hasBinary("opencode") || existsSync10(path7.join(resolveConfigHome(), "opencode")) || existsSync10(path7.join(cwd, ".opencode"));
|
|
2485
2667
|
}
|
|
2486
2668
|
function renderOpenCodeCommand() {
|
|
2487
2669
|
return `---
|
|
@@ -2509,11 +2691,11 @@ function writeOpenCodeCommand(scope, cwd) {
|
|
|
2509
2691
|
if (scope === "auto" && !detected) {
|
|
2510
2692
|
return { detected: false, action: "not-detected", scope: "off" };
|
|
2511
2693
|
}
|
|
2512
|
-
const resolvedScope = scope === "project" ? "project" : scope === "global" ? "global" :
|
|
2694
|
+
const resolvedScope = scope === "project" ? "project" : scope === "global" ? "global" : existsSync10(path7.join(cwd, ".opencode")) ? "project" : "global";
|
|
2513
2695
|
const commandsDir = resolvedScope === "project" ? getOpenCodeProjectCommandsDir(cwd) : getOpenCodeGlobalCommandsDir();
|
|
2514
2696
|
const commandFile = path7.join(ensureDir(commandsDir), "unbrowse.md");
|
|
2515
2697
|
const content = renderOpenCodeCommand();
|
|
2516
|
-
const action2 =
|
|
2698
|
+
const action2 = existsSync10(commandFile) ? "updated" : "installed";
|
|
2517
2699
|
mkdirSync6(path7.dirname(commandFile), { recursive: true });
|
|
2518
2700
|
writeFileSync5(commandFile, content);
|
|
2519
2701
|
return {
|
|
@@ -2525,10 +2707,10 @@ function writeOpenCodeCommand(scope, cwd) {
|
|
|
2525
2707
|
}
|
|
2526
2708
|
async function ensureBrowserEngineInstalled() {
|
|
2527
2709
|
const binary = findKuriBinary();
|
|
2528
|
-
if (
|
|
2710
|
+
if (existsSync10(binary)) {
|
|
2529
2711
|
return { installed: true, action: "already-installed" };
|
|
2530
2712
|
}
|
|
2531
|
-
const sourceDir = getKuriSourceCandidates().find((candidate) =>
|
|
2713
|
+
const sourceDir = getKuriSourceCandidates().find((candidate) => existsSync10(path7.join(candidate, "build.zig")));
|
|
2532
2714
|
if (!sourceDir) {
|
|
2533
2715
|
return {
|
|
2534
2716
|
installed: false,
|
|
@@ -2544,13 +2726,13 @@ async function ensureBrowserEngineInstalled() {
|
|
|
2544
2726
|
};
|
|
2545
2727
|
}
|
|
2546
2728
|
try {
|
|
2547
|
-
|
|
2729
|
+
execFileSync3("zig", ["build", "-Doptimize=ReleaseFast"], {
|
|
2548
2730
|
cwd: sourceDir,
|
|
2549
2731
|
stdio: "inherit",
|
|
2550
2732
|
timeout: 300000
|
|
2551
2733
|
});
|
|
2552
2734
|
const builtBinary = findKuriBinary();
|
|
2553
|
-
if (
|
|
2735
|
+
if (existsSync10(builtBinary)) {
|
|
2554
2736
|
return {
|
|
2555
2737
|
installed: true,
|
|
2556
2738
|
action: "installed",
|
|
@@ -2575,11 +2757,11 @@ async function runSetup(options) {
|
|
|
2575
2757
|
const browser = options?.installBrowser === false ? { installed: false, action: "skipped" } : await ensureBrowserEngineInstalled();
|
|
2576
2758
|
const walletCheck = checkWalletConfigured();
|
|
2577
2759
|
const skipWalletSetup = process.env.UNBROWSE_SKIP_WALLET_SETUP === "1";
|
|
2578
|
-
const lobsterInstalled = hasBinary("lobstercash") ||
|
|
2760
|
+
const lobsterInstalled = hasBinary("lobstercash") || existsSync10(path7.join(os4.homedir(), ".agents", "skills", "lobstercash", "SKILL.md"));
|
|
2579
2761
|
if (!skipWalletSetup && !walletCheck.configured && lobsterInstalled) {
|
|
2580
2762
|
console.log("[unbrowse] Crossmint lobster.cash detected but wallet not configured — running wallet setup...");
|
|
2581
2763
|
try {
|
|
2582
|
-
|
|
2764
|
+
execFileSync3("npx", ["@crossmint/lobster-cli", "setup"], {
|
|
2583
2765
|
stdio: "inherit",
|
|
2584
2766
|
timeout: 60000
|
|
2585
2767
|
});
|
|
@@ -2615,7 +2797,7 @@ async function runSetup(options) {
|
|
|
2615
2797
|
|
|
2616
2798
|
// ../../src/runtime/update-hints.ts
|
|
2617
2799
|
init_paths();
|
|
2618
|
-
import { existsSync as
|
|
2800
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync7, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "node:fs";
|
|
2619
2801
|
import os5 from "node:os";
|
|
2620
2802
|
import path8 from "node:path";
|
|
2621
2803
|
var INSTALL_SCRIPT_URL = "https://unbrowse.ai/install.sh";
|
|
@@ -2629,7 +2811,7 @@ function getConfigDir3() {
|
|
|
2629
2811
|
return path8.join(getHomeDir2(), ".unbrowse");
|
|
2630
2812
|
}
|
|
2631
2813
|
function ensureDir3(dir) {
|
|
2632
|
-
if (!
|
|
2814
|
+
if (!existsSync11(dir))
|
|
2633
2815
|
mkdirSync7(dir, { recursive: true });
|
|
2634
2816
|
return dir;
|
|
2635
2817
|
}
|
|
@@ -2655,7 +2837,7 @@ function detectRepoRoot2(start2) {
|
|
|
2655
2837
|
let dir = path8.resolve(start2);
|
|
2656
2838
|
const root = path8.parse(dir).root;
|
|
2657
2839
|
while (dir !== root) {
|
|
2658
|
-
if (
|
|
2840
|
+
if (existsSync11(path8.join(dir, ".git")))
|
|
2659
2841
|
return dir;
|
|
2660
2842
|
dir = path8.dirname(dir);
|
|
2661
2843
|
}
|
|
@@ -2789,6 +2971,7 @@ loadEnv({ quiet: true });
|
|
|
2789
2971
|
loadEnv({ path: ".env.runtime", quiet: true });
|
|
2790
2972
|
var BASE_URL = process.env.UNBROWSE_URL || "http://localhost:6969";
|
|
2791
2973
|
var CLI_CLIENT_ID = process.env.UNBROWSE_CLIENT_ID || `cli-${process.ppid || process.pid}`;
|
|
2974
|
+
var walletNudgeShown = false;
|
|
2792
2975
|
function parseArgs(argv) {
|
|
2793
2976
|
const raw = argv.slice(2);
|
|
2794
2977
|
const command = raw[0] && !raw[0].startsWith("--") ? raw[0] : "help";
|
|
@@ -3098,6 +3281,16 @@ async function cmdResolve(flags) {
|
|
|
3098
3281
|
emitNextActionSummary(result);
|
|
3099
3282
|
const skill = result.skill;
|
|
3100
3283
|
const trace = result.trace;
|
|
3284
|
+
if (trace?.success && !walletNudgeShown) {
|
|
3285
|
+
try {
|
|
3286
|
+
const { checkWalletConfigured: checkWalletConfigured3 } = await Promise.resolve().then(() => (init_wallet2(), exports_wallet));
|
|
3287
|
+
const wallet = checkWalletConfigured3();
|
|
3288
|
+
if (!wallet.configured) {
|
|
3289
|
+
info("You're indexing routes but have no payout wallet. Run: npx @crossmint/lobster-cli setup");
|
|
3290
|
+
walletNudgeShown = true;
|
|
3291
|
+
}
|
|
3292
|
+
} catch (_e) {}
|
|
3293
|
+
}
|
|
3101
3294
|
if (skill?.skill_id && trace) {
|
|
3102
3295
|
result._feedback = `unbrowse feedback --skill ${skill.skill_id} --endpoint ${trace.endpoint_id || "?"} --rating <1-5>`;
|
|
3103
3296
|
}
|
|
@@ -3481,6 +3674,16 @@ async function cmdSetup(flags) {
|
|
|
3481
3674
|
info(`${hook.host} update hint hook ${hook.action} at ${hook.config_file}`);
|
|
3482
3675
|
}
|
|
3483
3676
|
}
|
|
3677
|
+
if (report.wallet.configured) {
|
|
3678
|
+
info(`Wallet configured (${report.wallet.provider}): ${report.wallet.wallet_address ?? "linked"}`);
|
|
3679
|
+
} else if (report.wallet.lobster_installed) {
|
|
3680
|
+
info("Wallet not paired \u2014 your indexed routes won't earn payouts.");
|
|
3681
|
+
info("Run: npx @crossmint/lobster-cli setup");
|
|
3682
|
+
} else {
|
|
3683
|
+
info("No wallet configured \u2014 you're indexing routes for free.");
|
|
3684
|
+
info("Set up a wallet so you earn when agents use your routes:");
|
|
3685
|
+
info(" npx @crossmint/lobster-cli setup");
|
|
3686
|
+
}
|
|
3484
3687
|
await recordInstallTelemetryEvent("setup", {
|
|
3485
3688
|
hostType,
|
|
3486
3689
|
status: report.browser_engine.action === "failed" ? "failed" : "installed",
|