@lawrenceliang-btc/atel-sdk 1.1.18 → 1.1.20
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/bin/atel.mjs +184 -107
- package/package.json +1 -1
package/bin/atel.mjs
CHANGED
|
@@ -5271,108 +5271,68 @@ async function cmdResult(taskId, resultJson) {
|
|
|
5271
5271
|
|
|
5272
5272
|
async function cmdCheck(targetDid, riskLevel, options) {
|
|
5273
5273
|
const risk = riskLevel || 'low';
|
|
5274
|
-
const chainMode = options?.chain || !!process.env.ATEL_SOLANA_RPC_URL;
|
|
5275
5274
|
const policy = loadPolicy();
|
|
5276
5275
|
const tp = policy.trustPolicy || DEFAULT_POLICY.trustPolicy;
|
|
5276
|
+
const RISK_THRESHOLDS = { low: 0, medium: 30, high: 50, critical: 75 };
|
|
5277
5277
|
|
|
5278
|
-
console.log(JSON.stringify({ event: 'checking_trust', did: targetDid, risk
|
|
5278
|
+
console.log(JSON.stringify({ event: 'checking_trust', did: targetDid, risk }));
|
|
5279
5279
|
|
|
5280
|
-
// 1.
|
|
5281
|
-
let
|
|
5282
|
-
let
|
|
5283
|
-
let
|
|
5280
|
+
// 1. Fetch agent profile from Platform (primary source of truth)
|
|
5281
|
+
let platformAgent = null;
|
|
5282
|
+
let platformScore = null;
|
|
5283
|
+
let platformReachable = true;
|
|
5284
5284
|
try {
|
|
5285
|
-
const r = await fetch(`${
|
|
5285
|
+
const r = await fetch(`${ATEL_PLATFORM}/registry/v1/agent/${encodeURIComponent(targetDid)}`, { signal: AbortSignal.timeout(5000) });
|
|
5286
|
+
if (r.ok) {
|
|
5287
|
+
platformAgent = await r.json();
|
|
5288
|
+
platformScore = platformAgent.trustScore;
|
|
5289
|
+
}
|
|
5290
|
+
} catch {
|
|
5291
|
+
platformReachable = false;
|
|
5292
|
+
}
|
|
5293
|
+
|
|
5294
|
+
// 2. Fetch trust history from Platform
|
|
5295
|
+
let trustEvents = [];
|
|
5296
|
+
try {
|
|
5297
|
+
const r = await fetch(`${ATEL_PLATFORM}/registry/v1/agent/${encodeURIComponent(targetDid)}/trust-history`, { signal: AbortSignal.timeout(5000) });
|
|
5286
5298
|
if (r.ok) {
|
|
5287
5299
|
const d = await r.json();
|
|
5288
|
-
|
|
5289
|
-
agentName = d.name;
|
|
5290
|
-
if (d.wallets) peerWallets = d.wallets;
|
|
5300
|
+
trustEvents = d.events || [];
|
|
5291
5301
|
}
|
|
5292
5302
|
} catch {}
|
|
5293
5303
|
|
|
5294
|
-
//
|
|
5304
|
+
// 3. Local interaction history (secondary/fallback)
|
|
5295
5305
|
const localHistoryFile = resolve(ATEL_DIR, 'trust-history.json');
|
|
5296
5306
|
let history = {};
|
|
5297
5307
|
try { history = JSON.parse(readFileSync(localHistoryFile, 'utf-8')); } catch {}
|
|
5298
5308
|
const agentHistory = history[targetDid] || { tasks: 0, successes: 0, failures: 0, lastSeen: null, proofs: [] };
|
|
5309
|
+
const localScore = computeTrustScore(agentHistory);
|
|
5299
5310
|
|
|
5300
|
-
//
|
|
5301
|
-
let
|
|
5302
|
-
|
|
5303
|
-
const
|
|
5304
|
-
|
|
5305
|
-
|
|
5306
|
-
|
|
5307
|
-
|
|
5308
|
-
|
|
5309
|
-
|
|
5310
|
-
|
|
5311
|
-
const
|
|
5312
|
-
|
|
5313
|
-
}
|
|
5314
|
-
history[targetDid] = agentHistory;
|
|
5315
|
-
try { writeFileSync(localHistoryFile, JSON.stringify(history, null, 2)); } catch {}
|
|
5316
|
-
}
|
|
5317
|
-
|
|
5318
|
-
// 3b. Query peer's wallet addresses on all three chains
|
|
5319
|
-
if (peerWallets) {
|
|
5320
|
-
console.log(JSON.stringify({ event: 'querying_chain_history', wallets: peerWallets }));
|
|
5321
|
-
|
|
5322
|
-
// Solana
|
|
5323
|
-
if (peerWallets.solana) {
|
|
5324
|
-
try {
|
|
5325
|
-
const rpcUrl = process.env.ATEL_SOLANA_RPC_URL || 'https://api.mainnet-beta.solana.com';
|
|
5326
|
-
const provider = new SolanaAnchorProvider({ rpcUrl });
|
|
5327
|
-
const records = await provider.queryByWallet(peerWallets.solana, { limit: 100, filterDid: targetDid });
|
|
5328
|
-
chainResults.solana = { wallet: peerWallets.solana, records: records.length, asExecutor: records.filter(r => r.executorDid === targetDid).length, asRequester: records.filter(r => r.requesterDid === targetDid).length };
|
|
5329
|
-
chainResults.totalRecords += records.length;
|
|
5330
|
-
chainResults.matchingDid += records.length;
|
|
5331
|
-
} catch (e) { chainResults.solana = { error: e.message }; }
|
|
5332
|
-
}
|
|
5333
|
-
|
|
5334
|
-
// Base
|
|
5335
|
-
if (peerWallets.base) {
|
|
5336
|
-
try {
|
|
5337
|
-
const { BaseAnchorProvider } = await import('@lawrenceliang-btc/atel-sdk');
|
|
5338
|
-
const baseRpc = process.env.ATEL_BASE_RPC_URL || 'https://mainnet.base.org';
|
|
5339
|
-
const provider = new BaseAnchorProvider({ rpcUrl: baseRpc });
|
|
5340
|
-
const explorerApi = process.env.ATEL_BASE_EXPLORER_API || 'https://api.basescan.org/api';
|
|
5341
|
-
const apiKey = process.env.ATEL_BASE_EXPLORER_KEY;
|
|
5342
|
-
const records = await provider.queryByWallet(peerWallets.base, explorerApi, apiKey, { limit: 100, filterDid: targetDid });
|
|
5343
|
-
chainResults.base = { wallet: peerWallets.base, records: records.length, asExecutor: records.filter(r => r.executorDid === targetDid).length, asRequester: records.filter(r => r.requesterDid === targetDid).length };
|
|
5344
|
-
chainResults.totalRecords += records.length;
|
|
5345
|
-
chainResults.matchingDid += records.length;
|
|
5346
|
-
} catch (e) { chainResults.base = { error: e.message }; }
|
|
5347
|
-
}
|
|
5348
|
-
|
|
5349
|
-
// BSC
|
|
5350
|
-
if (peerWallets.bsc) {
|
|
5351
|
-
try {
|
|
5352
|
-
const { BSCAnchorProvider } = await import('@lawrenceliang-btc/atel-sdk');
|
|
5353
|
-
const bscRpc = process.env.ATEL_BSC_RPC_URL || 'https://bsc-dataseed.binance.org';
|
|
5354
|
-
const provider = new BSCAnchorProvider({ rpcUrl: bscRpc });
|
|
5355
|
-
const explorerApi = process.env.ATEL_BSC_EXPLORER_API || 'https://api.bscscan.com/api';
|
|
5356
|
-
const apiKey = process.env.ATEL_BSC_EXPLORER_KEY;
|
|
5357
|
-
const records = await provider.queryByWallet(peerWallets.bsc, explorerApi, apiKey, { limit: 100, filterDid: targetDid });
|
|
5358
|
-
chainResults.bsc = { wallet: peerWallets.bsc, records: records.length, asExecutor: records.filter(r => r.executorDid === targetDid).length, asRequester: records.filter(r => r.requesterDid === targetDid).length };
|
|
5359
|
-
chainResults.totalRecords += records.length;
|
|
5360
|
-
chainResults.matchingDid += records.length;
|
|
5361
|
-
} catch (e) { chainResults.bsc = { error: e.message }; }
|
|
5311
|
+
// 4. Local TrustGraph info (supplementary)
|
|
5312
|
+
let graphInfo = null;
|
|
5313
|
+
try {
|
|
5314
|
+
const saved = JSON.parse(readFileSync(resolve(ATEL_DIR, 'trust-graph.json'), 'utf-8'));
|
|
5315
|
+
if (saved.interactions) {
|
|
5316
|
+
const tg = new TrustGraph();
|
|
5317
|
+
for (const i of saved.interactions) tg.recordInteraction(i);
|
|
5318
|
+
const directConns = saved.interactions.filter(
|
|
5319
|
+
i => i.from === targetDid || i.to === targetDid
|
|
5320
|
+
);
|
|
5321
|
+
if (directConns.length > 0) {
|
|
5322
|
+
const stats = tg.getStats();
|
|
5323
|
+
graphInfo = { directConnections: directConns.length, stats };
|
|
5362
5324
|
}
|
|
5363
5325
|
}
|
|
5326
|
+
} catch {}
|
|
5364
5327
|
|
|
5365
|
-
|
|
5366
|
-
|
|
5367
|
-
|
|
5368
|
-
|
|
5369
|
-
const computedScore = computeTrustScore(agentHistory);
|
|
5370
|
-
const trustLevel = computeTrustLevel(computedScore);
|
|
5328
|
+
// 5. Determine effective score: Platform is primary, local is fallback
|
|
5329
|
+
const effectiveScore = platformScore !== null ? platformScore : localScore;
|
|
5330
|
+
const scoreSource = platformScore !== null ? 'platform' : 'local';
|
|
5331
|
+
const trustLevel = computeTrustLevel(effectiveScore);
|
|
5371
5332
|
|
|
5372
|
-
//
|
|
5373
|
-
const threshold = tp.riskThresholds?.[risk] ?? 0;
|
|
5374
|
-
const
|
|
5375
|
-
const isNewAgent = agentHistory.tasks === 0;
|
|
5333
|
+
// 6. Apply trust policy (allow/deny decision)
|
|
5334
|
+
const threshold = RISK_THRESHOLDS[risk] ?? (tp.riskThresholds?.[risk] ?? 0);
|
|
5335
|
+
const isNewAgent = platformAgent === null && agentHistory.tasks === 0;
|
|
5376
5336
|
let decision = 'allow';
|
|
5377
5337
|
let reason = '';
|
|
5378
5338
|
|
|
@@ -5391,28 +5351,82 @@ async function cmdCheck(targetDid, riskLevel, options) {
|
|
|
5391
5351
|
reason = `Score ${effectiveScore} meets threshold ${threshold} for ${risk} risk`;
|
|
5392
5352
|
}
|
|
5393
5353
|
|
|
5354
|
+
// 7. Build human-readable output
|
|
5355
|
+
const lines = [];
|
|
5356
|
+
lines.push(`Trust Check: ${targetDid}`);
|
|
5357
|
+
if (platformAgent?.name) lines.push(` Name: ${platformAgent.name}`);
|
|
5358
|
+
lines.push(` Platform Score: ${effectiveScore} / 100${scoreSource === 'local' ? ' (fallback: local)' : ''}`);
|
|
5359
|
+
lines.push(` Decision: ${decision} (threshold: ${threshold} for ${risk} risk)`);
|
|
5360
|
+
if (reason) lines.push(` Reason: ${reason}`);
|
|
5361
|
+
|
|
5362
|
+
// Recent events from Platform
|
|
5363
|
+
if (trustEvents.length > 0) {
|
|
5364
|
+
lines.push(` Recent Events:`);
|
|
5365
|
+
for (const ev of trustEvents.slice(0, 10)) {
|
|
5366
|
+
const delta = ev.scoreDelta >= 0 ? `+${ev.scoreDelta}` : `${ev.scoreDelta}`;
|
|
5367
|
+
const date = ev.createdAt ? ev.createdAt.split('T')[0] : '';
|
|
5368
|
+
const ref = ev.referenceId || '';
|
|
5369
|
+
lines.push(` ${delta.padEnd(8)} ${ev.eventType.padEnd(22)} ${ref.padEnd(16)} ${date}`);
|
|
5370
|
+
}
|
|
5371
|
+
if (trustEvents.length > 10) lines.push(` ... and ${trustEvents.length - 10} more`);
|
|
5372
|
+
}
|
|
5373
|
+
|
|
5374
|
+
// Stats from Platform
|
|
5375
|
+
if (platformAgent?.stats) {
|
|
5376
|
+
const s = platformAgent.stats;
|
|
5377
|
+
const successPct = s.successRate != null ? `${Math.round(s.successRate * 100)}%` : 'n/a';
|
|
5378
|
+
lines.push(` Stats: ${s.totalTasks} tasks, ${successPct} success${s.avgRating ? `, avg rating: ${s.avgRating.toFixed(1)}` : ''}`);
|
|
5379
|
+
} else if (agentHistory.tasks > 0) {
|
|
5380
|
+
const successPct = agentHistory.tasks > 0 ? `${Math.round((agentHistory.successes / agentHistory.tasks) * 100)}%` : 'n/a';
|
|
5381
|
+
lines.push(` Stats: ${agentHistory.tasks} tasks, ${successPct} success (local)`);
|
|
5382
|
+
}
|
|
5383
|
+
|
|
5384
|
+
// Verified & Certification from Platform
|
|
5385
|
+
if (platformAgent) {
|
|
5386
|
+
lines.push(` Verified: ${platformAgent.verified || false}`);
|
|
5387
|
+
if (platformAgent.certification) {
|
|
5388
|
+
lines.push(` Certification: ${platformAgent.certification.level} (since ${platformAgent.certification.since})`);
|
|
5389
|
+
}
|
|
5390
|
+
if (platformAgent.boost?.active) {
|
|
5391
|
+
lines.push(` Boost: ${platformAgent.boost.tier} (active)`);
|
|
5392
|
+
}
|
|
5393
|
+
}
|
|
5394
|
+
|
|
5395
|
+
// Local TrustGraph supplementary info
|
|
5396
|
+
if (graphInfo) {
|
|
5397
|
+
lines.push(` Local Graph: ${graphInfo.directConnections} direct connection${graphInfo.directConnections !== 1 ? 's' : ''}`);
|
|
5398
|
+
}
|
|
5399
|
+
|
|
5400
|
+
// Fallback warning
|
|
5401
|
+
if (!platformReachable) {
|
|
5402
|
+
lines.push(` Warning: Platform unreachable, using local score as fallback`);
|
|
5403
|
+
}
|
|
5404
|
+
|
|
5405
|
+
// Print human-readable output
|
|
5406
|
+
console.log(lines.join('\n'));
|
|
5407
|
+
|
|
5408
|
+
// Also emit structured JSON for machine consumption
|
|
5394
5409
|
const output = {
|
|
5395
5410
|
did: targetDid,
|
|
5396
|
-
name:
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
|
|
5400
|
-
|
|
5401
|
-
|
|
5402
|
-
|
|
5403
|
-
|
|
5404
|
-
|
|
5405
|
-
|
|
5406
|
-
|
|
5407
|
-
|
|
5408
|
-
|
|
5409
|
-
|
|
5410
|
-
|
|
5411
|
-
policy: { risk, threshold, decision, reason },
|
|
5411
|
+
name: platformAgent?.name || null,
|
|
5412
|
+
score: effectiveScore,
|
|
5413
|
+
scoreSource,
|
|
5414
|
+
level: trustLevel.level,
|
|
5415
|
+
levelName: trustLevel.name,
|
|
5416
|
+
decision,
|
|
5417
|
+
risk,
|
|
5418
|
+
threshold,
|
|
5419
|
+
reason,
|
|
5420
|
+
verified: platformAgent?.verified || false,
|
|
5421
|
+
certification: platformAgent?.certification || null,
|
|
5422
|
+
stats: platformAgent?.stats || null,
|
|
5423
|
+
recentEvents: trustEvents.slice(0, 10),
|
|
5424
|
+
localGraph: graphInfo,
|
|
5425
|
+
platformReachable,
|
|
5412
5426
|
};
|
|
5413
|
-
if (
|
|
5414
|
-
|
|
5415
|
-
|
|
5427
|
+
if (localScore > 0 && scoreSource === 'platform') {
|
|
5428
|
+
output.localScore = localScore;
|
|
5429
|
+
}
|
|
5416
5430
|
console.log(JSON.stringify(output, null, 2));
|
|
5417
5431
|
}
|
|
5418
5432
|
|
|
@@ -6345,8 +6359,8 @@ async function cmdMilestoneFeedback(orderId) {
|
|
|
6345
6359
|
|
|
6346
6360
|
async function cmdMilestoneSubmit(orderId, indexStr) {
|
|
6347
6361
|
if (!orderId || indexStr === undefined) {
|
|
6348
|
-
console.error('Usage: atel milestone-submit <orderId> <index> --result "结果描述"');
|
|
6349
|
-
console.error(' atel milestone-submit <orderId> <index> --result ./file.pdf [--hash 0x...]');
|
|
6362
|
+
console.error('Usage: atel milestone-submit <orderId> <index> --result "结果描述" [--file <path>]');
|
|
6363
|
+
console.error(' atel milestone-submit <orderId> <index> --result ./file.pdf [--hash 0x...] [--file <path>]');
|
|
6350
6364
|
process.exit(1);
|
|
6351
6365
|
}
|
|
6352
6366
|
const resultIdx = rawArgs.findIndex(a => a === '--result');
|
|
@@ -6380,11 +6394,35 @@ async function cmdMilestoneSubmit(orderId, indexStr) {
|
|
|
6380
6394
|
resultHash = ethers.keccak256(ethers.toUtf8Bytes(result));
|
|
6381
6395
|
}
|
|
6382
6396
|
|
|
6383
|
-
|
|
6397
|
+
// --file support: upload attachment before submitting
|
|
6398
|
+
let resultText = result;
|
|
6399
|
+
const filePath = rawArgs.find((a, i) => rawArgs[i - 1] === '--file');
|
|
6400
|
+
if (filePath) {
|
|
6401
|
+
const { execFileSync } = await import('child_process');
|
|
6402
|
+
const path = await import('path');
|
|
6403
|
+
try {
|
|
6404
|
+
const id = requireIdentity();
|
|
6405
|
+
const uploadResult = execFileSync('curl', ['-s', '-X', 'POST',
|
|
6406
|
+
`${PLATFORM_URL}/attachment/v1/upload`,
|
|
6407
|
+
'-F', `file=@${filePath}`,
|
|
6408
|
+
'-F', 'kind=file',
|
|
6409
|
+
'-F', `uploadedBy=${id.did}`
|
|
6410
|
+
], { encoding: 'utf8' });
|
|
6411
|
+
const uploadData = JSON.parse(uploadResult);
|
|
6412
|
+
if (uploadData.attachmentId) {
|
|
6413
|
+
resultText += `\n[Attachment: ${uploadData.attachmentId} (${path.basename(filePath)})]`;
|
|
6414
|
+
console.error(`File uploaded: ${uploadData.attachmentId}`);
|
|
6415
|
+
}
|
|
6416
|
+
} catch (e) {
|
|
6417
|
+
console.error(`File upload failed: ${e.message}`);
|
|
6418
|
+
}
|
|
6419
|
+
}
|
|
6420
|
+
|
|
6421
|
+
console.log(`Submitting M${indexStr}: "${resultText.slice(0, 60)}${resultText.length > 60 ? '...' : ''}"`);
|
|
6384
6422
|
console.log(`Hash: ${resultHash}`);
|
|
6385
6423
|
|
|
6386
6424
|
const data = await signedFetch('POST', `/trade/v1/order/${orderId}/milestone/${indexStr}/submit`, {
|
|
6387
|
-
resultSummary:
|
|
6425
|
+
resultSummary: resultText,
|
|
6388
6426
|
resultHash,
|
|
6389
6427
|
});
|
|
6390
6428
|
console.log(JSON.stringify(data, null, 2));
|
|
@@ -6475,10 +6513,34 @@ async function cmdDispute(orderId, reason, description) {
|
|
|
6475
6513
|
}
|
|
6476
6514
|
|
|
6477
6515
|
async function cmdEvidence(disputeId, evidenceJson) {
|
|
6478
|
-
if (!disputeId || !evidenceJson) { console.error('Usage: atel evidence <disputeId> <json>'); process.exit(1); }
|
|
6516
|
+
if (!disputeId || !evidenceJson) { console.error('Usage: atel evidence <disputeId> <json> [--file <path>]'); process.exit(1); }
|
|
6479
6517
|
let evidence;
|
|
6480
6518
|
try { evidence = JSON.parse(evidenceJson); } catch { console.error('Invalid JSON'); process.exit(1); }
|
|
6481
6519
|
|
|
6520
|
+
// --file support: upload attachment and attach to evidence
|
|
6521
|
+
const filePath = rawArgs.find((a, i) => rawArgs[i - 1] === '--file');
|
|
6522
|
+
if (filePath) {
|
|
6523
|
+
const { execFileSync } = await import('child_process');
|
|
6524
|
+
const path = await import('path');
|
|
6525
|
+
try {
|
|
6526
|
+
const id = requireIdentity();
|
|
6527
|
+
const uploadResult = execFileSync('curl', ['-s', '-X', 'POST',
|
|
6528
|
+
`${PLATFORM_URL}/attachment/v1/upload`,
|
|
6529
|
+
'-F', `file=@${filePath}`,
|
|
6530
|
+
'-F', 'kind=file',
|
|
6531
|
+
'-F', `uploadedBy=${id.did}`
|
|
6532
|
+
], { encoding: 'utf8' });
|
|
6533
|
+
const uploadData = JSON.parse(uploadResult);
|
|
6534
|
+
if (uploadData.attachmentId) {
|
|
6535
|
+
evidence.attachmentId = uploadData.attachmentId;
|
|
6536
|
+
evidence.attachmentName = path.basename(filePath);
|
|
6537
|
+
console.error(`File uploaded: ${uploadData.attachmentId}`);
|
|
6538
|
+
}
|
|
6539
|
+
} catch (e) {
|
|
6540
|
+
console.error(`File upload failed: ${e.message}`);
|
|
6541
|
+
}
|
|
6542
|
+
}
|
|
6543
|
+
|
|
6482
6544
|
// Submit to Platform API
|
|
6483
6545
|
const data = await signedFetch('POST', `/dispute/v1/${disputeId}/evidence`, { evidence });
|
|
6484
6546
|
|
|
@@ -6534,6 +6596,21 @@ async function cmdCertStatus(did) {
|
|
|
6534
6596
|
const text = await res.text(); console.error("DEBUG Response:", text); const data = JSON.parse(text);
|
|
6535
6597
|
if (!res.ok) throw new Error(data.error || `HTTP ${res.status}`);
|
|
6536
6598
|
console.log(JSON.stringify(data, null, 2));
|
|
6599
|
+
|
|
6600
|
+
// Fetch and display certification requirements
|
|
6601
|
+
try {
|
|
6602
|
+
const reqResp = await fetch(`${PLATFORM_URL}/cert/v1/requirements`, { signal: AbortSignal.timeout(5000) });
|
|
6603
|
+
if (reqResp.ok) {
|
|
6604
|
+
const reqs = await reqResp.json();
|
|
6605
|
+
console.log('\nCertification Requirements:');
|
|
6606
|
+
if (reqs.certified) {
|
|
6607
|
+
console.log(` Certified: trust_score >= ${reqs.certified.minTrustScore}, cost: $${reqs.certified.cost}`);
|
|
6608
|
+
}
|
|
6609
|
+
if (reqs.enterprise) {
|
|
6610
|
+
console.log(` Enterprise: trust_score >= ${reqs.enterprise.minTrustScore}, cost: $${reqs.enterprise.cost}`);
|
|
6611
|
+
}
|
|
6612
|
+
}
|
|
6613
|
+
} catch {}
|
|
6537
6614
|
}
|
|
6538
6615
|
|
|
6539
6616
|
async function cmdCertRenew(level) {
|