@lawrenceliang-btc/atel-sdk 1.1.17 → 1.1.19

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.
Files changed (2) hide show
  1. package/bin/atel.mjs +137 -119
  2. package/package.json +1 -1
package/bin/atel.mjs CHANGED
@@ -3681,23 +3681,25 @@ ${callbackFailed}
3681
3681
  if (localAction.ok && !localAction.skipped) {
3682
3682
  // Guard: if agent hook already submitted via its own shell command during execution,
3683
3683
  // the milestone status will have changed. Re-check before double-submitting.
3684
- if (['milestone_rejected', 'milestone_verified', 'milestone_plan_confirmed'].includes(hookEvent)) {
3685
- const guardCmd = localAction.action?.command;
3686
- if (Array.isArray(guardCmd) && guardCmd[0] === 'atel' && guardCmd[1] === 'milestone-submit' && guardCmd[2]) {
3687
- try {
3688
- const guardResp = await fetch(`${PLATFORM_URL}/trade/v1/order/${guardCmd[2]}/milestones`, { signal: AbortSignal.timeout(8000) });
3689
- if (guardResp.ok) {
3690
- const guardState = await guardResp.json();
3691
- const guardIdx = Number.parseInt(String(guardCmd[3]), 10);
3692
- const guardMs = Array.isArray(guardState?.milestones) ? guardState.milestones.find(m => m.index === guardIdx) : null;
3693
- if (guardMs && guardMs.status === 'submitted') {
3694
- log({ event: 'agent_cmd_done', eventType: hookEvent, mode: 'already_submitted_by_agent', dedupeKey: hookKey });
3695
- finishHook();
3696
- return;
3697
- }
3698
- }
3699
- } catch {}
3700
- }
3684
+ const guardCmd = localAction.action?.command;
3685
+ const needsGuard = ['milestone_rejected', 'milestone_verified', 'milestone_plan_confirmed'].includes(hookEvent)
3686
+ && Array.isArray(guardCmd) && guardCmd[0] === 'atel' && guardCmd[1] === 'milestone-submit' && guardCmd[2];
3687
+ const guardCheck = needsGuard
3688
+ ? fetch(`${PLATFORM_URL}/trade/v1/order/${guardCmd[2]}/milestones`, { signal: AbortSignal.timeout(8000) })
3689
+ .then(r => r.ok ? r.json() : null)
3690
+ .then(state => {
3691
+ if (!state) return false;
3692
+ const idx = Number.parseInt(String(guardCmd[3]), 10);
3693
+ const ms = Array.isArray(state?.milestones) ? state.milestones.find(m => m.index === idx) : null;
3694
+ return ms && ms.status === 'submitted';
3695
+ })
3696
+ .catch(() => false)
3697
+ : Promise.resolve(false);
3698
+ guardCheck.then(alreadySubmitted => {
3699
+ if (alreadySubmitted) {
3700
+ log({ event: 'agent_cmd_done', eventType: hookEvent, mode: 'already_submitted_by_agent', dedupeKey: hookKey });
3701
+ finishHook();
3702
+ return;
3701
3703
  }
3702
3704
  executeRecommendedActionDirect(hookEvent, localAction.action, hookCwd || process.cwd(), hookKey)
3703
3705
  .then((execResult) => {
@@ -3713,6 +3715,8 @@ ${callbackFailed}
3713
3715
  finishHook();
3714
3716
  });
3715
3717
  return;
3718
+ }); // guardCheck.then
3719
+ return;
3716
3720
  }
3717
3721
 
3718
3722
  log({ event: 'agent_cmd_done', eventType: hookEvent, stdout: summarizeAgentOutput(stdout, 300) });
@@ -5267,108 +5271,68 @@ async function cmdResult(taskId, resultJson) {
5267
5271
 
5268
5272
  async function cmdCheck(targetDid, riskLevel, options) {
5269
5273
  const risk = riskLevel || 'low';
5270
- const chainMode = options?.chain || !!process.env.ATEL_SOLANA_RPC_URL;
5271
5274
  const policy = loadPolicy();
5272
5275
  const tp = policy.trustPolicy || DEFAULT_POLICY.trustPolicy;
5276
+ const RISK_THRESHOLDS = { low: 0, medium: 30, high: 50, critical: 75 };
5273
5277
 
5274
- console.log(JSON.stringify({ event: 'checking_trust', did: targetDid, risk, mode: chainMode ? 'chain-verified' : 'local-only' }));
5278
+ console.log(JSON.stringify({ event: 'checking_trust', did: targetDid, risk }));
5279
+
5280
+ // 1. Fetch agent profile from Platform (primary source of truth)
5281
+ let platformAgent = null;
5282
+ let platformScore = null;
5283
+ let platformReachable = true;
5284
+ try {
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
+ }
5275
5293
 
5276
- // 1. Get Registry info (reference only, includes wallets)
5277
- let registryScore = null;
5278
- let agentName = null;
5279
- let peerWallets = null;
5294
+ // 2. Fetch trust history from Platform
5295
+ let trustEvents = [];
5280
5296
  try {
5281
- const r = await fetch(`${REGISTRY_URL}/registry/v1/agent/${encodeURIComponent(targetDid)}`, { signal: AbortSignal.timeout(5000) });
5297
+ const r = await fetch(`${ATEL_PLATFORM}/registry/v1/agent/${encodeURIComponent(targetDid)}/trust-history`, { signal: AbortSignal.timeout(5000) });
5282
5298
  if (r.ok) {
5283
5299
  const d = await r.json();
5284
- registryScore = d.trustScore;
5285
- agentName = d.name;
5286
- if (d.wallets) peerWallets = d.wallets;
5300
+ trustEvents = d.events || [];
5287
5301
  }
5288
5302
  } catch {}
5289
5303
 
5290
- // 2. Local interaction history
5304
+ // 3. Local interaction history (secondary/fallback)
5291
5305
  const localHistoryFile = resolve(ATEL_DIR, 'trust-history.json');
5292
5306
  let history = {};
5293
5307
  try { history = JSON.parse(readFileSync(localHistoryFile, 'utf-8')); } catch {}
5294
5308
  const agentHistory = history[targetDid] || { tasks: 0, successes: 0, failures: 0, lastSeen: null, proofs: [] };
5309
+ const localScore = computeTrustScore(agentHistory);
5295
5310
 
5296
- // 3. Chain-verified mode: query all three chains by wallet address
5297
- let chainVerification = null;
5298
- if (chainMode) {
5299
- const chainResults = { solana: null, base: null, bsc: null, totalRecords: 0, matchingDid: 0 };
5300
-
5301
- // 3a. Verify unverified local proofs on-chain
5302
- const unverifiedProofs = agentHistory.proofs.filter(p => !p.verified && p.anchor_tx);
5303
- if (unverifiedProofs.length > 0) {
5304
- console.log(JSON.stringify({ event: 'verifying_local_proofs', count: unverifiedProofs.length }));
5305
- const result = await verifyAnchorTxList(unverifiedProofs, targetDid);
5306
- for (const vp of result.proofs) {
5307
- const existing = agentHistory.proofs.find(p => p.anchor_tx === vp.anchor_tx);
5308
- if (existing) existing.verified = true;
5309
- }
5310
- history[targetDid] = agentHistory;
5311
- try { writeFileSync(localHistoryFile, JSON.stringify(history, null, 2)); } catch {}
5312
- }
5313
-
5314
- // 3b. Query peer's wallet addresses on all three chains
5315
- if (peerWallets) {
5316
- console.log(JSON.stringify({ event: 'querying_chain_history', wallets: peerWallets }));
5317
-
5318
- // Solana
5319
- if (peerWallets.solana) {
5320
- try {
5321
- const rpcUrl = process.env.ATEL_SOLANA_RPC_URL || 'https://api.mainnet-beta.solana.com';
5322
- const provider = new SolanaAnchorProvider({ rpcUrl });
5323
- const records = await provider.queryByWallet(peerWallets.solana, { limit: 100, filterDid: targetDid });
5324
- chainResults.solana = { wallet: peerWallets.solana, records: records.length, asExecutor: records.filter(r => r.executorDid === targetDid).length, asRequester: records.filter(r => r.requesterDid === targetDid).length };
5325
- chainResults.totalRecords += records.length;
5326
- chainResults.matchingDid += records.length;
5327
- } catch (e) { chainResults.solana = { error: e.message }; }
5328
- }
5329
-
5330
- // Base
5331
- if (peerWallets.base) {
5332
- try {
5333
- const { BaseAnchorProvider } = await import('@lawrenceliang-btc/atel-sdk');
5334
- const baseRpc = process.env.ATEL_BASE_RPC_URL || 'https://mainnet.base.org';
5335
- const provider = new BaseAnchorProvider({ rpcUrl: baseRpc });
5336
- const explorerApi = process.env.ATEL_BASE_EXPLORER_API || 'https://api.basescan.org/api';
5337
- const apiKey = process.env.ATEL_BASE_EXPLORER_KEY;
5338
- const records = await provider.queryByWallet(peerWallets.base, explorerApi, apiKey, { limit: 100, filterDid: targetDid });
5339
- chainResults.base = { wallet: peerWallets.base, records: records.length, asExecutor: records.filter(r => r.executorDid === targetDid).length, asRequester: records.filter(r => r.requesterDid === targetDid).length };
5340
- chainResults.totalRecords += records.length;
5341
- chainResults.matchingDid += records.length;
5342
- } catch (e) { chainResults.base = { error: e.message }; }
5343
- }
5344
-
5345
- // BSC
5346
- if (peerWallets.bsc) {
5347
- try {
5348
- const { BSCAnchorProvider } = await import('@lawrenceliang-btc/atel-sdk');
5349
- const bscRpc = process.env.ATEL_BSC_RPC_URL || 'https://bsc-dataseed.binance.org';
5350
- const provider = new BSCAnchorProvider({ rpcUrl: bscRpc });
5351
- const explorerApi = process.env.ATEL_BSC_EXPLORER_API || 'https://api.bscscan.com/api';
5352
- const apiKey = process.env.ATEL_BSC_EXPLORER_KEY;
5353
- const records = await provider.queryByWallet(peerWallets.bsc, explorerApi, apiKey, { limit: 100, filterDid: targetDid });
5354
- chainResults.bsc = { wallet: peerWallets.bsc, records: records.length, asExecutor: records.filter(r => r.executorDid === targetDid).length, asRequester: records.filter(r => r.requesterDid === targetDid).length };
5355
- chainResults.totalRecords += records.length;
5356
- chainResults.matchingDid += records.length;
5357
- } 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 };
5358
5324
  }
5359
5325
  }
5326
+ } catch {}
5360
5327
 
5361
- chainVerification = chainResults;
5362
- }
5363
-
5364
- // 4. Compute unified trust score and level
5365
- const computedScore = computeTrustScore(agentHistory);
5366
- 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);
5367
5332
 
