unbrowse 2.9.0 → 2.10.1
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 +405 -50
- package/package.json +1 -1
- package/runtime-src/analytics-session.ts +33 -0
- package/runtime-src/api/routes.ts +62 -9
- package/runtime-src/auth/index.ts +44 -6
- package/runtime-src/client/index.ts +157 -12
- package/runtime-src/execution/index.ts +2 -1
- package/runtime-src/kuri/client.ts +68 -2
- package/runtime-src/orchestrator/index.ts +71 -19
- package/runtime-src/payments/cascade.ts +137 -0
- package/runtime-src/types/skill.ts +18 -0
package/dist/cli.js
CHANGED
|
@@ -30,6 +30,83 @@ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
|
30
30
|
var __promiseAll = (args) => Promise.all(args);
|
|
31
31
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
32
32
|
|
|
33
|
+
// ../../src/payments/cascade.ts
|
|
34
|
+
import { createHash } from "crypto";
|
|
35
|
+
import bs58 from "bs58";
|
|
36
|
+
function payableContributors(skill) {
|
|
37
|
+
return (skill.contributors ?? []).filter((c) => !!c.wallet_address?.trim());
|
|
38
|
+
}
|
|
39
|
+
function cascadeLabel(skillId) {
|
|
40
|
+
const digest = createHash("sha256").update(skillId).digest("hex");
|
|
41
|
+
return `ubr-${digest.slice(0, 23)}`;
|
|
42
|
+
}
|
|
43
|
+
function decodeSecretKey(raw) {
|
|
44
|
+
const trimmed = raw.trim();
|
|
45
|
+
if (!trimmed)
|
|
46
|
+
throw new Error("empty signer secret");
|
|
47
|
+
if (trimmed.startsWith("[")) {
|
|
48
|
+
return Uint8Array.from(JSON.parse(trimmed));
|
|
49
|
+
}
|
|
50
|
+
if (/^[1-9A-HJ-NP-Za-km-z]+$/.test(trimmed)) {
|
|
51
|
+
return Uint8Array.from(bs58.decode(trimmed));
|
|
52
|
+
}
|
|
53
|
+
return Uint8Array.from(Buffer.from(trimmed, "base64"));
|
|
54
|
+
}
|
|
55
|
+
function recipientsForSkill(skill, platformWallet) {
|
|
56
|
+
return [
|
|
57
|
+
{ address: platformWallet, share: 10 },
|
|
58
|
+
...payableContributors(skill).map((c) => ({
|
|
59
|
+
address: c.wallet_address.trim(),
|
|
60
|
+
share: c.share
|
|
61
|
+
}))
|
|
62
|
+
];
|
|
63
|
+
}
|
|
64
|
+
async function ensureCascadeSplitForSkill(skill, deps = {}) {
|
|
65
|
+
const env = deps.env ?? process.env;
|
|
66
|
+
if (skill.split_config?.trim()) {
|
|
67
|
+
return { split_config: skill.split_config.trim(), source: "existing" };
|
|
68
|
+
}
|
|
69
|
+
const contributors = payableContributors(skill);
|
|
70
|
+
if (contributors.length <= 1)
|
|
71
|
+
return {};
|
|
72
|
+
const explicitSplitConfig = env.UNBROWSE_CASCADE_SPLIT_ADDRESS?.trim() || env.UNBROWSE_CASCADE_SPLIT_CONFIG?.trim();
|
|
73
|
+
if (explicitSplitConfig) {
|
|
74
|
+
return { split_config: explicitSplitConfig, source: "env" };
|
|
75
|
+
}
|
|
76
|
+
const platformWallet = env.UNBROWSE_CASCADE_PLATFORM_WALLET?.trim() || env.PAYMENT_RECIPIENT?.trim();
|
|
77
|
+
const secretKey = env.UNBROWSE_CASCADE_SIGNER_SECRET_KEY?.trim();
|
|
78
|
+
const rpcUrl = env.UNBROWSE_CASCADE_RPC_URL?.trim();
|
|
79
|
+
const rpcWsUrl = env.UNBROWSE_CASCADE_RPC_WS_URL?.trim();
|
|
80
|
+
if (!platformWallet || !secretKey || !rpcUrl || !rpcWsUrl) {
|
|
81
|
+
return {
|
|
82
|
+
warning: "cascade_split_not_configured"
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
const loadSdk = deps.loadSdk ?? (async () => await import("@cascade-fyi/splits-sdk"));
|
|
86
|
+
const loadKit = deps.loadKit ?? (async () => await import("@solana/kit"));
|
|
87
|
+
const [sdk, kit] = await Promise.all([loadSdk(), loadKit()]);
|
|
88
|
+
const signer = await kit.createKeyPairSignerFromBytes(decodeSecretKey(secretKey));
|
|
89
|
+
const splits = sdk.createSplitsClient({
|
|
90
|
+
rpc: kit.createSolanaRpc(rpcUrl),
|
|
91
|
+
rpcSubscriptions: kit.createSolanaRpcSubscriptions(rpcWsUrl),
|
|
92
|
+
signer
|
|
93
|
+
});
|
|
94
|
+
const result = await splits.ensureSplit({
|
|
95
|
+
recipients: recipientsForSkill(skill, platformWallet),
|
|
96
|
+
uniqueId: sdk.labelToSeed(cascadeLabel(skill.skill_id))
|
|
97
|
+
});
|
|
98
|
+
if (result.status === "created" || result.status === "updated" || result.status === "no_change") {
|
|
99
|
+
return {
|
|
100
|
+
split_config: result.splitConfig,
|
|
101
|
+
source: "sdk"
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
warning: result.message || `cascade_split_${result.status}`
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
var init_cascade = () => {};
|
|
109
|
+
|
|
33
110
|
// ../../src/runtime/lifecycle.ts
|
|
34
111
|
function attributeLifecycle(events) {
|
|
35
112
|
const totals = new Map;
|
|
@@ -501,11 +578,75 @@ async function getCookies(tabId) {
|
|
|
501
578
|
const raw = await kuriGet("/cookies", { tab_id: tabId });
|
|
502
579
|
return raw?.result?.cookies ?? [];
|
|
503
580
|
}
|
|
581
|
+
async function setCookieViaCDP(wsUrl, cookie) {
|
|
582
|
+
return new Promise((resolve) => {
|
|
583
|
+
const timer = setTimeout(() => {
|
|
584
|
+
resolve(false);
|
|
585
|
+
}, 3000);
|
|
586
|
+
try {
|
|
587
|
+
const ws = new (__require("ws"))(wsUrl);
|
|
588
|
+
ws.on("open", () => {
|
|
589
|
+
ws.send(JSON.stringify({
|
|
590
|
+
id: 1,
|
|
591
|
+
method: "Network.setCookie",
|
|
592
|
+
params: {
|
|
593
|
+
...cookie,
|
|
594
|
+
url: `https://${cookie.domain.replace(/^\./, "")}/`
|
|
595
|
+
}
|
|
596
|
+
}));
|
|
597
|
+
});
|
|
598
|
+
ws.on("message", (data) => {
|
|
599
|
+
clearTimeout(timer);
|
|
600
|
+
try {
|
|
601
|
+
const msg = JSON.parse(data.toString());
|
|
602
|
+
if (msg.id === 1) {
|
|
603
|
+
ws.close();
|
|
604
|
+
resolve(msg.result?.success ?? false);
|
|
605
|
+
}
|
|
606
|
+
} catch {
|
|
607
|
+
ws.close();
|
|
608
|
+
resolve(false);
|
|
609
|
+
}
|
|
610
|
+
});
|
|
611
|
+
ws.on("error", () => {
|
|
612
|
+
clearTimeout(timer);
|
|
613
|
+
resolve(false);
|
|
614
|
+
});
|
|
615
|
+
} catch {
|
|
616
|
+
clearTimeout(timer);
|
|
617
|
+
resolve(false);
|
|
618
|
+
}
|
|
619
|
+
});
|
|
620
|
+
}
|
|
504
621
|
async function setCookie(tabId, cookie) {
|
|
622
|
+
const value = cookie.value.replace(/^"|"$/g, "");
|
|
623
|
+
if (cookie.secure || cookie.httpOnly) {
|
|
624
|
+
try {
|
|
625
|
+
const res = await fetch("http://127.0.0.1:9222/json", { signal: AbortSignal.timeout(1000) }).catch(() => null);
|
|
626
|
+
if (res?.ok) {
|
|
627
|
+
const pages = await res.json();
|
|
628
|
+
const page = pages.find((p) => p.id === tabId);
|
|
629
|
+
if (page?.webSocketDebuggerUrl) {
|
|
630
|
+
const success = await setCookieViaCDP(page.webSocketDebuggerUrl, {
|
|
631
|
+
name: cookie.name,
|
|
632
|
+
value,
|
|
633
|
+
domain: cookie.domain,
|
|
634
|
+
path: cookie.path || "/",
|
|
635
|
+
secure: cookie.secure ?? false,
|
|
636
|
+
httpOnly: cookie.httpOnly ?? false,
|
|
637
|
+
sameSite: cookie.sameSite || "Lax",
|
|
638
|
+
...cookie.expires && cookie.expires > 0 ? { expires: cookie.expires } : {}
|
|
639
|
+
});
|
|
640
|
+
if (success)
|
|
641
|
+
return;
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
} catch {}
|
|
645
|
+
}
|
|
505
646
|
await kuriGet("/cookies", {
|
|
506
647
|
tab_id: tabId,
|
|
507
648
|
name: cookie.name,
|
|
508
|
-
value
|
|
649
|
+
value,
|
|
509
650
|
domain: cookie.domain,
|
|
510
651
|
...cookie.path ? { path: cookie.path } : {}
|
|
511
652
|
});
|
|
@@ -4581,6 +4722,8 @@ __export(exports_client2, {
|
|
|
4581
4722
|
validateManifest: () => validateManifest,
|
|
4582
4723
|
updateEndpointScore: () => updateEndpointScore,
|
|
4583
4724
|
updateEndpointSchema: () => updateEndpointSchema,
|
|
4725
|
+
syncAgentWallet: () => syncAgentWallet2,
|
|
4726
|
+
setSkillSplitConfig: () => setSkillSplitConfig,
|
|
4584
4727
|
setSkillPrice: () => setSkillPrice,
|
|
4585
4728
|
searchIntentResolve: () => searchIntentResolve,
|
|
4586
4729
|
searchIntentInDomain: () => searchIntentInDomain,
|
|
@@ -4592,10 +4735,12 @@ __export(exports_client2, {
|
|
|
4592
4735
|
recordFeedback: () => recordFeedback,
|
|
4593
4736
|
recordExecution: () => recordExecution,
|
|
4594
4737
|
recordDiagnostics: () => recordDiagnostics,
|
|
4738
|
+
recordAnalyticsSession: () => recordAnalyticsSession,
|
|
4595
4739
|
publishSkill: () => publishSkill,
|
|
4596
4740
|
publishGraphEdges: () => publishGraphEdges,
|
|
4597
4741
|
normalizeAgentEmail: () => normalizeAgentEmail2,
|
|
4598
4742
|
listSkills: () => listSkills,
|
|
4743
|
+
isX402Error: () => isX402Error,
|
|
4599
4744
|
isValidAgentEmail: () => isValidAgentEmail2,
|
|
4600
4745
|
isLocalOnlyMode: () => isLocalOnlyMode,
|
|
4601
4746
|
hashApiKey: () => hashApiKey,
|
|
@@ -4603,7 +4748,7 @@ __export(exports_client2, {
|
|
|
4603
4748
|
getSkillChunk: () => getSkillChunk2,
|
|
4604
4749
|
getSkill: () => getSkill,
|
|
4605
4750
|
getRecentLocalSkill: () => getRecentLocalSkill,
|
|
4606
|
-
getMyProfile: () =>
|
|
4751
|
+
getMyProfile: () => getMyProfile2,
|
|
4607
4752
|
getEndpointSchema: () => getEndpointSchema,
|
|
4608
4753
|
getCreatorEarnings: () => getCreatorEarnings,
|
|
4609
4754
|
getApiKey: () => getApiKey2,
|
|
@@ -4621,7 +4766,7 @@ __export(exports_client2, {
|
|
|
4621
4766
|
import { readFileSync as readFileSync2, writeFileSync as writeFileSync3, existsSync as existsSync4, mkdirSync as mkdirSync4, readdirSync as readdirSync2 } from "fs";
|
|
4622
4767
|
import { join as join3 } from "path";
|
|
4623
4768
|
import { homedir as homedir2, hostname as hostname2 } from "os";
|
|
4624
|
-
import { randomBytes as randomBytes2, createHash as
|
|
4769
|
+
import { randomBytes as randomBytes2, createHash as createHash3 } from "crypto";
|
|
4625
4770
|
import { createInterface as createInterface2 } from "readline";
|
|
4626
4771
|
function decodeBase64Json2(value) {
|
|
4627
4772
|
try {
|
|
@@ -4638,6 +4783,9 @@ function decodeBase64Json2(value) {
|
|
|
4638
4783
|
return;
|
|
4639
4784
|
}
|
|
4640
4785
|
}
|
|
4786
|
+
function isX402Error(err) {
|
|
4787
|
+
return !!err && typeof err === "object" && err.x402 === true;
|
|
4788
|
+
}
|
|
4641
4789
|
function scopedSkillKey(skillId, scopeId) {
|
|
4642
4790
|
return scopeId ? `${scopeId}:${skillId}` : skillId;
|
|
4643
4791
|
}
|
|
@@ -4690,6 +4838,20 @@ function resolveAgentName2(preferredEmail, fallbackName) {
|
|
|
4690
4838
|
const normalized = normalizeAgentEmail2(preferredEmail ?? "");
|
|
4691
4839
|
return isValidAgentEmail2(normalized) ? normalized : fallbackName;
|
|
4692
4840
|
}
|
|
4841
|
+
function getLocalWalletContext2() {
|
|
4842
|
+
const lobsterWallet = process.env.LOBSTER_WALLET_ADDRESS?.trim();
|
|
4843
|
+
if (lobsterWallet) {
|
|
4844
|
+
return { wallet_address: lobsterWallet, wallet_provider: "lobster.cash" };
|
|
4845
|
+
}
|
|
4846
|
+
const genericWallet = process.env.AGENT_WALLET_ADDRESS?.trim();
|
|
4847
|
+
if (genericWallet) {
|
|
4848
|
+
return {
|
|
4849
|
+
wallet_address: genericWallet,
|
|
4850
|
+
wallet_provider: process.env.AGENT_WALLET_PROVIDER?.trim() || undefined
|
|
4851
|
+
};
|
|
4852
|
+
}
|
|
4853
|
+
return {};
|
|
4854
|
+
}
|
|
4693
4855
|
function getApiKey2() {
|
|
4694
4856
|
if (LOCAL_ONLY2)
|
|
4695
4857
|
return "local-only";
|
|
@@ -4705,7 +4867,7 @@ function getApiKey2() {
|
|
|
4705
4867
|
function hashApiKey(key) {
|
|
4706
4868
|
if (!key || key === "local-only")
|
|
4707
4869
|
return "";
|
|
4708
|
-
return
|
|
4870
|
+
return createHash3("sha256").update(key).digest("hex");
|
|
4709
4871
|
}
|
|
4710
4872
|
function getAgentId() {
|
|
4711
4873
|
const config = loadConfig2();
|
|
@@ -4768,7 +4930,7 @@ async function findUsableApiKey2() {
|
|
|
4768
4930
|
}
|
|
4769
4931
|
return null;
|
|
4770
4932
|
}
|
|
4771
|
-
async function
|
|
4933
|
+
async function apiRequest2(method, path4, body, opts) {
|
|
4772
4934
|
const key = opts?.noAuth ? "" : getApiKey2();
|
|
4773
4935
|
const controller = new AbortController;
|
|
4774
4936
|
const timer = setTimeout(() => controller.abort(), opts?.timeoutMs ?? API_TIMEOUT_MS2);
|
|
@@ -4814,6 +4976,10 @@ async function api2(method, path4, body, opts) {
|
|
|
4814
4976
|
const msg = errData.details?.length ? `${errData.error}: ${errData.details.join("; ")}` : errData.error ?? `API HTTP ${res.status}`;
|
|
4815
4977
|
throw new Error(msg);
|
|
4816
4978
|
}
|
|
4979
|
+
return { data, headers: res.headers };
|
|
4980
|
+
}
|
|
4981
|
+
async function api2(method, path4, body, opts) {
|
|
4982
|
+
const { data } = await apiRequest2(method, path4, body, opts);
|
|
4817
4983
|
return data;
|
|
4818
4984
|
}
|
|
4819
4985
|
async function promptTosAcceptance2(summary, tosUrl) {
|
|
@@ -4911,6 +5077,13 @@ async function ensureRegistered2(options) {
|
|
|
4911
5077
|
console.log("[unbrowse] Restored saved registration.");
|
|
4912
5078
|
}
|
|
4913
5079
|
await checkTosStatus2();
|
|
5080
|
+
try {
|
|
5081
|
+
const profile = await getMyProfile2();
|
|
5082
|
+
const wallet = getLocalWalletContext2();
|
|
5083
|
+
if (wallet.wallet_address && profile.wallet_address !== wallet.wallet_address) {
|
|
5084
|
+
await syncAgentWallet2(wallet);
|
|
5085
|
+
}
|
|
5086
|
+
} catch {}
|
|
4914
5087
|
return;
|
|
4915
5088
|
}
|
|
4916
5089
|
let tosInfo;
|
|
@@ -4930,7 +5103,8 @@ async function ensureRegistered2(options) {
|
|
|
4930
5103
|
const name = options?.promptForEmail ? await promptAgentEmail2(fallbackName) : resolveAgentName2(process.env.UNBROWSE_AGENT_EMAIL, fallbackName);
|
|
4931
5104
|
console.log(`Registering as "${name}"...`);
|
|
4932
5105
|
try {
|
|
4933
|
-
const
|
|
5106
|
+
const wallet = getLocalWalletContext2();
|
|
5107
|
+
const { agent_id, api_key } = await api2("POST", "/v1/agents/register", { name, tos_version: tosInfo.version, ...wallet });
|
|
4934
5108
|
process.env.UNBROWSE_API_KEY = api_key;
|
|
4935
5109
|
saveConfig2({
|
|
4936
5110
|
api_key,
|
|
@@ -4938,7 +5112,8 @@ async function ensureRegistered2(options) {
|
|
|
4938
5112
|
agent_name: name,
|
|
4939
5113
|
registered_at: new Date().toISOString(),
|
|
4940
5114
|
tos_accepted_version: tosInfo.version,
|
|
4941
|
-
tos_accepted_at: new Date().toISOString()
|
|
5115
|
+
tos_accepted_at: new Date().toISOString(),
|
|
5116
|
+
...wallet
|
|
4942
5117
|
});
|
|
4943
5118
|
console.log(`Registered as ${name}. API key saved to ~/.unbrowse/config.json`);
|
|
4944
5119
|
} catch (err) {
|
|
@@ -5094,7 +5269,27 @@ async function publishSkill(draft) {
|
|
|
5094
5269
|
}
|
|
5095
5270
|
if (LOCAL_ONLY2)
|
|
5096
5271
|
throw new Error("local-only mode");
|
|
5097
|
-
|
|
5272
|
+
const wallet = getLocalWalletContext2();
|
|
5273
|
+
const published = await api2("POST", "/v1/skills", {
|
|
5274
|
+
...draft,
|
|
5275
|
+
...wallet.wallet_address ? wallet : {}
|
|
5276
|
+
}, { timeoutMs: PUBLISH_TIMEOUT_MS2 });
|
|
5277
|
+
const cascade = await ensureCascadeSplitForSkill(published).catch((err) => ({
|
|
5278
|
+
warning: `cascade_split_failed:${err.message}`
|
|
5279
|
+
}));
|
|
5280
|
+
const warnings = [...published.warnings ?? []];
|
|
5281
|
+
if (cascade.warning)
|
|
5282
|
+
warnings.push(cascade.warning);
|
|
5283
|
+
if (cascade.split_config && cascade.split_config !== published.split_config) {
|
|
5284
|
+
const updated = await api2("PATCH", `/v1/skills/${published.skill_id}`, {
|
|
5285
|
+
split_config: cascade.split_config
|
|
5286
|
+
});
|
|
5287
|
+
return {
|
|
5288
|
+
...updated,
|
|
5289
|
+
warnings
|
|
5290
|
+
};
|
|
5291
|
+
}
|
|
5292
|
+
return { ...published, warnings };
|
|
5098
5293
|
}
|
|
5099
5294
|
async function deprecateSkill(skillId) {
|
|
5100
5295
|
if (LOCAL_ONLY2)
|
|
@@ -5136,16 +5331,29 @@ async function searchIntentResolve(intent, domain, domainK = 5, globalK = 10) {
|
|
|
5136
5331
|
if (LOCAL_ONLY2)
|
|
5137
5332
|
return { domain_results: [], global_results: [], skipped_global: false };
|
|
5138
5333
|
try {
|
|
5139
|
-
|
|
5334
|
+
const { data, headers } = await apiRequest2("POST", "/v1/search/resolve", {
|
|
5140
5335
|
intent,
|
|
5141
5336
|
domain,
|
|
5142
5337
|
domain_k: domainK,
|
|
5143
5338
|
global_k: globalK
|
|
5144
5339
|
});
|
|
5145
|
-
|
|
5340
|
+
const actualCostHeader = headers.get("X-Unbrowse-Cost-Uc");
|
|
5341
|
+
const actualCostUc = actualCostHeader && /^\d+$/.test(actualCostHeader) ? Number(actualCostHeader) : undefined;
|
|
5342
|
+
return actualCostUc != null ? { ...data, actual_cost_uc: actualCostUc } : data;
|
|
5343
|
+
} catch (err) {
|
|
5344
|
+
if (isX402Error(err))
|
|
5345
|
+
throw err;
|
|
5146
5346
|
const [domain_results, global_results] = await Promise.all([
|
|
5147
|
-
domain ? searchIntentInDomain(intent, domain, domainK).catch(() =>
|
|
5148
|
-
|
|
5347
|
+
domain ? searchIntentInDomain(intent, domain, domainK).catch((fallbackErr) => {
|
|
5348
|
+
if (isX402Error(fallbackErr))
|
|
5349
|
+
throw fallbackErr;
|
|
5350
|
+
return [];
|
|
5351
|
+
}) : Promise.resolve([]),
|
|
5352
|
+
searchIntent(intent, globalK).catch((fallbackErr) => {
|
|
5353
|
+
if (isX402Error(fallbackErr))
|
|
5354
|
+
throw fallbackErr;
|
|
5355
|
+
return [];
|
|
5356
|
+
})
|
|
5149
5357
|
]);
|
|
5150
5358
|
return { domain_results, global_results, skipped_global: false };
|
|
5151
5359
|
}
|
|
@@ -5210,6 +5418,11 @@ async function recordOrchestrationPerf(timing) {
|
|
|
5210
5418
|
const phaseTotals = Object.fromEntries(attributeLifecycle(events));
|
|
5211
5419
|
await api2("POST", "/v1/stats/perf", { ...timing, phase_totals_ms: phaseTotals });
|
|
5212
5420
|
}
|
|
5421
|
+
async function recordAnalyticsSession(session) {
|
|
5422
|
+
if (LOCAL_ONLY2)
|
|
5423
|
+
return;
|
|
5424
|
+
await api2("POST", "/v1/analytics/sessions", session);
|
|
5425
|
+
}
|
|
5213
5426
|
async function validateManifest(manifest) {
|
|
5214
5427
|
if (LOCAL_ONLY2)
|
|
5215
5428
|
return { valid: true, hardErrors: [], softWarnings: [] };
|
|
@@ -5264,8 +5477,8 @@ async function verifyMarketplaceDiscovery(skillId, intent, maxWaitMs = 60000) {
|
|
|
5264
5477
|
}
|
|
5265
5478
|
return { found: false, latency_ms: Date.now() - start2 };
|
|
5266
5479
|
}
|
|
5267
|
-
async function registerAgent(name) {
|
|
5268
|
-
return api2("POST", "/v1/agents/register", { name });
|
|
5480
|
+
async function registerAgent(name, wallet = getLocalWalletContext2()) {
|
|
5481
|
+
return api2("POST", "/v1/agents/register", { name, ...wallet });
|
|
5269
5482
|
}
|
|
5270
5483
|
async function getAgent(agentId) {
|
|
5271
5484
|
try {
|
|
@@ -5274,9 +5487,18 @@ async function getAgent(agentId) {
|
|
|
5274
5487
|
return null;
|
|
5275
5488
|
}
|
|
5276
5489
|
}
|
|
5277
|
-
async function
|
|
5490
|
+
async function getMyProfile2() {
|
|
5278
5491
|
return api2("GET", "/v1/agents/me", undefined);
|
|
5279
5492
|
}
|
|
5493
|
+
async function syncAgentWallet2(wallet = getLocalWalletContext2()) {
|
|
5494
|
+
if (!wallet.wallet_address)
|
|
5495
|
+
return;
|
|
5496
|
+
await api2("POST", "/v1/agents/wallet", wallet);
|
|
5497
|
+
const config = loadConfig2();
|
|
5498
|
+
if (!config)
|
|
5499
|
+
return;
|
|
5500
|
+
saveConfig2({ ...config, ...wallet });
|
|
5501
|
+
}
|
|
5280
5502
|
async function getTransactionHistory(agentId) {
|
|
5281
5503
|
return api2("GET", `/v1/transactions/consumer/${agentId}`);
|
|
5282
5504
|
}
|
|
@@ -5286,8 +5508,12 @@ async function getCreatorEarnings(agentId) {
|
|
|
5286
5508
|
async function setSkillPrice(skillId, priceUsd) {
|
|
5287
5509
|
return api2("PATCH", `/v1/skills/${skillId}`, { base_price_usd: priceUsd });
|
|
5288
5510
|
}
|
|
5511
|
+
async function setSkillSplitConfig(skillId, splitConfig) {
|
|
5512
|
+
return api2("PATCH", `/v1/skills/${skillId}`, { split_config: splitConfig });
|
|
5513
|
+
}
|
|
5289
5514
|
var API_URL2, PROFILE_NAME2, recentLocalSkills2, LOCAL_ONLY2, EMAIL_RE2, API_TIMEOUT_MS2, PUBLISH_TIMEOUT_MS2;
|
|
5290
5515
|
var init_client2 = __esm(() => {
|
|
5516
|
+
init_cascade();
|
|
5291
5517
|
API_URL2 = process.env.UNBROWSE_BACKEND_URL || "https://beta-api.unbrowse.ai";
|
|
5292
5518
|
PROFILE_NAME2 = sanitizeProfileName2(process.env.UNBROWSE_PROFILE ?? "");
|
|
5293
5519
|
recentLocalSkills2 = new Map;
|
|
@@ -5371,7 +5597,7 @@ var init_marketplace = __esm(() => {
|
|
|
5371
5597
|
});
|
|
5372
5598
|
|
|
5373
5599
|
// ../../src/version.ts
|
|
5374
|
-
import { createHash as
|
|
5600
|
+
import { createHash as createHash4 } from "crypto";
|
|
5375
5601
|
import { readFileSync as readFileSync3, readdirSync as readdirSync3 } from "fs";
|
|
5376
5602
|
import { dirname, join as join4 } from "path";
|
|
5377
5603
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
@@ -5391,7 +5617,7 @@ function computeCodeHash() {
|
|
|
5391
5617
|
try {
|
|
5392
5618
|
const srcDir = join4(MODULE_DIR, ".");
|
|
5393
5619
|
const files = collectTsFiles(srcDir).sort();
|
|
5394
|
-
const hash =
|
|
5620
|
+
const hash = createHash4("sha256");
|
|
5395
5621
|
for (const file of files) {
|
|
5396
5622
|
hash.update(file.slice(srcDir.length));
|
|
5397
5623
|
hash.update(readFileSync3(file, "utf-8"));
|
|
@@ -5413,7 +5639,7 @@ var init_version = __esm(() => {
|
|
|
5413
5639
|
});
|
|
5414
5640
|
|
|
5415
5641
|
// ../../src/telemetry.ts
|
|
5416
|
-
import { createHash as
|
|
5642
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
5417
5643
|
import { existsSync as existsSync5, mkdirSync as mkdirSync5, writeFileSync as writeFileSync4 } from "node:fs";
|
|
5418
5644
|
import { join as join5 } from "node:path";
|
|
5419
5645
|
function getTraceDir() {
|
|
@@ -5430,7 +5656,7 @@ function safeBindingNames(bindings) {
|
|
|
5430
5656
|
}
|
|
5431
5657
|
function hashResponseBody(result) {
|
|
5432
5658
|
const str = typeof result === "string" ? result : JSON.stringify(result ?? "");
|
|
5433
|
-
return
|
|
5659
|
+
return createHash5("sha256").update(str).digest("hex").slice(0, 32);
|
|
5434
5660
|
}
|
|
5435
5661
|
function classifyFailure(error) {
|
|
5436
5662
|
if (!error)
|
|
@@ -6243,6 +6469,10 @@ function filterExpired(cookies) {
|
|
|
6243
6469
|
});
|
|
6244
6470
|
}
|
|
6245
6471
|
async function getStoredAuth(domain) {
|
|
6472
|
+
const bundle = await getStoredAuthBundle(domain);
|
|
6473
|
+
return bundle?.cookies?.length ? bundle.cookies : null;
|
|
6474
|
+
}
|
|
6475
|
+
async function getStoredAuthBundle(domain) {
|
|
6246
6476
|
const regDomain = getRegistrableDomain(domain);
|
|
6247
6477
|
const keysToTry = [`auth:${regDomain}`];
|
|
6248
6478
|
if (domain !== regDomain)
|
|
@@ -6253,11 +6483,9 @@ async function getStoredAuth(domain) {
|
|
|
6253
6483
|
continue;
|
|
6254
6484
|
try {
|
|
6255
6485
|
const parsed = JSON.parse(stored);
|
|
6256
|
-
const cookies = parsed.cookies;
|
|
6257
|
-
if (!cookies || cookies.length === 0)
|
|
6258
|
-
continue;
|
|
6486
|
+
const cookies = parsed.cookies ?? [];
|
|
6259
6487
|
const valid = filterExpired(cookies);
|
|
6260
|
-
if (valid.length === 0) {
|
|
6488
|
+
if (cookies.length > 0 && valid.length === 0 && Object.keys(parsed.headers ?? {}).length === 0) {
|
|
6261
6489
|
log("auth", `all ${cookies.length} cookies for ${domain} (key: ${key}) are expired — deleting`);
|
|
6262
6490
|
await deleteCredential(key);
|
|
6263
6491
|
continue;
|
|
@@ -6265,7 +6493,12 @@ async function getStoredAuth(domain) {
|
|
|
6265
6493
|
if (valid.length < cookies.length) {
|
|
6266
6494
|
log("auth", `filtered ${cookies.length - valid.length} expired cookies for ${domain}`);
|
|
6267
6495
|
}
|
|
6268
|
-
return
|
|
6496
|
+
return {
|
|
6497
|
+
cookies: valid,
|
|
6498
|
+
headers: parsed.headers ?? {},
|
|
6499
|
+
source_keys: parsed.source_keys ?? [],
|
|
6500
|
+
source_meta: parsed.source_meta ?? null
|
|
6501
|
+
};
|
|
6269
6502
|
} catch {
|
|
6270
6503
|
continue;
|
|
6271
6504
|
}
|
|
@@ -11346,7 +11579,7 @@ async function executeEndpoint(skill, endpoint, params = {}, projection, options
|
|
|
11346
11579
|
} catch {}
|
|
11347
11580
|
}
|
|
11348
11581
|
recordExecution(skill.skill_id, endpoint.endpoint_id, trace, skill).catch(() => {});
|
|
11349
|
-
if (trace.success &&
|
|
11582
|
+
if (trace.success && options?.payment_verified === true && skill.base_price_usd && skill.base_price_usd > 0) {
|
|
11350
11583
|
const consumerConfig = (() => {
|
|
11351
11584
|
try {
|
|
11352
11585
|
return JSON.parse(__require("fs").readFileSync(__require("os").homedir() + "/.unbrowse/config.json", "utf-8"));
|
|
@@ -12656,7 +12889,7 @@ var init_prefetch = __esm(async () => {
|
|
|
12656
12889
|
});
|
|
12657
12890
|
|
|
12658
12891
|
// ../../src/orchestrator/first-pass-action.ts
|
|
12659
|
-
import { createHash as
|
|
12892
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
12660
12893
|
function classifyIntent(intent) {
|
|
12661
12894
|
if (/\b(search|find|discover|look\s+for|browse)\b/i.test(intent))
|
|
12662
12895
|
return "search";
|
|
@@ -12703,7 +12936,7 @@ function filterJsonApiEntries(entries) {
|
|
|
12703
12936
|
function synthesizeSkillFromIntercepted(interceptedEntries, domain, intent) {
|
|
12704
12937
|
if (interceptedEntries.length === 0)
|
|
12705
12938
|
return;
|
|
12706
|
-
const hash =
|
|
12939
|
+
const hash = createHash6("sha1").update(interceptedEntries.map((e) => e.request.url).join("|")).digest("hex").slice(0, 8);
|
|
12707
12940
|
const endpoints = interceptedEntries.map((entry, i) => {
|
|
12708
12941
|
const parsed = new URL(entry.request.url);
|
|
12709
12942
|
return {
|
|
@@ -12927,7 +13160,7 @@ function checkWalletConfigured() {
|
|
|
12927
13160
|
import { nanoid as nanoid7 } from "nanoid";
|
|
12928
13161
|
import { existsSync as existsSync9, writeFileSync as writeFileSync7, readFileSync as readFileSync6, mkdirSync as mkdirSync8, readdirSync as readdirSync5 } from "node:fs";
|
|
12929
13162
|
import { dirname as dirname2, join as join9 } from "node:path";
|
|
12930
|
-
import { createHash as
|
|
13163
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
12931
13164
|
function summarizeSchema(schema, maxDepth = 3) {
|
|
12932
13165
|
function walk(s, depth) {
|
|
12933
13166
|
if (depth <= 0)
|
|
@@ -13042,7 +13275,7 @@ function scopedResolveCacheKeys(scope, key) {
|
|
|
13042
13275
|
return scope === "global" ? [scopedCacheKey("global", key)] : [scopedCacheKey(scope, key), scopedCacheKey("global", key)];
|
|
13043
13276
|
}
|
|
13044
13277
|
function snapshotPathForCacheKey(cacheKey) {
|
|
13045
|
-
const digest =
|
|
13278
|
+
const digest = createHash7("sha1").update(cacheKey).digest("hex");
|
|
13046
13279
|
return join9(SKILL_SNAPSHOT_DIR, `${digest}.json`);
|
|
13047
13280
|
}
|
|
13048
13281
|
function writeSkillSnapshot(cacheKey, skill) {
|
|
@@ -14146,6 +14379,7 @@ async function resolveAndExecute(intent, params = {}, context, projection, optio
|
|
|
14146
14379
|
response_bytes: 0,
|
|
14147
14380
|
time_saved_pct: 0,
|
|
14148
14381
|
tokens_saved_pct: 0,
|
|
14382
|
+
actual_total_ms: 0,
|
|
14149
14383
|
trace_version: TRACE_VERSION
|
|
14150
14384
|
};
|
|
14151
14385
|
const decisionTrace = {
|
|
@@ -14181,6 +14415,7 @@ async function resolveAndExecute(intent, params = {}, context, projection, optio
|
|
|
14181
14415
|
}
|
|
14182
14416
|
function finalize(source, result2, skillId, skill, trace2) {
|
|
14183
14417
|
timing.total_ms = Date.now() - t0;
|
|
14418
|
+
timing.actual_total_ms = timing.total_ms;
|
|
14184
14419
|
timing.source = source;
|
|
14185
14420
|
timing.skill_id = skillId;
|
|
14186
14421
|
const resultStr = typeof result2 === "string" ? result2 : JSON.stringify(result2 ?? "");
|
|
@@ -14189,11 +14424,20 @@ async function resolveAndExecute(intent, params = {}, context, projection, optio
|
|
|
14189
14424
|
const cost = skill?.discovery_cost;
|
|
14190
14425
|
const baselineTokens = cost?.capture_tokens ?? DEFAULT_CAPTURE_TOKENS;
|
|
14191
14426
|
const baselineMs = cost?.capture_ms ?? DEFAULT_CAPTURE_MS;
|
|
14427
|
+
const paidSearchUc = timing.paid_search_uc ?? 0;
|
|
14428
|
+
const paidExecutionUc = timing.paid_execution_uc ?? 0;
|
|
14429
|
+
const totalActualCostUc = paidSearchUc + paidExecutionUc;
|
|
14430
|
+
if (totalActualCostUc > 0)
|
|
14431
|
+
timing.actual_cost_uc = totalActualCostUc;
|
|
14192
14432
|
if (source === "marketplace" || source === "route-cache" || source === "first-pass") {
|
|
14193
14433
|
timing.tokens_saved = Math.max(0, baselineTokens - responseTokens);
|
|
14194
14434
|
timing.tokens_saved_pct = baselineTokens > 0 ? Math.round(timing.tokens_saved / baselineTokens * 100) : 0;
|
|
14195
14435
|
timing.time_saved_pct = baselineMs > 0 ? Math.round(Math.max(0, baselineMs - timing.total_ms) / baselineMs * 100) : 0;
|
|
14196
14436
|
}
|
|
14437
|
+
if (cost?.capture_ms != null) {
|
|
14438
|
+
timing.baseline_total_ms = cost.capture_ms;
|
|
14439
|
+
timing.time_saved_ms = Math.max(0, cost.capture_ms - timing.total_ms);
|
|
14440
|
+
}
|
|
14197
14441
|
if (trace2) {
|
|
14198
14442
|
trace2.tokens_used = responseTokens;
|
|
14199
14443
|
trace2.tokens_saved = timing.tokens_saved;
|
|
@@ -15053,17 +15297,54 @@ async function resolveAndExecute(intent, params = {}, context, projection, optio
|
|
|
15053
15297
|
const MARKETPLACE_TIMEOUT_MS = context?.url ? 5000 : 30000;
|
|
15054
15298
|
if (!forceCapture) {
|
|
15055
15299
|
const ts0 = Date.now();
|
|
15056
|
-
|
|
15057
|
-
|
|
15058
|
-
|
|
15059
|
-
|
|
15060
|
-
resolve
|
|
15061
|
-
|
|
15062
|
-
|
|
15063
|
-
|
|
15064
|
-
|
|
15065
|
-
|
|
15066
|
-
|
|
15300
|
+
let searchResponse;
|
|
15301
|
+
try {
|
|
15302
|
+
searchResponse = await Promise.race([
|
|
15303
|
+
searchIntentResolve(queryIntent, requestedDomain ?? undefined, MARKETPLACE_DOMAIN_SEARCH_K, MARKETPLACE_GLOBAL_SEARCH_K),
|
|
15304
|
+
new Promise((resolve) => setTimeout(() => {
|
|
15305
|
+
console.log(`[marketplace] timeout after ${MARKETPLACE_TIMEOUT_MS}ms — falling through to browser`);
|
|
15306
|
+
resolve({ domain_results: [], global_results: [], skipped_global: true });
|
|
15307
|
+
}, MARKETPLACE_TIMEOUT_MS))
|
|
15308
|
+
]);
|
|
15309
|
+
} catch (err) {
|
|
15310
|
+
if (isX402Error(err)) {
|
|
15311
|
+
const trace2 = {
|
|
15312
|
+
trace_id: nanoid7(),
|
|
15313
|
+
skill_id: "marketplace-search",
|
|
15314
|
+
endpoint_id: "search",
|
|
15315
|
+
started_at: new Date().toISOString(),
|
|
15316
|
+
completed_at: new Date().toISOString(),
|
|
15317
|
+
success: false,
|
|
15318
|
+
status_code: 402,
|
|
15319
|
+
error: "payment_required"
|
|
15320
|
+
};
|
|
15321
|
+
return {
|
|
15322
|
+
result: {
|
|
15323
|
+
error: "payment_required",
|
|
15324
|
+
payment_status: "payment_required",
|
|
15325
|
+
wallet_provider: "lobster.cash",
|
|
15326
|
+
message: "Marketplace search requires payment before shared graph results are returned.",
|
|
15327
|
+
next_step: "Pay the Tier 3 search fee, or re-run with force capture for free local discovery.",
|
|
15328
|
+
indexing_fallback_available: true,
|
|
15329
|
+
tier: "tier3",
|
|
15330
|
+
terms: err.terms
|
|
15331
|
+
},
|
|
15332
|
+
trace: trace2,
|
|
15333
|
+
source: "marketplace",
|
|
15334
|
+
skill: undefined,
|
|
15335
|
+
timing: finalize("marketplace", null, undefined, undefined, trace2)
|
|
15336
|
+
};
|
|
15337
|
+
}
|
|
15338
|
+
searchResponse = {
|
|
15339
|
+
domain_results: [],
|
|
15340
|
+
global_results: [],
|
|
15341
|
+
skipped_global: false
|
|
15342
|
+
};
|
|
15343
|
+
}
|
|
15344
|
+
if (typeof searchResponse.actual_cost_uc === "number" && searchResponse.actual_cost_uc > 0) {
|
|
15345
|
+
timing.paid_search_uc = searchResponse.actual_cost_uc;
|
|
15346
|
+
}
|
|
15347
|
+
const { domain_results: domainResults, global_results: globalResults } = searchResponse;
|
|
15067
15348
|
timing.search_ms = Date.now() - ts0;
|
|
15068
15349
|
console.log(`[marketplace] search: ${domainResults.length} domain + ${globalResults.length} global results (${timing.search_ms}ms)`);
|
|
15069
15350
|
const seen = new Set;
|
|
@@ -16387,11 +16668,29 @@ var init_verification = __esm(() => {
|
|
|
16387
16668
|
var exports_routes = {};
|
|
16388
16669
|
__export(exports_routes, {
|
|
16389
16670
|
registerRoutes: () => registerRoutes,
|
|
16390
|
-
registerBrowseSession: () => registerBrowseSession
|
|
16671
|
+
registerBrowseSession: () => registerBrowseSession,
|
|
16672
|
+
buildAnalyticsSessionPayload: () => buildAnalyticsSessionPayload
|
|
16391
16673
|
});
|
|
16392
16674
|
import { nanoid as nanoid8 } from "nanoid";
|
|
16393
16675
|
import { writeFileSync as writeFileSync8, existsSync as existsSync12, mkdirSync as mkdirSync9 } from "fs";
|
|
16394
16676
|
import { join as join12 } from "path";
|
|
16677
|
+
function buildAnalyticsSessionPayload(result, opts) {
|
|
16678
|
+
const source = result.timing?.source ?? result.source;
|
|
16679
|
+
const apiCalls = result.trace.endpoint_id ? 1 : 0;
|
|
16680
|
+
const cachedSkillCalls = opts.cached_skill_calls ?? (apiCalls > 0 && source !== "live-capture" && source !== "first-pass" ? 1 : 0);
|
|
16681
|
+
const freshIndexCalls = opts.fresh_index_calls ?? (apiCalls > 0 && (source === "live-capture" || source === "first-pass") ? 1 : 0);
|
|
16682
|
+
return {
|
|
16683
|
+
session_id: result.trace.trace_id,
|
|
16684
|
+
started_at: result.trace.started_at,
|
|
16685
|
+
completed_at: result.trace.completed_at,
|
|
16686
|
+
trace_version: result.trace.trace_version ?? TRACE_VERSION,
|
|
16687
|
+
api_calls: apiCalls,
|
|
16688
|
+
discovery_queries: opts.discovery_queries,
|
|
16689
|
+
cached_skill_calls: cachedSkillCalls,
|
|
16690
|
+
fresh_index_calls: freshIndexCalls,
|
|
16691
|
+
browser_mode: opts.browser_mode ?? "unknown"
|
|
16692
|
+
};
|
|
16693
|
+
}
|
|
16395
16694
|
function harEntriesToRawRequests(entries) {
|
|
16396
16695
|
return entries.filter((e) => e.request && e.response).map((e) => ({
|
|
16397
16696
|
url: e.request.url,
|
|
@@ -16493,11 +16792,11 @@ async function fetchStats() {
|
|
|
16493
16792
|
const npmRange = (pkg) => fetch(`https://api.npmjs.org/downloads/range/last-month/${pkg}`).then((r) => r.json());
|
|
16494
16793
|
const externalCalls = [
|
|
16495
16794
|
npmPoint("unbrowse", "last-month"),
|
|
16496
|
-
npmPoint("
|
|
16795
|
+
npmPoint("unbrowse-openclaw", "last-month"),
|
|
16497
16796
|
npmPoint("unbrowse", "1970-01-01:2099-12-31"),
|
|
16498
|
-
npmPoint("
|
|
16797
|
+
npmPoint("unbrowse-openclaw", "1970-01-01:2099-12-31"),
|
|
16499
16798
|
npmRange("unbrowse"),
|
|
16500
|
-
npmRange("
|
|
16799
|
+
npmRange("unbrowse-openclaw"),
|
|
16501
16800
|
fetch("https://api.github.com/repos/anthropic-ai/unbrowse", {
|
|
16502
16801
|
headers: { "User-Agent": "unbrowse-stats" }
|
|
16503
16802
|
}).then((r) => r.json())
|
|
@@ -16606,6 +16905,10 @@ async function registerRoutes(app) {
|
|
|
16606
16905
|
if (innerResult?.available_endpoints && !res.available_endpoints) {
|
|
16607
16906
|
res.available_endpoints = innerResult.available_endpoints;
|
|
16608
16907
|
}
|
|
16908
|
+
await recordAnalyticsSession(buildAnalyticsSessionPayload(result, {
|
|
16909
|
+
browser_mode: "replaced",
|
|
16910
|
+
discovery_queries: 1
|
|
16911
|
+
})).catch(() => {});
|
|
16609
16912
|
return reply.send(result);
|
|
16610
16913
|
} catch (err) {
|
|
16611
16914
|
return reply.code(500).send({ error: err.message });
|
|
@@ -16815,6 +17118,10 @@ async function registerRoutes(app) {
|
|
|
16815
17118
|
if (freshResult.trace?.skill_id && freshResult.trace?.endpoint_id) {
|
|
16816
17119
|
recordExecution(freshResult.trace.skill_id, freshResult.trace.endpoint_id, freshResult.trace, skill).catch(() => {});
|
|
16817
17120
|
}
|
|
17121
|
+
await recordAnalyticsSession(buildAnalyticsSessionPayload(freshResult, {
|
|
17122
|
+
browser_mode: "manual",
|
|
17123
|
+
discovery_queries: 1
|
|
17124
|
+
})).catch(() => {});
|
|
16818
17125
|
return reply.send({
|
|
16819
17126
|
...freshResult,
|
|
16820
17127
|
_recovery: {
|
|
@@ -16825,6 +17132,12 @@ async function registerRoutes(app) {
|
|
|
16825
17132
|
});
|
|
16826
17133
|
} catch {}
|
|
16827
17134
|
}
|
|
17135
|
+
await recordAnalyticsSession(buildAnalyticsSessionPayload(execResult, {
|
|
17136
|
+
browser_mode: "manual",
|
|
17137
|
+
discovery_queries: 0,
|
|
17138
|
+
cached_skill_calls: execResult.trace.endpoint_id ? 1 : 0,
|
|
17139
|
+
fresh_index_calls: 0
|
|
17140
|
+
})).catch(() => {});
|
|
16828
17141
|
return reply.send(execResult);
|
|
16829
17142
|
} catch (err) {
|
|
16830
17143
|
return reply.code(500).send({ error: err.message });
|
|
@@ -16995,6 +17308,7 @@ async function registerRoutes(app) {
|
|
|
16995
17308
|
if (session.domain && session.domain !== newDomain) {
|
|
16996
17309
|
await authProfileSave(session.tabId, session.domain).catch(() => {});
|
|
16997
17310
|
}
|
|
17311
|
+
let cookiesInjected = 0;
|
|
16998
17312
|
if (newDomain && newDomain !== session.domain) {
|
|
16999
17313
|
await authProfileLoad(session.tabId, newDomain).catch(() => {});
|
|
17000
17314
|
try {
|
|
@@ -17003,6 +17317,7 @@ async function registerRoutes(app) {
|
|
|
17003
17317
|
for (const c of browserCookies) {
|
|
17004
17318
|
await setCookie(session.tabId, c).catch(() => {});
|
|
17005
17319
|
}
|
|
17320
|
+
cookiesInjected = browserCookies.length;
|
|
17006
17321
|
}
|
|
17007
17322
|
} catch {}
|
|
17008
17323
|
}
|
|
@@ -17015,7 +17330,7 @@ async function registerRoutes(app) {
|
|
|
17015
17330
|
session.url = typeof finalUrl === "string" && finalUrl.startsWith("http") ? finalUrl : url;
|
|
17016
17331
|
session.domain = profileName(session.url);
|
|
17017
17332
|
await injectInterceptor(session.tabId);
|
|
17018
|
-
return reply.send({ ok: true, url: session.url, tab_id: session.tabId, auth_profile: session.domain });
|
|
17333
|
+
return reply.send({ ok: true, url: session.url, tab_id: session.tabId, auth_profile: session.domain, ...cookiesInjected > 0 ? { cookies_injected: cookiesInjected } : {} });
|
|
17019
17334
|
});
|
|
17020
17335
|
app.post("/v1/browse/snap", async (req, reply) => {
|
|
17021
17336
|
const { filter } = req.body ?? {};
|
|
@@ -17329,10 +17644,10 @@ var init_routes = __esm(async () => {
|
|
|
17329
17644
|
init_session_logs();
|
|
17330
17645
|
await __promiseAll([
|
|
17331
17646
|
init_indexer(),
|
|
17647
|
+
init_vault(),
|
|
17332
17648
|
init_orchestrator(),
|
|
17333
17649
|
init_orchestrator(),
|
|
17334
17650
|
init_execution(),
|
|
17335
|
-
init_vault(),
|
|
17336
17651
|
init_auth(),
|
|
17337
17652
|
init_indexer()
|
|
17338
17653
|
]);
|
|
@@ -17417,10 +17732,11 @@ var init_server = __esm(async () => {
|
|
|
17417
17732
|
import { config as loadEnv } from "dotenv";
|
|
17418
17733
|
|
|
17419
17734
|
// ../../src/client/index.ts
|
|
17735
|
+
init_cascade();
|
|
17420
17736
|
import { readFileSync, writeFileSync, existsSync, mkdirSync, readdirSync } from "fs";
|
|
17421
17737
|
import { join } from "path";
|
|
17422
17738
|
import { homedir, hostname } from "os";
|
|
17423
|
-
import { randomBytes, createHash } from "crypto";
|
|
17739
|
+
import { randomBytes, createHash as createHash2 } from "crypto";
|
|
17424
17740
|
import { createInterface } from "readline";
|
|
17425
17741
|
var API_URL = process.env.UNBROWSE_BACKEND_URL || "https://beta-api.unbrowse.ai";
|
|
17426
17742
|
var PROFILE_NAME = sanitizeProfileName(process.env.UNBROWSE_PROFILE ?? "");
|
|
@@ -17482,6 +17798,20 @@ function resolveAgentName(preferredEmail, fallbackName) {
|
|
|
17482
17798
|
const normalized = normalizeAgentEmail(preferredEmail ?? "");
|
|
17483
17799
|
return isValidAgentEmail(normalized) ? normalized : fallbackName;
|
|
17484
17800
|
}
|
|
17801
|
+
function getLocalWalletContext() {
|
|
17802
|
+
const lobsterWallet = process.env.LOBSTER_WALLET_ADDRESS?.trim();
|
|
17803
|
+
if (lobsterWallet) {
|
|
17804
|
+
return { wallet_address: lobsterWallet, wallet_provider: "lobster.cash" };
|
|
17805
|
+
}
|
|
17806
|
+
const genericWallet = process.env.AGENT_WALLET_ADDRESS?.trim();
|
|
17807
|
+
if (genericWallet) {
|
|
17808
|
+
return {
|
|
17809
|
+
wallet_address: genericWallet,
|
|
17810
|
+
wallet_provider: process.env.AGENT_WALLET_PROVIDER?.trim() || undefined
|
|
17811
|
+
};
|
|
17812
|
+
}
|
|
17813
|
+
return {};
|
|
17814
|
+
}
|
|
17485
17815
|
function getApiKey() {
|
|
17486
17816
|
if (LOCAL_ONLY)
|
|
17487
17817
|
return "local-only";
|
|
@@ -17553,7 +17883,7 @@ async function findUsableApiKey() {
|
|
|
17553
17883
|
}
|
|
17554
17884
|
return null;
|
|
17555
17885
|
}
|
|
17556
|
-
async function
|
|
17886
|
+
async function apiRequest(method, path, body, opts) {
|
|
17557
17887
|
const key = opts?.noAuth ? "" : getApiKey();
|
|
17558
17888
|
const controller = new AbortController;
|
|
17559
17889
|
const timer = setTimeout(() => controller.abort(), opts?.timeoutMs ?? API_TIMEOUT_MS);
|
|
@@ -17599,6 +17929,10 @@ async function api(method, path, body, opts) {
|
|
|
17599
17929
|
const msg = errData.details?.length ? `${errData.error}: ${errData.details.join("; ")}` : errData.error ?? `API HTTP ${res.status}`;
|
|
17600
17930
|
throw new Error(msg);
|
|
17601
17931
|
}
|
|
17932
|
+
return { data, headers: res.headers };
|
|
17933
|
+
}
|
|
17934
|
+
async function api(method, path, body, opts) {
|
|
17935
|
+
const { data } = await apiRequest(method, path, body, opts);
|
|
17602
17936
|
return data;
|
|
17603
17937
|
}
|
|
17604
17938
|
async function promptTosAcceptance(summary, tosUrl) {
|
|
@@ -17696,6 +18030,13 @@ async function ensureRegistered(options) {
|
|
|
17696
18030
|
console.log("[unbrowse] Restored saved registration.");
|
|
17697
18031
|
}
|
|
17698
18032
|
await checkTosStatus();
|
|
18033
|
+
try {
|
|
18034
|
+
const profile = await getMyProfile();
|
|
18035
|
+
const wallet = getLocalWalletContext();
|
|
18036
|
+
if (wallet.wallet_address && profile.wallet_address !== wallet.wallet_address) {
|
|
18037
|
+
await syncAgentWallet(wallet);
|
|
18038
|
+
}
|
|
18039
|
+
} catch {}
|
|
17699
18040
|
return;
|
|
17700
18041
|
}
|
|
17701
18042
|
let tosInfo;
|
|
@@ -17715,7 +18056,8 @@ async function ensureRegistered(options) {
|
|
|
17715
18056
|
const name = options?.promptForEmail ? await promptAgentEmail(fallbackName) : resolveAgentName(process.env.UNBROWSE_AGENT_EMAIL, fallbackName);
|
|
17716
18057
|
console.log(`Registering as "${name}"...`);
|
|
17717
18058
|
try {
|
|
17718
|
-
const
|
|
18059
|
+
const wallet = getLocalWalletContext();
|
|
18060
|
+
const { agent_id, api_key } = await api("POST", "/v1/agents/register", { name, tos_version: tosInfo.version, ...wallet });
|
|
17719
18061
|
process.env.UNBROWSE_API_KEY = api_key;
|
|
17720
18062
|
saveConfig({
|
|
17721
18063
|
api_key,
|
|
@@ -17723,7 +18065,8 @@ async function ensureRegistered(options) {
|
|
|
17723
18065
|
agent_name: name,
|
|
17724
18066
|
registered_at: new Date().toISOString(),
|
|
17725
18067
|
tos_accepted_version: tosInfo.version,
|
|
17726
|
-
tos_accepted_at: new Date().toISOString()
|
|
18068
|
+
tos_accepted_at: new Date().toISOString(),
|
|
18069
|
+
...wallet
|
|
17727
18070
|
});
|
|
17728
18071
|
console.log(`Registered as ${name}. API key saved to ~/.unbrowse/config.json`);
|
|
17729
18072
|
} catch (err) {
|
|
@@ -17732,6 +18075,18 @@ async function ensureRegistered(options) {
|
|
|
17732
18075
|
process.exit(1);
|
|
17733
18076
|
}
|
|
17734
18077
|
}
|
|
18078
|
+
async function getMyProfile() {
|
|
18079
|
+
return api("GET", "/v1/agents/me", undefined);
|
|
18080
|
+
}
|
|
18081
|
+
async function syncAgentWallet(wallet = getLocalWalletContext()) {
|
|
18082
|
+
if (!wallet.wallet_address)
|
|
18083
|
+
return;
|
|
18084
|
+
await api("POST", "/v1/agents/wallet", wallet);
|
|
18085
|
+
const config = loadConfig();
|
|
18086
|
+
if (!config)
|
|
18087
|
+
return;
|
|
18088
|
+
saveConfig({ ...config, ...wallet });
|
|
18089
|
+
}
|
|
17735
18090
|
|
|
17736
18091
|
// ../../src/cli/shortcuts.ts
|
|
17737
18092
|
var linkedin = {
|