@bolloon/bolloon-agent 0.4.30 → 0.4.32
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/agents/agent-gateway.js +5 -0
- package/dist/agents/agent-manifest-protocol.js +29 -0
- package/dist/agents/chain/chain-config.js +504 -0
- package/dist/agents/chain/chain-index-query.js +135 -0
- package/dist/agents/chain/chain-indexer.js +1045 -0
- package/dist/agents/chain/chain-settlement.js +284 -0
- package/dist/agents/chain/chain-state-store.js +245 -0
- package/dist/agents/chain/chain-wallet.js +198 -0
- package/dist/agents/chain/escrow-client.js +433 -0
- package/dist/agents/chain/index.js +20 -0
- package/dist/agents/chain/onchain-trade.js +691 -0
- package/dist/agents/economic-policy.js +7 -0
- package/dist/agents/gateway-network.js +6 -0
- package/dist/agents/local-signer.js +59 -0
- package/dist/agents/network-pulse.js +912 -0
- package/dist/agents/task/task-onchain-runner.js +284 -0
- package/dist/agents/task-contract.js +322 -0
- package/dist/agents/task-inbox.js +267 -0
- package/dist/agents/task-transport.js +280 -0
- package/dist/agents/x402/paid-info-store.js +75 -6
- package/dist/agents/x402/transaction-store.js +8 -1
- package/dist/cli/commands/agent.js +230 -0
- package/dist/cli/commands/chain.js +926 -0
- package/dist/cli/commands/index.js +69 -0
- package/dist/cli/commands/mcp.js +98 -0
- package/dist/cli/commands/network.js +334 -0
- package/dist/cli/commands/payment.js +125 -0
- package/dist/cli/commands/tasks.js +1236 -0
- package/dist/cli/commands/trade.js +229 -0
- package/dist/cli/commands/wallet.js +450 -0
- package/dist/cli/mcp/bridge.js +105 -0
- package/dist/cli/mcp/server.js +188 -0
- package/dist/cli/mcp/tools.js +955 -0
- package/dist/cli/protocol-envelope.js +358 -0
- package/dist/cli-entry.js +146 -17
- package/dist/electron-build/agents/agent-gateway.js +5 -0
- package/dist/electron-build/agents/agent-gateway.js.map +1 -1
- package/dist/electron-build/agents/agent-manifest-protocol.js +62 -0
- package/dist/electron-build/agents/agent-manifest-protocol.js.map +1 -1
- package/dist/electron-build/agents/chain/chain-config.js +556 -0
- package/dist/electron-build/agents/chain/chain-config.js.map +1 -0
- package/dist/electron-build/agents/chain/chain-index-query.js +145 -0
- package/dist/electron-build/agents/chain/chain-index-query.js.map +1 -0
- package/dist/electron-build/agents/chain/chain-indexer.js +1095 -0
- package/dist/electron-build/agents/chain/chain-indexer.js.map +1 -0
- package/dist/electron-build/agents/chain/chain-settlement.js +291 -0
- package/dist/electron-build/agents/chain/chain-settlement.js.map +1 -0
- package/dist/electron-build/agents/chain/escrow-client.js +443 -0
- package/dist/electron-build/agents/chain/escrow-client.js.map +1 -0
- package/dist/electron-build/agents/economic-policy.js +7 -0
- package/dist/electron-build/agents/economic-policy.js.map +1 -1
- package/dist/electron-build/agents/gateway-network.js +6 -0
- package/dist/electron-build/agents/gateway-network.js.map +1 -1
- package/dist/electron-build/agents/network-pulse.js +979 -0
- package/dist/electron-build/agents/network-pulse.js.map +1 -0
- package/dist/electron-build/agents/x402/paid-info-store.js +76 -6
- package/dist/electron-build/agents/x402/paid-info-store.js.map +1 -1
- package/dist/electron-build/agents/x402/transaction-store.js +8 -1
- package/dist/electron-build/agents/x402/transaction-store.js.map +1 -1
- package/dist/web/chain-explorer.js +617 -0
- package/dist/web/explorer.html +163 -0
- package/dist/web/index.html +5 -0
- package/dist/web/routes-chain-index.js +108 -0
- package/dist/web/routes-onchain-trade.js +99 -0
- package/dist/web/server.js +42 -0
- package/dist/web/task-frame-server.js +211 -0
- package/package.json +2 -1
- package/scripts/build-web.ts +20 -1
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* chain-index-query.ts — 链上索引的**只读查询接口** (P5, ③)
|
|
3
|
+
* =========================================================================
|
|
4
|
+
* 只做四件事, 全部是**读已落盘索引**, 不发任何 RPC、不写盘、不签名:
|
|
5
|
+
* ① 按 taskKey 查 escrow 时间线 → getEscrowTimeline(taskKey)
|
|
6
|
+
* ② 按 cursor(区块号+logIndex) 增量拉取 → fetchIndexSince(cursor, {limit})
|
|
7
|
+
* ③ 全量统计 (tasks/released/refunded/disputed/expired) → getIndexStats()
|
|
8
|
+
* ④ 当前索引高度 + 最后同步时间 → getIndexStatus()
|
|
9
|
+
*
|
|
10
|
+
* 为什么单独一个文件: 网页/工具/别的进程都可能要读, 而**读不该需要 RPC**。
|
|
11
|
+
* 这里构造的 ChainIndexer 一律是只读模式 (deploymentBlock 显式给 0, 不查 manifest),
|
|
12
|
+
* 真去读链会明确报 'chain_index_readonly' —— 不静默返回空。
|
|
13
|
+
*/
|
|
14
|
+
import { ChainIndexer, chainIndexPath, deriveEscrowState, byBlockLogIndex } from './chain-indexer.js';
|
|
15
|
+
import { DEFAULT_CONFIRMATIONS } from './chain-config.js';
|
|
16
|
+
let overridePath = null;
|
|
17
|
+
/** 测试/嵌入用: 把索引文件路径钉死 (null = 恢复默认 ~/.bolloon/chain/index.json) */
|
|
18
|
+
export function setChainIndexPathForTesting(p) {
|
|
19
|
+
overridePath = p;
|
|
20
|
+
}
|
|
21
|
+
export function currentIndexPath(home) {
|
|
22
|
+
return overridePath || chainIndexPath(home);
|
|
23
|
+
}
|
|
24
|
+
/** 只读模式的 indexer (故意不查 manifest: 查索引不需要知道部署块) */
|
|
25
|
+
function readonlyIndexer(opts = {}) {
|
|
26
|
+
const p = currentIndexPath(opts.home);
|
|
27
|
+
return new ChainIndexer({
|
|
28
|
+
// 只读: 给个占位 provider, 真调链会抛 chain_index_readonly
|
|
29
|
+
provider: {
|
|
30
|
+
async getBlockNumber() { throw new Error('chain_index_readonly: 只读查询不发 RPC'); },
|
|
31
|
+
async getBlock() { throw new Error('chain_index_readonly: 只读查询不发 RPC'); },
|
|
32
|
+
async getLogs() { throw new Error('chain_index_readonly: 只读查询不发 RPC'); },
|
|
33
|
+
},
|
|
34
|
+
escrowAddress: '0x' + '00'.repeat(20),
|
|
35
|
+
deploymentBlock: 0,
|
|
36
|
+
deploymentSource: 'readonly-query (不需要起点)',
|
|
37
|
+
home: opts.home,
|
|
38
|
+
indexPath: p,
|
|
39
|
+
confirmations: DEFAULT_CONFIRMATIONS,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/** 读索引文件 (没有 → 空索引, 不假装有) */
|
|
43
|
+
export function readIndexFile(opts = {}) {
|
|
44
|
+
return readonlyIndexer(opts).load();
|
|
45
|
+
}
|
|
46
|
+
/** ④ 当前索引高度 + 最后同步时间 */
|
|
47
|
+
export function getIndexStatus(opts = {}) {
|
|
48
|
+
const s = readIndexFile(opts);
|
|
49
|
+
return {
|
|
50
|
+
indexPath: currentIndexPath(opts.home),
|
|
51
|
+
chainId: s.chainId, networkName: s.networkName,
|
|
52
|
+
escrowAddress: s.escrowAddress, deploymentBlock: s.deploymentBlock, deploymentSource: s.deploymentSource,
|
|
53
|
+
identity: s.identity ?? { chainId: s.chainId, escrowAddress: s.escrowAddress.toLowerCase(), deploymentBlock: s.deploymentBlock },
|
|
54
|
+
lastSyncedBlock: s.lastSyncedBlock, lastSyncedAt: s.lastSyncedAt,
|
|
55
|
+
lastSyncedAgoMs: s.lastSyncedAt == null ? null : Date.now() - s.lastSyncedAt,
|
|
56
|
+
headBlock: s.headBlock, headBlockHash: s.headBlockHash,
|
|
57
|
+
entries: s.entries.length, suspects: s.entries.filter((e) => e.suspect).length,
|
|
58
|
+
confirmations: s.confirmations, pageSize: s.pageSize, reorgDepth: s.reorgDepth,
|
|
59
|
+
rebuiltAt: s.rebuiltAt ?? null, updatedAt: s.updatedAt,
|
|
60
|
+
lagFromSnapshot: s.headBlock == null ? null : Math.max(0, s.headBlock - (s.lastSyncedBlock + 1)),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/** ③ 全量统计。suspect (被回退) 的记录**不计入**业务计数, 但单独报出来。 */
|
|
64
|
+
export function getIndexStats(opts = {}) {
|
|
65
|
+
const s = readIndexFile(opts);
|
|
66
|
+
const live = s.entries.filter((e) => !e.suspect);
|
|
67
|
+
const byEvent = {};
|
|
68
|
+
for (const e of live)
|
|
69
|
+
byEvent[e.eventName] = (byEvent[e.eventName] || 0) + 1;
|
|
70
|
+
const byFinality = { observed: 0, confirmed: 0, finalized: 0 };
|
|
71
|
+
for (const e of s.entries)
|
|
72
|
+
byFinality[e.finality]++;
|
|
73
|
+
const n = (name) => live.filter((e) => e.eventName === name).length;
|
|
74
|
+
return {
|
|
75
|
+
entries: s.entries.length,
|
|
76
|
+
suspects: s.entries.filter((e) => e.suspect).length,
|
|
77
|
+
tasks: new Set(live.filter((e) => e.eventName === 'EscrowCreatedV2').map((e) => e.taskKey.toLowerCase())).size,
|
|
78
|
+
created: n('EscrowCreatedV2'),
|
|
79
|
+
proofSubmitted: n('ProofSubmittedV2'),
|
|
80
|
+
released: n('ReleasedV2'),
|
|
81
|
+
refunded: n('RefundedV2'),
|
|
82
|
+
disputed: n('DisputedV2'),
|
|
83
|
+
expired: n('ExpiredV2'),
|
|
84
|
+
byFinality, byEvent,
|
|
85
|
+
lastSyncedBlock: s.lastSyncedBlock, lastSyncedAt: s.lastSyncedAt, headBlock: s.headBlock,
|
|
86
|
+
deploymentBlock: s.deploymentBlock, chainId: s.chainId, escrowAddress: s.escrowAddress,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
const slim = (e) => ({
|
|
90
|
+
blockNumber: e.blockNumber, blockHash: e.blockHash, txHash: e.txHash, logIndex: e.logIndex,
|
|
91
|
+
eventName: e.eventName, args: e.args, confirmations: e.confirmations, finality: e.finality,
|
|
92
|
+
suspect: e.suspect, suspectReason: e.suspectReason,
|
|
93
|
+
});
|
|
94
|
+
/** ① 按 taskKey 查 escrow 时间线 (块号 + logIndex 升序) */
|
|
95
|
+
export function getEscrowTimeline(taskKey, opts = {}) {
|
|
96
|
+
const key = String(taskKey || '').toLowerCase();
|
|
97
|
+
if (!/^0x[0-9a-f]{64}$/.test(key)) {
|
|
98
|
+
// 非法 taskKey 不硬搜: 直接空时间线 + 明确说明 (路由层会回 400)
|
|
99
|
+
return { taskKey: key, state: null, events: [], count: 0, hasSuspect: false };
|
|
100
|
+
}
|
|
101
|
+
const events = readIndexFile(opts).entries
|
|
102
|
+
.filter((e) => e.taskKey.toLowerCase() === key)
|
|
103
|
+
.sort(byBlockLogIndex);
|
|
104
|
+
return {
|
|
105
|
+
taskKey: key,
|
|
106
|
+
state: deriveEscrowState(events),
|
|
107
|
+
events: events.map(slim),
|
|
108
|
+
count: events.length,
|
|
109
|
+
hasSuspect: events.some((e) => e.suspect),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
/** ② 按 cursor 增量拉取 (严格大于 cursor 的 (blockNumber, logIndex)) */
|
|
113
|
+
export function fetchIndexSince(cursor, opts = {}) {
|
|
114
|
+
const limit = Math.max(1, Math.min(1000, Math.floor(opts.limit ?? 200)));
|
|
115
|
+
const all = readIndexFile(opts).entries
|
|
116
|
+
.filter((e) => {
|
|
117
|
+
if (!cursor)
|
|
118
|
+
return true;
|
|
119
|
+
const cb = Number(cursor.blockNumber), cl = Number(cursor.logIndex);
|
|
120
|
+
return e.blockNumber > cb || (e.blockNumber === cb && e.logIndex > cl);
|
|
121
|
+
})
|
|
122
|
+
.sort(byBlockLogIndex);
|
|
123
|
+
const page = all.slice(0, limit);
|
|
124
|
+
const last = page[page.length - 1];
|
|
125
|
+
return {
|
|
126
|
+
events: page.map(slim),
|
|
127
|
+
nextCursor: last ? { blockNumber: last.blockNumber, logIndex: last.logIndex } : (cursor ?? null),
|
|
128
|
+
hasMore: all.length > page.length,
|
|
129
|
+
remaining: all.length,
|
|
130
|
+
cursor: cursor ?? null,
|
|
131
|
+
limit,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
// 索引目录/路径的唯一出口在 chain-indexer.ts (chainIndexDir / chainIndexPath) —— 这里不重复导出,
|
|
135
|
+
// 否则 index.ts 的 `export *` 会出现同名歧义 (ESM 下歧义名会被静默丢掉)。
|