@lawrenceliang-btc/atel-sdk 1.2.13 → 1.2.14

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 CHANGED
@@ -61,12 +61,12 @@ import {
61
61
  createMessage, verifyMessage, parseDID, RegistryClient, ExecutionTrace, ProofGenerator,
62
62
  SolanaAnchorProvider, BaseAnchorProvider, BSCAnchorProvider,
63
63
  autoNetworkSetup, collectCandidates, connectToAgent,
64
- discoverPublicIP, checkReachable, ContentAuditor, TrustScoreClient,
64
+ discoverPublicIP, checkReachable, verifyPortReachable, ContentAuditor, TrustScoreClient,
65
65
  RollbackManager, rotateKey, verifyKeyRotation, ToolGateway, PolicyEngine, mintConsentToken, sign,
66
66
  TrustGraph, calculateTaskWeight,
67
67
  } from '@lawrenceliang-btc/atel-sdk';
68
68
  import { TunnelManager, HeartbeatManager } from './tunnel-manager.mjs';
69
- import { buildAgentCallbackAction, getDirectExecutableActions, normalizeGatewayBind, shouldSkipAgentHook, shouldUseGatewaySession } from './notification-action-helpers.mjs';
69
+ import { buildAgentCallbackAction, explainDirectExecutionSkip, getDirectExecutableActions, normalizeGatewayBind, shouldSkipAgentHook, shouldUseGatewaySession } from './notification-action-helpers.mjs';
70
70
  import { parseOrderCancelArgs, preflightOrderCancel } from './order-cancel-helpers.mjs';
71
71
  // ollama-manager removed — SDK does not run local models
72
72
  const initializeOllama = async () => {};
@@ -1118,12 +1118,26 @@ async function pushTradeNotification(eventType, payload, body) {
1118
1118
  if (c === 'bsc') return ' (BSC)';
1119
1119
  return '';
1120
1120
  };
