@bolloon/bolloon-agent 0.4.23 → 0.4.24
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/ios/index.html +74 -17
- package/dist/ios/mobile-agent.js +49 -4
- package/dist/ios/mobile-chain.js +481 -0
- package/dist/ios/mobile-core.js +373 -13
- package/dist/ios/mobile-helia.js +683 -0
- package/dist/ios/mobile-ipfs.js +680 -0
- package/dist/ios/mobile-orbit.js +268 -0
- package/dist/ios/mobile-p2p.js +130 -1
- package/dist/ios/mobile-social.js +624 -0
- package/dist/ios/mobile-sync.js +193 -0
- package/dist/ios/mobile-trade.js +492 -0
- package/dist/ios/mobile-wallet.js +11 -0
- package/dist/ios/mobile.css +24 -0
- package/dist/ios/mobile.html +74 -17
- package/dist/ios/mobile.js +911 -55
- package/dist/ios/routes-x402-info.js +194 -0
- package/dist/ios/server.js +303 -9
- package/dist/ios/sw.js +26 -2
- package/dist/web/agent-delegate-server.js +58 -12
- package/dist/web/mobile-agent.js +195 -1
- package/dist/web/mobile-core.js +170 -1
- package/dist/web/server.js +51 -4
- package/package.json +1 -1
package/dist/ios/mobile-core.js
CHANGED
|
@@ -86151,11 +86151,16 @@ ${[...listenStats.errors.entries()].map(([addr, err2]) => {
|
|
|
86151
86151
|
// src/web/mobile-p2p.ts
|
|
86152
86152
|
var mobile_p2p_exports = {};
|
|
86153
86153
|
__export(mobile_p2p_exports, {
|
|
86154
|
+
RELAY_HOP_PROTOCOL: () => RELAY_HOP_PROTOCOL,
|
|
86154
86155
|
addMobilePeer: () => addMobilePeer,
|
|
86156
|
+
getMobileCircuitAddrs: () => getMobileCircuitAddrs,
|
|
86155
86157
|
getMobileP2PConnections: () => getMobileP2PConnections,
|
|
86156
86158
|
getMobileP2PState: () => getMobileP2PState,
|
|
86159
|
+
getMobileRelayReservations: () => getMobileRelayReservations,
|
|
86160
|
+
getMobileRelays: () => getMobileRelays,
|
|
86157
86161
|
listMobilePeerAddrs: () => listMobilePeerAddrs,
|
|
86158
86162
|
onMobileP2PMessage: () => onMobileP2PMessage,
|
|
86163
|
+
reserveMobileRelay: () => reserveMobileRelay,
|
|
86159
86164
|
sendMobileP2PMessage: () => sendMobileP2PMessage,
|
|
86160
86165
|
startMobileP2P: () => startMobileP2P
|
|
86161
86166
|
});
|
|
@@ -86175,7 +86180,13 @@ ${[...listenStats.errors.entries()].map(([addr, err2]) => {
|
|
|
86175
86180
|
async function startMobileP2P(cfg = {}) {
|
|
86176
86181
|
if (node) return state;
|
|
86177
86182
|
try {
|
|
86183
|
+
const relayListen = (cfg.relayAddrs || []).map((a) => (a || "").trim().replace(/\/p2p-circuit\/?$/, "")).filter((a) => /\/p2p\/[^/]+$/.test(a)).map((a) => `${a}/p2p-circuit`);
|
|
86178
86184
|
node = await createLibp2p({
|
|
86185
|
+
// 2026-09-11: 手机唯一的「可被拨入」途径 = 向中继预约。
|
|
86186
|
+
// listen /p2p-circuit 会在传输层 reserveRelay() 一个待预约名额; 之后只要连上
|
|
86187
|
+
// 一个广播了 hop 协议的中继, 就会自动预约并拿到 <relay>/p2p-circuit/p2p/<本机>。
|
|
86188
|
+
// (WebView 不能 listen ip4/ip6 → 只有这一类 listen 项是有意义的。)
|
|
86189
|
+
addresses: { listen: ["/p2p-circuit", ...relayListen] },
|
|
86179
86190
|
transports: [webSockets(), circuitRelayTransport()],
|
|
86180
86191
|
connectionEncrypters: [noise()],
|
|
86181
86192
|
streamMuxers: [yamux()],
|
|
@@ -86232,6 +86243,16 @@ ${[...listenStats.errors.entries()].map(([addr, err2]) => {
|
|
|
86232
86243
|
console.warn(`[mobile-p2p] failed to dial saved ${addr}:`, String(e).slice(0, 100));
|
|
86233
86244
|
}
|
|
86234
86245
|
}
|
|
86246
|
+
for (const addr of cfg.relayAddrs || []) {
|
|
86247
|
+
if (getMobileCircuitAddrs().length > 0) break;
|
|
86248
|
+
const r = await reserveMobileRelay(addr);
|
|
86249
|
+
console.log(
|
|
86250
|
+
`[mobile-p2p] relay reserve ${addr} \u2192 ok=${r.ok} circuitAddrs=${r.circuitAddrs.length}` + (r.error ? ` err=${String(r.error).slice(0, 140)}` : "")
|
|
86251
|
+
);
|
|
86252
|
+
}
|
|
86253
|
+
if (getMobileCircuitAddrs().length > 0) {
|
|
86254
|
+
console.log(`[mobile-p2p] \u53EF\u62E8\u5165\u5730\u5740: ${getMobileCircuitAddrs().join(" , ")}`);
|
|
86255
|
+
}
|
|
86235
86256
|
refreshState();
|
|
86236
86257
|
return state;
|
|
86237
86258
|
} catch (e) {
|
|
@@ -86317,6 +86338,58 @@ ${[...listenStats.errors.entries()].map(([addr, err2]) => {
|
|
|
86317
86338
|
function listMobilePeerAddrs() {
|
|
86318
86339
|
return [...peerAddrs];
|
|
86319
86340
|
}
|
|
86341
|
+
function getMobileCircuitAddrs() {
|
|
86342
|
+
if (!node) return [];
|
|
86343
|
+
try {
|
|
86344
|
+
return (node.getMultiaddrs() || []).map((a) => typeof a?.toString === "function" ? a.toString() : String(a)).filter((a) => a.includes("/p2p-circuit")).sort((a, b) => wsFirstRank(a) - wsFirstRank(b));
|
|
86345
|
+
} catch {
|
|
86346
|
+
return [];
|
|
86347
|
+
}
|
|
86348
|
+
}
|
|
86349
|
+
function getMobileRelays() {
|
|
86350
|
+
const out = [];
|
|
86351
|
+
for (const a of getMobileCircuitAddrs()) {
|
|
86352
|
+
const head = a.split("/p2p-circuit")[0] || "";
|
|
86353
|
+
const ids = head.match(/\/p2p\/([^/]+)/g) || [];
|
|
86354
|
+
const last = ids[ids.length - 1];
|
|
86355
|
+
const relay = last ? last.slice("/p2p/".length) : "";
|
|
86356
|
+
if (relay && !out.includes(relay)) out.push(relay);
|
|
86357
|
+
}
|
|
86358
|
+
return out;
|
|
86359
|
+
}
|
|
86360
|
+
function getMobileRelayReservations() {
|
|
86361
|
+
return relayReservationResults.map((r) => ({ ...r }));
|
|
86362
|
+
}
|
|
86363
|
+
async function reserveMobileRelay(relayAddr) {
|
|
86364
|
+
const raw = (relayAddr || "").trim();
|
|
86365
|
+
if (!node) return { ok: false, circuitAddrs: [], error: "P2P \u8282\u70B9\u672A\u542F\u52A8" };
|
|
86366
|
+
if (!raw) return { ok: false, circuitAddrs: [], error: "\u4E2D\u7EE7\u5730\u5740\u4E3A\u7A7A" };
|
|
86367
|
+
const base6 = raw.replace(/\/p2p-circuit\/?$/, "");
|
|
86368
|
+
if (!/\/p2p\/[^/]+$/.test(base6)) {
|
|
86369
|
+
const err2 = "\u4E2D\u7EE7\u5730\u5740\u5FC5\u987B\u5E26 /p2p/<\u4E2D\u7EE7PeerId> (\u6CA1\u6709 PeerId \u65E0\u6CD5\u9884\u7EA6)";
|
|
86370
|
+
relayReservationResults.push({ addr: raw, ok: false, error: err2 });
|
|
86371
|
+
return { ok: false, circuitAddrs: [], error: err2 };
|
|
86372
|
+
}
|
|
86373
|
+
try {
|
|
86374
|
+
const listenAddr = multiaddr(`${base6}/p2p-circuit`);
|
|
86375
|
+
if (typeof node.listen === "function") {
|
|
86376
|
+
await node.listen(listenAddr);
|
|
86377
|
+
} else if (node.components?.transportManager?.listen) {
|
|
86378
|
+
await node.components.transportManager.listen([listenAddr]);
|
|
86379
|
+
} else {
|
|
86380
|
+
throw new Error("\u672C\u7248\u672C libp2p \u65E2\u65E0 node.listen() \u4E5F\u65E0 components.transportManager.listen() \u2014\u2014 \u4E2D\u7EE7\u5730\u5740\u5FC5\u987B\u5728 createLibp2p \u7684 addresses.listen \u91CC\u7ED9");
|
|
86381
|
+
}
|
|
86382
|
+
const circuitAddrs = getMobileCircuitAddrs();
|
|
86383
|
+
const relay = getMobileRelays().slice(-1)[0];
|
|
86384
|
+
relayReservationResults.push({ addr: raw, ok: circuitAddrs.length > 0, relay, error: circuitAddrs.length ? void 0 : "\u9884\u7EA6\u8FD4\u56DE\u4F46\u672A\u62FF\u5230 /p2p-circuit \u5730\u5740" });
|
|
86385
|
+
return { ok: circuitAddrs.length > 0, circuitAddrs };
|
|
86386
|
+
} catch (e) {
|
|
86387
|
+
const err2 = String(e?.message || e).slice(0, 240);
|
|
86388
|
+
relayReservationResults.push({ addr: raw, ok: false, error: err2 });
|
|
86389
|
+
console.warn("[mobile-p2p] relay reservation failed:", err2);
|
|
86390
|
+
return { ok: false, circuitAddrs: getMobileCircuitAddrs(), error: err2 };
|
|
86391
|
+
}
|
|
86392
|
+
}
|
|
86320
86393
|
async function addMobilePeer(addr) {
|
|
86321
86394
|
const normalized = (addr || "").trim();
|
|
86322
86395
|
if (!normalized) return { ok: false, error: "\u5730\u5740\u4E0D\u80FD\u4E3A\u7A7A" };
|
|
@@ -86340,7 +86413,7 @@ ${[...listenStats.errors.entries()].map(([addr, err2]) => {
|
|
|
86340
86413
|
return { ok: false, error: "\u8FDE\u63A5\u5931\u8D25: " + String(e?.message || e).slice(0, 120) };
|
|
86341
86414
|
}
|
|
86342
86415
|
}
|
|
86343
|
-
var node, state, msgHandlers, peerAddrs;
|
|
86416
|
+
var RELAY_HOP_PROTOCOL, node, state, msgHandlers, relayReservationResults, peerAddrs, wsFirstRank;
|
|
86344
86417
|
var init_mobile_p2p = __esm({
|
|
86345
86418
|
"src/web/mobile-p2p.ts"() {
|
|
86346
86419
|
"use strict";
|
|
@@ -86354,13 +86427,24 @@ ${[...listenStats.errors.entries()].map(([addr, err2]) => {
|
|
|
86354
86427
|
init_src72();
|
|
86355
86428
|
init_src74();
|
|
86356
86429
|
init_src14();
|
|
86430
|
+
RELAY_HOP_PROTOCOL = "/libp2p/circuit/relay/0.2.0/hop";
|
|
86357
86431
|
node = null;
|
|
86358
86432
|
state = { connected: false, peerCount: 0, peerIds: [] };
|
|
86359
86433
|
msgHandlers = [];
|
|
86434
|
+
relayReservationResults = [];
|
|
86360
86435
|
peerAddrs = [];
|
|
86361
86436
|
loadPeerAddrs();
|
|
86437
|
+
wsFirstRank = (a) => {
|
|
86438
|
+
const parts = a.split("/");
|
|
86439
|
+
return parts.includes("ws") || parts.includes("wss") ? 0 : 1;
|
|
86440
|
+
};
|
|
86362
86441
|
if (typeof globalThis !== "undefined") {
|
|
86363
|
-
globalThis.__mobileP2PStateSync = () => ({
|
|
86442
|
+
globalThis.__mobileP2PStateSync = () => ({
|
|
86443
|
+
...state,
|
|
86444
|
+
circuitAddrs: getMobileCircuitAddrs(),
|
|
86445
|
+
relays: getMobileRelays(),
|
|
86446
|
+
relayReservations: getMobileRelayReservations()
|
|
86447
|
+
});
|
|
86364
86448
|
}
|
|
86365
86449
|
}
|
|
86366
86450
|
});
|
|
@@ -86571,15 +86655,20 @@ ${[...listenStats.errors.entries()].map(([addr, err2]) => {
|
|
|
86571
86655
|
// src/web/mobile-agent.ts
|
|
86572
86656
|
var mobile_agent_exports = {};
|
|
86573
86657
|
__export(mobile_agent_exports, {
|
|
86658
|
+
MOBILE_JOIN_DOC_RE: () => MOBILE_JOIN_DOC_RE,
|
|
86574
86659
|
callRemoteAgent: () => callRemoteAgent,
|
|
86575
86660
|
cancelPhoneAgent: () => cancelPhoneAgent,
|
|
86576
86661
|
default: () => mobile_agent_default,
|
|
86662
|
+
detectJoinDocUrl: () => detectJoinDocUrl,
|
|
86577
86663
|
ensureIdentity: () => ensureIdentity,
|
|
86664
|
+
formatMobileJoinResult: () => formatMobileJoinResult,
|
|
86578
86665
|
getLastWorklog: () => getLastWorklog,
|
|
86579
86666
|
getLlmConfig: () => getLlmConfig,
|
|
86667
|
+
getMobileJoinState: () => getMobileJoinState,
|
|
86580
86668
|
handleIncomingAgentMessage: () => handleIncomingAgentMessage,
|
|
86581
86669
|
handleIncomingPhoneMessage: () => handleIncomingPhoneMessage,
|
|
86582
86670
|
identityStatus: () => identityStatus,
|
|
86671
|
+
joinGatewayFromDoc: () => joinGatewayFromDoc,
|
|
86583
86672
|
loginIdentity: () => loginIdentity,
|
|
86584
86673
|
logoutIdentity: () => logoutIdentity,
|
|
86585
86674
|
notifyAgentReply: () => notifyAgentReply,
|
|
@@ -86726,9 +86815,171 @@ ${[...listenStats.errors.entries()].map(([addr, err2]) => {
|
|
|
86726
86815
|
} catch {
|
|
86727
86816
|
}
|
|
86728
86817
|
}
|
|
86818
|
+
function detectJoinDocUrl(text) {
|
|
86819
|
+
const m2 = MOBILE_JOIN_DOC_RE.exec(String(text || ""));
|
|
86820
|
+
return m2 ? m2[1] : null;
|
|
86821
|
+
}
|
|
86822
|
+
function parseFm(text) {
|
|
86823
|
+
const m2 = /^---\r?\n([\s\S]*?)\r?\n---/.exec(String(text || ""));
|
|
86824
|
+
if (!m2) return {};
|
|
86825
|
+
const out = {};
|
|
86826
|
+
for (const line of m2[1].split(/\r?\n/)) {
|
|
86827
|
+
const kv = /^([A-Za-z_][\w-]*)\s*:\s*(.*)$/.exec(line.trim());
|
|
86828
|
+
if (!kv) continue;
|
|
86829
|
+
const k = kv[1].toLowerCase();
|
|
86830
|
+
if (k === "name") out.name = kv[2].trim().replace(/^["']|["']$/g, "");
|
|
86831
|
+
if (k === "version") out.version = kv[2].trim().replace(/^["']|["']$/g, "");
|
|
86832
|
+
}
|
|
86833
|
+
return out;
|
|
86834
|
+
}
|
|
86835
|
+
async function getMobileJoinState() {
|
|
86836
|
+
try {
|
|
86837
|
+
const raw = typeof localStorage !== "undefined" ? localStorage.getItem(MOBILE_JOIN_STATE_KEY) : null;
|
|
86838
|
+
return raw ? JSON.parse(raw) : null;
|
|
86839
|
+
} catch {
|
|
86840
|
+
return null;
|
|
86841
|
+
}
|
|
86842
|
+
}
|
|
86843
|
+
function saveMobileJoinState(s2) {
|
|
86844
|
+
try {
|
|
86845
|
+
if (typeof localStorage !== "undefined") localStorage.setItem(MOBILE_JOIN_STATE_KEY, JSON.stringify(s2));
|
|
86846
|
+
} catch {
|
|
86847
|
+
}
|
|
86848
|
+
}
|
|
86849
|
+
async function joinGatewayFromDoc(docUrl, opts = {}) {
|
|
86850
|
+
const f = opts.fetchImpl || fetch;
|
|
86851
|
+
const steps = [];
|
|
86852
|
+
const url = String(docUrl || "").trim();
|
|
86853
|
+
if (!/^https?:\/\//i.test(url)) {
|
|
86854
|
+
return { ok: false, docUrl: url, steps, error: `\u5165\u7F51\u8BF4\u660E\u5730\u5740\u5FC5\u987B\u662F http(s) URL (\u6536\u5230: ${url.slice(0, 60)})` };
|
|
86855
|
+
}
|
|
86856
|
+
let docVersion;
|
|
86857
|
+
try {
|
|
86858
|
+
const r = await f(url, { signal: AbortSignal.timeout(opts.timeoutMs ?? 15e3) });
|
|
86859
|
+
if (!r.ok) {
|
|
86860
|
+
steps.push({ step: "\u8BFB\u5165\u7F51\u8BF4\u660E", ok: false, note: `\u6587\u6863\u4E0D\u53EF\u8FBE (HTTP ${r.status})` });
|
|
86861
|
+
return { ok: false, docUrl: url, steps, error: `\u5165\u7F51\u8BF4\u660E\u4E0D\u53EF\u8FBE (HTTP ${r.status})` };
|
|
86862
|
+
}
|
|
86863
|
+
const text = await r.text();
|
|
86864
|
+
const fm = parseFm(text);
|
|
86865
|
+
if (fm.name !== "bolloon-gateway-join" && !/加入网关|bolloon-gateway-join/.test(text)) {
|
|
86866
|
+
steps.push({ step: "\u8BFB\u5165\u7F51\u8BF4\u660E", ok: false, note: `\u4E0D\u662F Bolloon \u5165\u7F51\u8BF4\u660E (name=${fm.name || "\u65E0"})` });
|
|
86867
|
+
return { ok: false, docUrl: url, steps, error: "\u8BE5\u6587\u6863\u4E0D\u662F Bolloon \u7F51\u5173\u5165\u7F51\u8BF4\u660E, \u62D2\u7EDD\u636E\u6B64\u5165\u7F51" };
|
|
86868
|
+
}
|
|
86869
|
+
docVersion = fm.version;
|
|
86870
|
+
steps.push({ step: "\u8BFB\u5165\u7F51\u8BF4\u660E", ok: true, note: `${fm.name || "bolloon-gateway-join"} v${fm.version || "?"} (${text.length} \u5B57\u7B26)` });
|
|
86871
|
+
} catch (e) {
|
|
86872
|
+
steps.push({ step: "\u8BFB\u5165\u7F51\u8BF4\u660E", ok: false, note: `\u8BFB\u53D6\u5931\u8D25: ${String(e?.message || e).slice(0, 120)}` });
|
|
86873
|
+
return { ok: false, docUrl: url, steps, error: `\u5165\u7F51\u8BF4\u660E\u8BFB\u53D6\u5931\u8D25: ${String(e?.message || e).slice(0, 120)}` };
|
|
86874
|
+
}
|
|
86875
|
+
let did = String(opts.did || "");
|
|
86876
|
+
if (did) {
|
|
86877
|
+
steps.push({ step: "DID \u8EAB\u4EFD", ok: true, note: `${did} (\u6CE8\u5165\u8EAB\u4EFD)` });
|
|
86878
|
+
} else {
|
|
86879
|
+
try {
|
|
86880
|
+
const id = await ensureIdentity();
|
|
86881
|
+
did = id.did;
|
|
86882
|
+
steps.push({ step: "DID \u8EAB\u4EFD", ok: true, note: `${did} (\u624B\u673A\u7AEF\u672C\u673A\u751F\u6210)` });
|
|
86883
|
+
} catch (e) {
|
|
86884
|
+
steps.push({ step: "DID \u8EAB\u4EFD", ok: false, note: String(e?.message || e).slice(0, 120) });
|
|
86885
|
+
return { ok: false, docUrl: url, docVersion, steps, error: "\u624B\u673A\u7AEF DID \u751F\u6210\u5931\u8D25" };
|
|
86886
|
+
}
|
|
86887
|
+
}
|
|
86888
|
+
const name10 = String(opts.name || "phone-agent");
|
|
86889
|
+
const capabilities = ["chat", "gateway-join"];
|
|
86890
|
+
let desktopBase = String(opts.desktopBaseUrl ?? "");
|
|
86891
|
+
if (opts.desktopBaseUrl === void 0) {
|
|
86892
|
+
try {
|
|
86893
|
+
const g = await Promise.resolve().then(() => (init_mobile_gateway(), mobile_gateway_exports));
|
|
86894
|
+
desktopBase = String(g.getDesktopBaseUrl() || "");
|
|
86895
|
+
} catch {
|
|
86896
|
+
desktopBase = "";
|
|
86897
|
+
}
|
|
86898
|
+
}
|
|
86899
|
+
desktopBase = desktopBase.replace(/\/+$/, "");
|
|
86900
|
+
let registeredOn = "local";
|
|
86901
|
+
if (desktopBase) {
|
|
86902
|
+
try {
|
|
86903
|
+
const r = await f(`${desktopBase}/api/registry/register`, {
|
|
86904
|
+
method: "POST",
|
|
86905
|
+
headers: { "content-type": "application/json" },
|
|
86906
|
+
body: JSON.stringify({
|
|
86907
|
+
agentId: did,
|
|
86908
|
+
name: name10,
|
|
86909
|
+
wallet: "",
|
|
86910
|
+
service: { name: "chat", description: "\u624B\u673A\u7AEF\u667A\u80FD\u4F53 (\u81EA\u8DB3\u8282\u70B9)", price: { amount: "0", currency: "USDC", per: "task" }, endpoint: "" },
|
|
86911
|
+
capabilities
|
|
86912
|
+
}),
|
|
86913
|
+
signal: AbortSignal.timeout(opts.timeoutMs ?? 15e3)
|
|
86914
|
+
});
|
|
86915
|
+
if (r.ok) {
|
|
86916
|
+
registeredOn = "desktop";
|
|
86917
|
+
steps.push({ step: "\u670D\u52A1\u767B\u8BB0", ok: true, note: `\u5DF2\u767B\u8BB0\u8FDB\u7535\u8111\u7AEF\u7F51\u7EDC registry (${desktopBase}) \u2014\u2014 \u7F51\u7EDC\u5185\u5176\u4ED6\u667A\u80FD\u4F53\u53EF\u6309\u80FD\u529B\u53D1\u73B0\u6211` });
|
|
86918
|
+
} else {
|
|
86919
|
+
steps.push({ step: "\u670D\u52A1\u767B\u8BB0", ok: false, note: `\u7535\u8111\u7AEF registry \u62D2\u7EDD (HTTP ${r.status}); \u5DF2\u6539\u4E3A\u672C\u673A\u767B\u8BB0` });
|
|
86920
|
+
}
|
|
86921
|
+
} catch (e) {
|
|
86922
|
+
steps.push({ step: "\u670D\u52A1\u767B\u8BB0", ok: false, note: `\u7535\u8111\u7AEF\u4E0D\u53EF\u8FBE (${String(e?.message || e).slice(0, 80)}); \u5DF2\u6539\u4E3A\u672C\u673A\u767B\u8BB0` });
|
|
86923
|
+
}
|
|
86924
|
+
} else {
|
|
86925
|
+
steps.push({ step: "\u670D\u52A1\u767B\u8BB0", ok: true, note: "\u672A\u914D\u7F6E\u7535\u8111\u7AEF\u57FA\u5740 \u2192 \u53EA\u5728\u672C\u673A\u767B\u8BB0 (\u624B\u673A\u662F\u81EA\u6CBB\u8282\u70B9; \u8BBE\u7F6E\u91CC\u586B\u7535\u8111\u7AEF\u5730\u5740\u53EF\u767B\u8BB0\u8FDB\u7F51\u7EDC registry)" });
|
|
86926
|
+
}
|
|
86927
|
+
try {
|
|
86928
|
+
const p2p = await Promise.resolve().then(() => (init_mobile_p2p(), mobile_p2p_exports));
|
|
86929
|
+
let peers = 0;
|
|
86930
|
+
try {
|
|
86931
|
+
peers = (p2p.getConnectedPeers?.() || []).length;
|
|
86932
|
+
} catch {
|
|
86933
|
+
peers = 0;
|
|
86934
|
+
}
|
|
86935
|
+
if (peers > 0 && typeof p2p.sendMobileP2PMessage === "function") {
|
|
86936
|
+
const okAnnounce = await p2p.sendMobileP2PMessage("*", "registry.register", JSON.stringify({ agent_id: did, name: name10, capabilities }), did);
|
|
86937
|
+
steps.push({ step: "P2P \u516C\u544A", ok: !!okAnnounce, note: okAnnounce ? `\u5DF2\u5411 ${peers} \u4E2A\u5BF9\u7AEF\u5E7F\u64AD\u672C\u673A\u58F0\u660E` : `\u5E7F\u64AD\u5931\u8D25 (\u5BF9\u7AEF ${peers} \u4E2A)` });
|
|
86938
|
+
} else {
|
|
86939
|
+
steps.push({ step: "P2P \u516C\u544A", ok: false, note: "\u5F53\u524D\u65E0\u5DF2\u8FDE\u63A5\u5BF9\u7AEF (\u6D4F\u89C8\u5668/\u672A\u8FDE\u7535\u8111\u7AEF\u65F6\u6B63\u5E38) \u2014 \u672C\u673A\u58F0\u660E\u5DF2\u5C31\u7EEA, \u8FDE\u4E0A\u5373\u751F\u6548" });
|
|
86940
|
+
}
|
|
86941
|
+
} catch (e) {
|
|
86942
|
+
steps.push({ step: "P2P \u516C\u544A", ok: false, note: `P2P \u5C42\u4E0D\u53EF\u7528: ${String(e?.message || e).slice(0, 80)}` });
|
|
86943
|
+
}
|
|
86944
|
+
saveMobileJoinState({ url, did, name: name10, capabilities, docVersion, registeredOn, desktopBaseUrl: desktopBase || void 0, joinedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
86945
|
+
const state2 = await getMobileJoinState();
|
|
86946
|
+
steps.push({ step: "\u843D\u76D8\u5165\u7F51\u6001", ok: !!state2?.did, note: `localStorage:${MOBILE_JOIN_STATE_KEY}` });
|
|
86947
|
+
return { ok: true, docUrl: url, docVersion, did, steps };
|
|
86948
|
+
}
|
|
86949
|
+
function formatMobileJoinResult(r) {
|
|
86950
|
+
if (!r.ok) {
|
|
86951
|
+
return `\u274C \u5165\u7F51\u5931\u8D25: ${r.error || "\u672A\u77E5\u539F\u56E0"}
|
|
86952
|
+
|
|
86953
|
+
${r.steps.map((s3) => `${s3.ok ? "\u2713" : "\u2717"} ${s3.step}: ${s3.note}`).join("\n")}`;
|
|
86954
|
+
}
|
|
86955
|
+
const s2 = r.steps.find((x) => x.step === "\u670D\u52A1\u767B\u8BB0");
|
|
86956
|
+
return [
|
|
86957
|
+
"\u2705 \u5DF2\u52A0\u5165\u5168\u7403\u667A\u80FD\u4F53\u7F51\u7EDC (\u624B\u673A\u7AEF\u81EA\u8DB3\u6267\u884C)",
|
|
86958
|
+
"",
|
|
86959
|
+
`DID: ${r.did}`,
|
|
86960
|
+
`\u5165\u7F51\u8BF4\u660E: v${r.docVersion || "?"} (${r.docUrl})`,
|
|
86961
|
+
s2 ? `\u767B\u8BB0: ${s2.note}` : "",
|
|
86962
|
+
"",
|
|
86963
|
+
...r.steps.map((x) => `${x.ok ? "\u2713" : "\u2717"} ${x.step}: ${x.note}`),
|
|
86964
|
+
"",
|
|
86965
|
+
"\u7528\u300C\u7F51\u7EDC \u2192 Agent \u7F51\u7EDC\u300D\u53EF\u67E5\u770B\u6210\u5458; \u8BBE\u7F6E\u91CC\u586B\u7535\u8111\u7AEF\u5730\u5740\u53EF\u628A\u672C\u673A\u767B\u8BB0\u8FDB\u7F51\u7EDC registry\u3002"
|
|
86966
|
+
].filter((l) => l !== "").join("\n");
|
|
86967
|
+
}
|
|
86729
86968
|
async function runLocalAgent(goal) {
|
|
86730
86969
|
const win = typeof window !== "undefined" ? window : null;
|
|
86731
86970
|
const cap = win?.Capacitor;
|
|
86971
|
+
const joinDocUrl = detectJoinDocUrl(goal);
|
|
86972
|
+
if (joinDocUrl) {
|
|
86973
|
+
_lastWorklog = [`\u{1F9E9} \u8BC6\u522B\u4E3A\u5165\u7F51\u53E3\u4EE4: ${joinDocUrl}`];
|
|
86974
|
+
const r = await joinGatewayFromDoc(joinDocUrl).catch((e) => ({
|
|
86975
|
+
ok: false,
|
|
86976
|
+
docUrl: joinDocUrl,
|
|
86977
|
+
steps: [{ step: "\u5165\u7F51", ok: false, note: String(e?.message || e).slice(0, 120) }],
|
|
86978
|
+
error: String(e?.message || e)
|
|
86979
|
+
}));
|
|
86980
|
+
_lastWorklog = [..._lastWorklog, ...r.steps.map((s2) => `${s2.ok ? "\u2713" : "\u2717"} ${s2.step}: ${s2.note}`)];
|
|
86981
|
+
return formatMobileJoinResult(r);
|
|
86982
|
+
}
|
|
86732
86983
|
const bridge = cap && cap.Plugins && cap.Plugins.RokidBridge;
|
|
86733
86984
|
if (bridge && cap.isNativePlatform?.()) {
|
|
86734
86985
|
try {
|
|
@@ -86984,7 +87235,7 @@ ${[...listenStats.errors.entries()].map(([addr, err2]) => {
|
|
|
86984
87235
|
} catch {
|
|
86985
87236
|
}
|
|
86986
87237
|
}
|
|
86987
|
-
var IDENTITY_DB, _identity, _identityDb, _llmConfig, _lastWorklog, _send, _ownDid, replyHandlers, inboundChatHandlers, mobile_agent_default;
|
|
87238
|
+
var IDENTITY_DB, _identity, _identityDb, _llmConfig, _lastWorklog, MOBILE_JOIN_DOC_RE, MOBILE_JOIN_STATE_KEY, _send, _ownDid, replyHandlers, inboundChatHandlers, mobile_agent_default;
|
|
86988
87239
|
var init_mobile_agent = __esm({
|
|
86989
87240
|
"src/web/mobile-agent.ts"() {
|
|
86990
87241
|
"use strict";
|
|
@@ -86994,6 +87245,8 @@ ${[...listenStats.errors.entries()].map(([addr, err2]) => {
|
|
|
86994
87245
|
_identityDb = null;
|
|
86995
87246
|
_llmConfig = null;
|
|
86996
87247
|
_lastWorklog = [];
|
|
87248
|
+
MOBILE_JOIN_DOC_RE = /read\s+(https?:\/\/\S*bolloon-gateway-join\.md)/i;
|
|
87249
|
+
MOBILE_JOIN_STATE_KEY = "bolloon_gateway_join";
|
|
86997
87250
|
_send = null;
|
|
86998
87251
|
_ownDid = "";
|
|
86999
87252
|
replyHandlers = /* @__PURE__ */ new Set();
|
|
@@ -99765,13 +100018,21 @@ ${[...listenStats.errors.entries()].map(([addr, err2]) => {
|
|
|
99765
100018
|
if (!r.ok) return { ok: false, addrs: [], error: `\u7535\u8111\u7AEF\u8FD4\u56DE ${r.status}` };
|
|
99766
100019
|
const j = await r.json();
|
|
99767
100020
|
const raw = Array.isArray(j?.wsAddrs) ? j.wsAddrs : [];
|
|
99768
|
-
const
|
|
99769
|
-
let
|
|
99770
|
-
if (host)
|
|
99771
|
-
|
|
99772
|
-
return
|
|
99773
|
-
}
|
|
99774
|
-
|
|
100021
|
+
const rewrite = (a) => {
|
|
100022
|
+
let out2 = a;
|
|
100023
|
+
if (host) out2 = out2.replace(/\/ip4\/(0\.0\.0\.0|127\.0\.0\.1)\//, `/ip4/${host}/`);
|
|
100024
|
+
out2 = out2.replace(/\/ip6\/::1\//, `/ip4/${host || "127.0.0.1"}/`);
|
|
100025
|
+
return out2;
|
|
100026
|
+
};
|
|
100027
|
+
const keep = (a) => ip4Of(a) && !/\/ip4\/(0\.0\.0\.0|127\.0\.0\.1)\//.test(a);
|
|
100028
|
+
const addrs = raw.map(rewrite).filter(keep);
|
|
100029
|
+
const relayRaw = Array.isArray(j?.relayAddrs) ? j.relayAddrs : [];
|
|
100030
|
+
const relayAddrs = relayRaw.map(rewrite).filter(keep);
|
|
100031
|
+
const out = { ok: j?.ok !== false, peerId: j?.peerId || "", addrs: Array.from(new Set(addrs)) };
|
|
100032
|
+
if (j?.isRelay === true) out.isRelay = true;
|
|
100033
|
+
if (relayAddrs.length) out.relayAddrs = Array.from(new Set(relayAddrs));
|
|
100034
|
+
if (typeof j?.relayProtocol === "string") out.relayProtocol = j.relayProtocol;
|
|
100035
|
+
return out;
|
|
99775
100036
|
} catch (e) {
|
|
99776
100037
|
return { ok: false, addrs: [], error: e?.message || String(e) };
|
|
99777
100038
|
}
|
|
@@ -149882,6 +150143,32 @@ ${error.stack}` : head;
|
|
|
149882
150143
|
return `error:${errMsg3(err2)}`;
|
|
149883
150144
|
}
|
|
149884
150145
|
}
|
|
150146
|
+
function relaysFromCircuitAddrs(circuitAddrs) {
|
|
150147
|
+
const out = [];
|
|
150148
|
+
for (const a of circuitAddrs) {
|
|
150149
|
+
const head = a.split("/p2p-circuit")[0] || "";
|
|
150150
|
+
const ids = head.match(/\/p2p\/([^/]+)/g) || [];
|
|
150151
|
+
const last = ids[ids.length - 1];
|
|
150152
|
+
const relay = last ? last.slice("/p2p/".length) : "";
|
|
150153
|
+
if (relay && !out.includes(relay)) out.push(relay);
|
|
150154
|
+
}
|
|
150155
|
+
return out;
|
|
150156
|
+
}
|
|
150157
|
+
function circuitInfoOf(libp2p) {
|
|
150158
|
+
try {
|
|
150159
|
+
const all2 = (libp2p?.getMultiaddrs?.() || []).map(
|
|
150160
|
+
(a) => a && typeof a.toString === "function" ? a.toString() : String(a)
|
|
150161
|
+
);
|
|
150162
|
+
const isWs = (a) => {
|
|
150163
|
+
const parts = a.split("/");
|
|
150164
|
+
return parts.includes("ws") || parts.includes("wss");
|
|
150165
|
+
};
|
|
150166
|
+
const circuitAddrs = all2.filter((a) => a.includes("/p2p-circuit")).sort((a, b) => (isWs(a) ? 0 : 1) - (isWs(b) ? 0 : 1));
|
|
150167
|
+
return { circuitAddrs, relays: relaysFromCircuitAddrs(circuitAddrs) };
|
|
150168
|
+
} catch {
|
|
150169
|
+
return { circuitAddrs: [], relays: [] };
|
|
150170
|
+
}
|
|
150171
|
+
}
|
|
149885
150172
|
function verifyStarted(node2) {
|
|
149886
150173
|
const peerId = peerIdOf(node2);
|
|
149887
150174
|
const lps = libp2pStatusOf(node2);
|
|
@@ -150147,7 +150434,9 @@ ${error.stack}` : head;
|
|
|
150147
150434
|
ok: true,
|
|
150148
150435
|
running: false,
|
|
150149
150436
|
peers: [],
|
|
150150
|
-
libp2pStatus: "not-created"
|
|
150437
|
+
libp2pStatus: "not-created",
|
|
150438
|
+
circuitAddrs: [],
|
|
150439
|
+
relays: []
|
|
150151
150440
|
};
|
|
150152
150441
|
if (lastStartError) out.lastError = lastStartError;
|
|
150153
150442
|
return out;
|
|
@@ -150157,6 +150446,7 @@ ${error.stack}` : head;
|
|
|
150157
150446
|
const libp2pStatus = libp2pStatusOf(node2);
|
|
150158
150447
|
const peerId = currentPeerId ?? peerIdOf(node2);
|
|
150159
150448
|
const running = libp2pError ? false : libp2p ? libp2pStatus === "started" : node2.status === "started";
|
|
150449
|
+
const { circuitAddrs, relays } = circuitInfoOf(libp2p);
|
|
150160
150450
|
let peers = [];
|
|
150161
150451
|
try {
|
|
150162
150452
|
const list = libp2p?.getPeers?.() || [];
|
|
@@ -150174,7 +150464,7 @@ ${error.stack}` : head;
|
|
|
150174
150464
|
blockCount = void 0;
|
|
150175
150465
|
}
|
|
150176
150466
|
}
|
|
150177
|
-
const out = { ok: true, running, peers, libp2pStatus };
|
|
150467
|
+
const out = { ok: true, running, peers, libp2pStatus, circuitAddrs, relays };
|
|
150178
150468
|
if (peerId) out.peerId = peerId;
|
|
150179
150469
|
if (blockCount !== void 0) out.blockCount = blockCount;
|
|
150180
150470
|
if (lastStartError) out.lastError = lastStartError;
|
|
@@ -150186,6 +150476,8 @@ ${error.stack}` : head;
|
|
|
150186
150476
|
running: false,
|
|
150187
150477
|
peers: [],
|
|
150188
150478
|
libp2pStatus: libp2pStatusOf(node2),
|
|
150479
|
+
circuitAddrs: [],
|
|
150480
|
+
relays: [],
|
|
150189
150481
|
error: errDetail(err2)
|
|
150190
150482
|
};
|
|
150191
150483
|
if (lastStartError) out.lastError = lastStartError;
|
|
@@ -162617,8 +162909,10 @@ ${error.stack}` : head;
|
|
|
162617
162909
|
resolve(path) {
|
|
162618
162910
|
const p = path || "";
|
|
162619
162911
|
if (p === "/channels") return () => core.channels.get();
|
|
162912
|
+
if (p === "/api/data/snapshot") return () => core.data.snapshot();
|
|
162620
162913
|
if (p === "/api/peers") return () => core.peers.list();
|
|
162621
162914
|
if (p === "/api/mcp/tools") return () => core.mcp.tools();
|
|
162915
|
+
if (p === "/api/skills") return () => core.skills.list();
|
|
162622
162916
|
if (p === "/api/auth/status") return () => core.identity.status();
|
|
162623
162917
|
if (p === "/api/payments/pending") return () => core.payments.pending();
|
|
162624
162918
|
if (p === "/api/llm-config") return () => core.data.getLlmConfig();
|
|
@@ -162652,6 +162946,7 @@ ${error.stack}` : head;
|
|
|
162652
162946
|
if (p === "/api/desktop/url") return () => core.desktop.url();
|
|
162653
162947
|
if (p === "/api/desktop/sync") return () => core.desktop.sync();
|
|
162654
162948
|
if (p === "/api/judgments/cached") return () => core.desktop.judgments();
|
|
162949
|
+
if (p === "/api/x402/info") return () => core.x402.list();
|
|
162655
162950
|
if (p === "/api/orbit/status") return () => core.orbit.status();
|
|
162656
162951
|
if (p === "/api/orbit/replica") return () => core.orbit.replica();
|
|
162657
162952
|
if (p.startsWith("/sessions/")) {
|
|
@@ -162663,6 +162958,10 @@ ${error.stack}` : head;
|
|
|
162663
162958
|
/** POST 路径 → 内核函数 */
|
|
162664
162959
|
resolvePost(path, body) {
|
|
162665
162960
|
const p = path || "";
|
|
162961
|
+
if (p === "/api/mcp/call") {
|
|
162962
|
+
const b = body || {};
|
|
162963
|
+
return () => core.mcp.call(String(b.name || ""), b.args || {});
|
|
162964
|
+
}
|
|
162666
162965
|
if (p === "/message") {
|
|
162667
162966
|
const b = body || {};
|
|
162668
162967
|
return () => core.message.send({ text: b.text, channelId: b.channelId });
|
|
@@ -162752,6 +163051,10 @@ ${error.stack}` : head;
|
|
|
162752
163051
|
const b = body || {};
|
|
162753
163052
|
return () => core.desktop.setUrl(String(b.url || ""));
|
|
162754
163053
|
}
|
|
163054
|
+
if (p === "/api/x402/info/buy") {
|
|
163055
|
+
const b = body || {};
|
|
163056
|
+
return () => core.x402.buy(b);
|
|
163057
|
+
}
|
|
162755
163058
|
if (p === "/api/network/connect") return () => core.network.connect();
|
|
162756
163059
|
if (p === "/api/social/announce") return () => core.social.announce();
|
|
162757
163060
|
if (p === "/api/chain/config") {
|
|
@@ -162887,6 +163190,7 @@ ${error.stack}` : head;
|
|
|
162887
163190
|
const dataLayer = await Promise.resolve().then(() => (init_mobile_data(), mobile_data_exports));
|
|
162888
163191
|
const id = await agentLayer.ensureIdentity();
|
|
162889
163192
|
let seeds = seedAddrs && seedAddrs.length ? seedAddrs : void 0;
|
|
163193
|
+
let relayAddrs;
|
|
162890
163194
|
let desktopPeer = "";
|
|
162891
163195
|
if (!seeds) {
|
|
162892
163196
|
try {
|
|
@@ -162896,10 +163200,11 @@ ${error.stack}` : head;
|
|
|
162896
163200
|
seeds = d2.addrs;
|
|
162897
163201
|
desktopPeer = d2.peerId || "";
|
|
162898
163202
|
}
|
|
163203
|
+
if (d2.ok && Array.isArray(d2.relayAddrs) && d2.relayAddrs.length) relayAddrs = d2.relayAddrs;
|
|
162899
163204
|
} catch {
|
|
162900
163205
|
}
|
|
162901
163206
|
}
|
|
162902
|
-
const st = await startMobileP2P2({ seedAddrs: seeds, ownDid: id.did });
|
|
163207
|
+
const st = await startMobileP2P2({ seedAddrs: seeds, ownDid: id.did, relayAddrs });
|
|
162903
163208
|
if (desktopPeer) busBroadcast({ type: "p2p-desktop", peerId: desktopPeer, addrs: seeds || [] });
|
|
162904
163209
|
try {
|
|
162905
163210
|
const social = await Promise.resolve().then(() => (init_mobile_social(), mobile_social_exports));
|
|
@@ -163168,6 +163473,50 @@ ${error.stack}` : head;
|
|
|
163168
163473
|
return { judgments: s2.getCachedJudgments() };
|
|
163169
163474
|
}
|
|
163170
163475
|
},
|
|
163476
|
+
// 微信息 (x402 付费信息) — 手机端**不持 EVM 私钥**: 浏览与代付一律转发电脑端;
|
|
163477
|
+
// 电脑端不可达就如实回 desktop-unreachable, 绝不返回假数据 (2026-09-13)
|
|
163478
|
+
x402: {
|
|
163479
|
+
/** 桌面基址 (设置页填; 与 mobile.js 的 desktopBaseUrl() 同一 localStorage key) */
|
|
163480
|
+
async baseUrl() {
|
|
163481
|
+
try {
|
|
163482
|
+
const g = await Promise.resolve().then(() => (init_mobile_gateway(), mobile_gateway_exports));
|
|
163483
|
+
return String(g.getDesktopBaseUrl() || "").replace(/\/+$/, "");
|
|
163484
|
+
} catch {
|
|
163485
|
+
return "";
|
|
163486
|
+
}
|
|
163487
|
+
},
|
|
163488
|
+
/** 免费元数据列表 (电脑端已发布的付费信息); 不可达 → {count:0,items:[],note:'desktop-unreachable'} */
|
|
163489
|
+
async list() {
|
|
163490
|
+
const base6 = await core.x402.baseUrl();
|
|
163491
|
+
if (!base6) return { count: 0, items: [], note: "desktop-unreachable" };
|
|
163492
|
+
try {
|
|
163493
|
+
const r = await fetch(`${base6}/api/x402/info`);
|
|
163494
|
+
if (!r.ok) return { count: 0, items: [], note: "desktop-unreachable" };
|
|
163495
|
+
const d2 = await r.json();
|
|
163496
|
+
if (!d2 || !Array.isArray(d2.items)) return { count: 0, items: [], note: "desktop-unreachable" };
|
|
163497
|
+
return d2;
|
|
163498
|
+
} catch {
|
|
163499
|
+
return { count: 0, items: [], note: "desktop-unreachable" };
|
|
163500
|
+
}
|
|
163501
|
+
},
|
|
163502
|
+
/** 购买并验真: 转发电脑端 /api/x402/info/buy 代付; 失败把后端 error 原文带回 (不吞错) */
|
|
163503
|
+
async buy(body) {
|
|
163504
|
+
const base6 = await core.x402.baseUrl();
|
|
163505
|
+
if (!base6) return { ok: false, error: "\u9700\u8981\u7535\u8111\u7AEF\u5728\u7EBF (\u8BBE\u7F6E\u91CC\u586B\u684C\u9762\u5730\u5740)" };
|
|
163506
|
+
try {
|
|
163507
|
+
const r = await fetch(`${base6}/api/x402/info/buy`, {
|
|
163508
|
+
method: "POST",
|
|
163509
|
+
headers: { "Content-Type": "application/json" },
|
|
163510
|
+
body: JSON.stringify(body || {})
|
|
163511
|
+
});
|
|
163512
|
+
const d2 = await r.json().catch(() => null);
|
|
163513
|
+
if (!r.ok) return { ok: false, status: r.status, error: d2 && (d2.error || d2.message) || `\u7535\u8111\u7AEF\u8FD4\u56DE ${r.status}` };
|
|
163514
|
+
return d2 || { ok: false, error: "\u7535\u8111\u7AEF\u8FD4\u56DE\u7A7A\u54CD\u5E94" };
|
|
163515
|
+
} catch (e) {
|
|
163516
|
+
return { ok: false, error: "\u7535\u8111\u7AEF\u4E0D\u53EF\u8FBE: " + String(e?.message || e).slice(0, 120) };
|
|
163517
|
+
}
|
|
163518
|
+
}
|
|
163519
|
+
},
|
|
163171
163520
|
// 自动社交 (E1): 服务声明广播 / 发现 / 心跳 — 协议见 docs/wiki/agent-economic-protocol.md
|
|
163172
163521
|
social: {
|
|
163173
163522
|
async announce() {
|
|
@@ -163311,6 +163660,17 @@ ${error.stack}` : head;
|
|
|
163311
163660
|
{ name: "gateway_call", description: "\u901A\u8FC7 Agent Gateway \u8C03\u7528\u670D\u52A1 (\u81EA\u52A8\u95ED\u73AF)" },
|
|
163312
163661
|
{ name: "gateway_join", description: "\u901A\u8FC7\u94FE\u63A5\u52A0\u5165\u5171\u4EAB Agent \u7F51\u7EDC" }
|
|
163313
163662
|
];
|
|
163663
|
+
},
|
|
163664
|
+
async call(name10, args) {
|
|
163665
|
+
const { mobileGatewayTool: mobileGatewayTool2 } = await Promise.resolve().then(() => (init_mobile_gateway(), mobile_gateway_exports));
|
|
163666
|
+
return mobileGatewayTool2(String(name10 || ""), args || {});
|
|
163667
|
+
}
|
|
163668
|
+
},
|
|
163669
|
+
skills: {
|
|
163670
|
+
async list() {
|
|
163671
|
+
const s2 = await Promise.resolve().then(() => (init_mobile_sync(), mobile_sync_exports));
|
|
163672
|
+
const snap = s2.getLastSnapshot();
|
|
163673
|
+
return snap && Array.isArray(snap.skills) ? snap.skills : [];
|
|
163314
163674
|
}
|
|
163315
163675
|
},
|
|
163316
163676
|
message: {
|