5368
- // 5. Apply trust policy
5369
- const threshold = tp.riskThresholds?.[risk] ?? 0;
5370
- const effectiveScore = computedScore > 0 ? computedScore : (registryScore || 0);
5371
- 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;
5372
5336
  let decision = 'allow';
5373
5337
  let reason = '';
5374
5338
 
@@ -5387,28 +5351,82 @@ async function cmdCheck(targetDid, riskLevel, options) {
5387
5351
  reason = `Score ${effectiveScore} meets threshold ${threshold} for ${risk} risk`;
5388
5352
  }
5389
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
5390
5409
  const output = {
5391
5410
  did: targetDid,
5392
- name: agentName,
5393
- mode: chainMode ? 'chain-verified' : 'local-only',
5394
- trust: {
5395
- computed_score: computedScore,
5396
- registry_score: registryScore,
5397
- effective_score: effectiveScore,
5398
- level: trustLevel.level,
5399
- level_name: trustLevel.name,
5400
- max_risk: trustLevel.maxRisk,
5401
- total_tasks: agentHistory.tasks,
5402
- successes: agentHistory.successes,
5403
- failures: agentHistory.failures,
5404
- verified_proofs: agentHistory.proofs.filter(p => p.verified).length,
5405
- total_proofs: agentHistory.proofs.length,
5406
- },
5407
- 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,
5408
5426
  };
5409
- if (chainVerification) output.chain_verification = chainVerification;
5410
- if (!chainMode) output.note = 'Local-only mode: score based on direct interaction history only. Set ATEL_SOLANA_RPC_URL or use --chain for on-chain verification.';
5411
-
5427
+ if (localScore > 0 && scoreSource === 'platform') {
5428
+ output.localScore = localScore;
5429
+ }
5412
5430
  console.log(JSON.stringify(output, null, 2));
5413
5431
  }
5414
5432
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lawrenceliang-btc/atel-sdk",
3
- "version": "1.1.17",
3
+ "version": "1.1.19",
4
4
  "description": "ATEL Protocol SDK - Agent Trust & Exchange Layer",
5
5
  "repository": {
6
6
  "type": "git",