1121
+ const autoAcceptReasonText = (reason) => {
1122
+ if (reason === 'missing_recommended_actions') return '平台未提供可执行接单动作';
1123
+ if (reason === 'missing_accept_action') return '事件里没有 accept 动作';
1124
+ if (reason === 'task_mode_not_auto') return '当前 taskMode 不是 auto';
1125
+ if (reason === 'auto_accept_platform_disabled') return '当前未启用免费单自动接单';
1126
+ if (reason === 'paid_auto_accept_disabled') return '当前未启用付费单自动接单';
1127
+ if (reason === 'price_exceeds_accept_max') return '订单金额超过自动接单上限';
1128
+ return reason || '未说明';
1129
+ };
1130
+
1121
1131
  const templates = {
1122
1132
  'order_created': (p) => `📥 收到新订单
1123
1133
  订单: ${p.orderId || body?.orderId || '?'}
1124
1134
  金额: $${p.priceAmount ?? '?'} USDC
1125
1135
  来自: ${p.requesterDid || '未知请求方'}
1126
1136
  请审核后决定是否接单`,
1137
+ 'order_created_auto_accept_skipped': (p) => `⏸️ 未自动接单
1138
+ 订单: ${p.orderId || body?.orderId || '?'}
1139
+ 原因: ${autoAcceptReasonText(p.reasonCode)}
1140
+ 请人工判断是否接单`,
1127
1141
  'order_accepted': (p) => `📋 订单已被接单
1128
1142
  订单: ${p.orderId || body?.orderId || '?'}
1129
1143
  执行方已开始处理,进入里程碑阶段`,
@@ -1176,7 +1190,8 @@ async function pushTradeNotification(eventType, payload, body) {
1176
1190
  订单: ${p.orderId || body?.orderId || '?'}
1177
1191
  原因: ${p.reason || '未说明'}`,
1178
1192
  'order_expired': (p) => `⌛ 订单已过期
1179
- 订单: ${p.orderId || body?.orderId || '?'}
1193
+ 订单: ${p.orderId || p.order_id || body?.orderId || body?.order_id || '?'}
1194
+ 原因: ${p.reason || '未说明'}
1180
1195
  系统已自动结束该订单`,
1181
1196
  'dispute_created': (p) => `⚖️ 争议已创建
1182
1197
  订单: ${p.orderId || body?.orderId || '?'}
@@ -2200,9 +2215,8 @@ async function getWalletAddresses() {
2200
2215
  function detectPreferredChain() {
2201
2216
  const config = loadAnchorConfig();
2202
2217
  if (config?.preferredChain) return config.preferredChain;
2203
- if (getChainPrivateKey('bsc')) return 'bsc';
2204
2218
  if (getChainPrivateKey('base')) return 'base';
2205
- if (getChainPrivateKey('solana')) return 'solana';
2219
+ if (getChainPrivateKey('bsc')) return 'bsc';
2206
2220
  return null;
2207
2221
  }
2208
2222
 
@@ -2312,6 +2326,12 @@ function addFriend(did, options = {}) {
2312
2326
 
2313
2327
  saveFriends(data);
2314
2328
  log({ event: 'friend_added', did, addedBy: options.addedBy });
2329
+ syncContactToPlatform(did, { alias: options.alias || '', notes: options.notes || '' }).catch(() => {});
2330
+ pushP2PNotification('p2p_contact_added', {
2331
+ peerDid: did,
2332
+ alias: options.alias || '',
2333
+ text: options.notes || ''
2334
+ }).catch((e) => log({ event: 'p2p_notify_error', kind: 'friend_added', error: e.message }));
2315
2335
  return true;
2316
2336
  }
2317
2337
 
@@ -3125,7 +3145,7 @@ async function configureAnchor() {
3125
3145
  // 1. Select chain
3126
3146
  const chain = await promptChoice(
3127
3147
  'Select blockchain for anchoring:',
3128
- ['solana', 'bsc', 'base']
3148
+ ['base', 'bsc']
3129
3149
  );
3130
3150
 
3131
3151
  // 2. Input private key
@@ -3667,6 +3687,15 @@ async function cmdStart(port) {
3667
3687
  log({ event: 'atel_skill_sync_error', error: e.message });
3668
3688
  }
3669
3689
 
3690
+ try {
3691
+ const syncedContacts = await syncAllFriendsToPlatform();
3692
+ if (syncedContacts.attempted > 0) {
3693
+ log({ event: 'contacts_backfill_sync_done', ...syncedContacts });
3694
+ }
3695
+ } catch (e) {
3696
+ log({ event: 'contacts_backfill_sync_error', error: e.message });
3697
+ }
3698
+
3670
3699
  // Initialize Ollama only if explicitly enabled (optional local AI audit)
3671
3700
  if (process.env.ATEL_OLLAMA_ENABLED === 'true') {
3672
3701
  await initializeOllama().catch(err => {
@@ -4024,6 +4053,22 @@ async function cmdStart(port) {
4024
4053
  const MAX_HOOK_CONCURRENCY = Math.max(1, Math.min(4, Number.parseInt(process.env.ATEL_HOOK_CONCURRENCY || '3', 10) || 3));
4025
4054
  const hookQueue = [];
4026
4055
  const activeRecoveryKeys = new Set();
4056
+ const recoveryKeyLogState = new Map();
4057
+
4058
+ function logRecoveryKeyActive(eventType, dedupeKey, recoveryKey) {
4059
+ if (!recoveryKey) return;
4060
+ const now = Date.now();
4061
+ const previous = recoveryKeyLogState.get(recoveryKey) || { lastLoggedAt: 0, suppressed: 0 };
4062
+ if (now - previous.lastLoggedAt < 15000) {
4063
+ previous.suppressed += 1;
4064
+ recoveryKeyLogState.set(recoveryKey, previous);
4065
+ return;
4066
+ }
4067
+ const payload = { event: 'agent_hook_not_queued', eventType, dedupeKey, reason: 'recovery_key_active', recoveryKey };
4068
+ if (previous.suppressed > 0) payload.suppressed = previous.suppressed;
4069
+ log(payload);
4070
+ recoveryKeyLogState.set(recoveryKey, { lastLoggedAt: now, suppressed: 0 });
4071
+ }
4027
4072
 
4028
4073
  endpoint.app?.post?.('/atel/v1/agent-callback', async (req, res) => {
4029
4074
  const body = req.body || {};
@@ -4609,7 +4654,7 @@ Format:
4609
4654
  const recoveryKey = options.recoveryKey || '';
4610
4655
  if (recoveryKey) {
4611
4656
  if (activeRecoveryKeys.has(recoveryKey)) {
4612
- log({ event: 'agent_hook_not_queued', eventType, dedupeKey, reason: 'recovery_key_active', recoveryKey });
4657
+ logRecoveryKeyActive(eventType, dedupeKey, recoveryKey);
4613
4658
  return false;
4614
4659
  }
4615
4660
  activeRecoveryKeys.add(recoveryKey);
@@ -5143,6 +5188,22 @@ Advance the current milestone strictly based on these approved results. Do not i
5143
5188
  let directExecutionSucceeded = false;
5144
5189
  const rejectLimitReached = event === 'milestone_rejected' && Number(payload?.submitCount || body?.submitCount || 0) >= 3;
5145
5190
  const directActions = rejectLimitReached ? [] : getDirectExecutableActions(event, recommendedActions, payload, currentPolicy);
5191
+ if (event === 'order_created' && directActions.length === 0 && !rejectLimitReached) {
5192
+ const skipReason = explainDirectExecutionSkip(event, recommendedActions, payload, currentPolicy);
5193
+ if (skipReason) {
5194
+ log({
5195
+ event: 'order_created_auto_accept_skipped',
5196
+ orderId: payload?.orderId || body?.orderId || '',
5197
+ amount: Number(payload?.priceAmount || 0),
5198
+ reason: skipReason,
5199
+ });
5200
+ pushTradeNotification('order_created_auto_accept_skipped', {
5201
+ ...payload,
5202
+ orderId: payload?.orderId || body?.orderId || '',
5203
+ reasonCode: skipReason,
5204
+ }, body).catch(e => log({ event: 'trade_notify_error', error: e.message }));
5205
+ }
5206
+ }
5146
5207
  if (rejectLimitReached) {
5147
5208
  log({ event: 'direct_action_skip_manual_arbitration', eventType: event, dedupeKey, orderId: payload?.orderId || body?.orderId || '', milestoneIndex: payload?.milestoneIndex ?? body?.milestoneIndex ?? null, reason: 'rejection_limit_reached' });
5148
5209
  }
@@ -5222,7 +5283,10 @@ Advance the current milestone strictly based on these approved results. Do not i
5222
5283
  }
5223
5284
  const { execFile } = await import('child_process');
5224
5285
  const finishHook = () => {
5225
- if (recoveryKey) activeRecoveryKeys.delete(recoveryKey);
5286
+ if (recoveryKey) {
5287
+ activeRecoveryKeys.delete(recoveryKey);
5288
+ recoveryKeyLogState.delete(recoveryKey);
5289
+ }
5226
5290
  activeHookWorkers = Math.max(0, activeHookWorkers - 1);
5227
5291
  processHookQueue();
5228
5292
  };
@@ -7293,6 +7357,42 @@ async function cmdRotate() {
7293
7357
 
7294
7358
  const PLATFORM_URL = ATEL_PLATFORM;
7295
7359
 
7360
+ async function syncContactToPlatform(contactDid, options = {}) {
7361
+ const id = requireIdentity();
7362
+ const normalized = String(contactDid || '').trim();
7363
+ if (!normalized || normalized === id.did) return { ok: false, reason: 'invalid_contact' };
7364
+ try {
7365
+ await signedFetch('POST', '/contacts/v1/sync', {
7366
+ contactDid: normalized,
7367
+ alias: String(options.alias || '').trim(),
7368
+ notes: String(options.notes || '').trim(),
7369
+ });
7370
+ log({ event: 'contact_sync_ok', contactDid: normalized });
7371
+ return { ok: true };
7372
+ } catch (e) {
7373
+ log({ event: 'contact_sync_failed', contactDid: normalized, error: e.message || 'unknown_error' });
7374
+ return { ok: false, reason: e.message || 'sync_failed' };
7375
+ }
7376
+ }
7377
+
7378
+ async function syncAllFriendsToPlatform() {
7379
+ const friends = loadFriends();
7380
+ const accepted = Array.isArray(friends?.friends) ? friends.friends : [];
7381
+ if (accepted.length === 0) return { attempted: 0, synced: 0, failed: 0 };
7382
+ let synced = 0;
7383
+ let failed = 0;
7384
+ for (const friend of accepted) {
7385
+ const result = await syncContactToPlatform(friend.did, {
7386
+ alias: friend.alias || '',
7387
+ notes: friend.notes || ''
7388
+ });
7389
+ if (result.ok) synced += 1;
7390
+ else failed += 1;
7391
+ }
7392
+ log({ event: 'contacts_backfill_sync', attempted: accepted.length, synced, failed });
7393
+ return { attempted: accepted.length, synced, failed };
7394
+ }
7395
+
7296
7396
  async function signedFetch(method, path, payload = {}) {
7297
7397
  const id = requireIdentity();
7298
7398
  const { default: nacl } = await import('tweetnacl');
@@ -10558,7 +10658,7 @@ Auth Commands:
10558
10658
 
10559
10659
  Account Commands:
10560
10660
  balance Show platform account balance
10561
- deposit <amount> [channel] Deposit funds (channel: manual|crypto_solana|crypto_base|crypto_bsc|stripe|alipay)
10661
+ deposit <amount> [channel] Deposit funds (channel: manual|crypto_base|crypto_bsc|stripe|alipay)
10562
10662
  withdraw <amount> [channel] [address] Withdraw funds (address required for crypto)
10563
10663
  transactions List payment history
10564
10664
 
@@ -1,3 +1,26 @@
1
+ export function explainDirectExecutionSkip(eventType, recommendedActions, payload = {}, policy = {}) {
2
+ if (eventType !== 'order_created') return '';
3
+ if (!Array.isArray(recommendedActions) || recommendedActions.length === 0) return 'missing_recommended_actions';
4
+ const hasAcceptAction = recommendedActions.some((action) =>
5
+ action?.type === 'cli' &&
6
+ action?.action === 'accept' &&
7
+ Array.isArray(action.command) &&
8
+ action.command[0] === 'atel'
9
+ );
10
+ if (!hasAcceptAction) return 'missing_accept_action';
11
+ const amount = Number(payload?.priceAmount || 0);
12
+ const autoPolicy = policy?.autoPolicy || {};
13
+ const acceptMaxAmount = Number(autoPolicy.acceptMaxAmount || 0);
14
+ if (amount <= 0) {
15
+ if (policy?.taskMode !== 'auto') return 'task_mode_not_auto';
16
+ if (policy?.autoAcceptPlatform !== true) return 'auto_accept_platform_disabled';
17
+ return '';
18
+ }
19
+ if (autoPolicy.acceptOrders !== true) return 'paid_auto_accept_disabled';
20
+ if (acceptMaxAmount > 0 && amount > acceptMaxAmount) return 'price_exceeds_accept_max';
21
+ return '';
22
+ }
23
+
1
24
  export function getDirectExecutableActions(eventType, recommendedActions, payload = {}, policy = {}) {
2
25
  if (!Array.isArray(recommendedActions) || recommendedActions.length === 0) return [];
3
26
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lawrenceliang-btc/atel-sdk",
3
- "version": "1.2.13",
3
+ "version": "1.2.14",
4
4
  "description": "ATEL Protocol SDK - Agent Trust & Exchange Layer",
5
5
  "repository": {
6
6
  "type": "git",