@lawrenceliang-btc/atel-sdk 0.8.7

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 (75) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +221 -0
  3. package/bin/atel.mjs +2692 -0
  4. package/bin/tunnel-manager.mjs +171 -0
  5. package/dist/anchor/base.d.ts +21 -0
  6. package/dist/anchor/base.js +26 -0
  7. package/dist/anchor/bsc.d.ts +20 -0
  8. package/dist/anchor/bsc.js +25 -0
  9. package/dist/anchor/evm.d.ts +99 -0
  10. package/dist/anchor/evm.js +262 -0
  11. package/dist/anchor/index.d.ts +173 -0
  12. package/dist/anchor/index.js +165 -0
  13. package/dist/anchor/mock.d.ts +43 -0
  14. package/dist/anchor/mock.js +100 -0
  15. package/dist/anchor/solana.d.ts +95 -0
  16. package/dist/anchor/solana.js +298 -0
  17. package/dist/auditor/index.d.ts +54 -0
  18. package/dist/auditor/index.js +141 -0
  19. package/dist/collaboration/index.d.ts +146 -0
  20. package/dist/collaboration/index.js +237 -0
  21. package/dist/crypto/index.d.ts +162 -0
  22. package/dist/crypto/index.js +231 -0
  23. package/dist/endpoint/index.d.ts +147 -0
  24. package/dist/endpoint/index.js +390 -0
  25. package/dist/envelope/index.d.ts +104 -0
  26. package/dist/envelope/index.js +156 -0
  27. package/dist/executor/index.d.ts +71 -0
  28. package/dist/executor/index.js +398 -0
  29. package/dist/gateway/index.d.ts +278 -0
  30. package/dist/gateway/index.js +520 -0
  31. package/dist/graph/index.d.ts +215 -0
  32. package/dist/graph/index.js +524 -0
  33. package/dist/handshake/index.d.ts +166 -0
  34. package/dist/handshake/index.js +287 -0
  35. package/dist/identity/index.d.ts +155 -0
  36. package/dist/identity/index.js +250 -0
  37. package/dist/index.d.ts +23 -0
  38. package/dist/index.js +28 -0
  39. package/dist/negotiation/index.d.ts +133 -0
  40. package/dist/negotiation/index.js +160 -0
  41. package/dist/network/index.d.ts +78 -0
  42. package/dist/network/index.js +207 -0
  43. package/dist/orchestrator/index.d.ts +190 -0
  44. package/dist/orchestrator/index.js +297 -0
  45. package/dist/policy/index.d.ts +100 -0
  46. package/dist/policy/index.js +206 -0
  47. package/dist/proof/index.d.ts +220 -0
  48. package/dist/proof/index.js +541 -0
  49. package/dist/registry/index.d.ts +98 -0
  50. package/dist/registry/index.js +129 -0
  51. package/dist/rollback/index.d.ts +76 -0
  52. package/dist/rollback/index.js +91 -0
  53. package/dist/schema/capability-schema.json +52 -0
  54. package/dist/schema/index.d.ts +128 -0
  55. package/dist/schema/index.js +163 -0
  56. package/dist/schema/task-schema.json +69 -0
  57. package/dist/score/index.d.ts +174 -0
  58. package/dist/score/index.js +275 -0
  59. package/dist/service/index.d.ts +34 -0
  60. package/dist/service/index.js +273 -0
  61. package/dist/service/server.d.ts +7 -0
  62. package/dist/service/server.js +22 -0
  63. package/dist/trace/index.d.ts +217 -0
  64. package/dist/trace/index.js +446 -0
  65. package/dist/trust/index.d.ts +84 -0
  66. package/dist/trust/index.js +107 -0
  67. package/dist/trust-sync/index.d.ts +30 -0
  68. package/dist/trust-sync/index.js +57 -0
  69. package/package.json +71 -0
  70. package/skill/SKILL.md +363 -0
  71. package/skill/references/commercial.md +184 -0
  72. package/skill/references/executor.md +356 -0
  73. package/skill/references/networking.md +64 -0
  74. package/skill/references/onchain.md +73 -0
  75. package/skill/references/security.md +96 -0
@@ -0,0 +1,298 @@
1
+ /**
2
+ * Solana Anchor Provider.
3
+ *
4
+ * Anchors hashes on Solana using the official Memo Program
5
+ * (`MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr`).
6
+ *
7
+ * The memo content is formatted as `ATEL_ANCHOR:<hash>` so anchored
8
+ * transactions are easily identifiable.
9
+ *
10
+ * @remarks
11
+ * ⚠️ SECURITY: The `privateKey` (Base58-encoded) is used to sign
12
+ * transactions. Never hard-code it — use environment variables or a vault.
13
+ */
14
+ import { Connection, Keypair, PublicKey, Transaction, TransactionInstruction, sendAndConfirmTransaction, } from '@solana/web3.js';
15
+ import bs58 from 'bs58';
16
+ /** Solana Memo Program address */
17
+ const MEMO_PROGRAM_ID = new PublicKey('MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr');
18
+ /** Prefix prepended to the hash in the memo (legacy format) */
19
+ const ANCHOR_PREFIX = 'ATEL_ANCHOR:';
20
+ /** V2 structured memo format: ATEL:1:<executorDID>:<requesterDID>:<taskId>:<trace_root> */
21
+ const ANCHOR_V2_PREFIX = 'ATEL:1:';
22
+ /**
23
+ * Anchor provider for the Solana blockchain.
24
+ */
25
+ export class SolanaAnchorProvider {
26
+ name = 'Solana';
27
+ chain = 'solana';
28
+ /** Solana RPC connection */
29
+ connection;
30
+ /** Keypair for signing (undefined when no private key is supplied) */
31
+ keypair;
32
+ /** Default Solana mainnet-beta RPC URL */
33
+ static DEFAULT_RPC_URL = 'https://api.mainnet-beta.solana.com';
34
+ /**
35
+ * @param config - RPC URL and optional private key.
36
+ * If `rpcUrl` is omitted, the Solana mainnet-beta default is used.
37
+ */
38
+ constructor(config) {
39
+ this.connection = new Connection(config?.rpcUrl ?? SolanaAnchorProvider.DEFAULT_RPC_URL, 'confirmed');
40
+ if (config?.privateKey) {
41
+ // ⚠️ SECURITY: The keypair holds the private key in memory.
42
+ const secretKey = bs58.decode(config.privateKey);
43
+ this.keypair = Keypair.fromSecretKey(secretKey);
44
+ }
45
+ }
46
+ /**
47
+ * Encode a hash into the memo data buffer (v2 structured format).
48
+ * Falls back to legacy format if no metadata provided.
49
+ */
50
+ static encodeMemo(hash, meta) {
51
+ if (meta?.executorDid && meta?.requesterDid && meta?.taskId) {
52
+ return Buffer.from(`${ANCHOR_V2_PREFIX}${meta.executorDid}:${meta.requesterDid}:${meta.taskId}:${hash}`, 'utf-8');
53
+ }
54
+ return Buffer.from(`${ANCHOR_PREFIX}${hash}`, 'utf-8');
55
+ }
56
+ /**
57
+ * Decode a hash from memo data. Supports both v2 structured and legacy format.
58
+ *
59
+ * @returns The decoded hash, or `null` if the data doesn't match.
60
+ */
61
+ static decodeMemo(data) {
62
+ const text = typeof data === 'string' ? data : Buffer.from(data).toString('utf-8');
63
+ // V2 structured format
64
+ if (text.startsWith(ANCHOR_V2_PREFIX)) {
65
+ const parts = text.slice(ANCHOR_V2_PREFIX.length).split(':');
66
+ if (parts.length >= 4)
67
+ return parts[parts.length - 1]; // last part is trace_root
68
+ }
69
+ // Legacy format
70
+ if (text.startsWith(ANCHOR_PREFIX)) {
71
+ return text.slice(ANCHOR_PREFIX.length);
72
+ }
73
+ return null;
74
+ }
75
+ /**
76
+ * Decode full structured memo (v2 only).
77
+ * Returns null for legacy format memos.
78
+ */
79
+ static decodeMemoV2(data) {
80
+ const text = typeof data === 'string' ? data : Buffer.from(data).toString('utf-8');
81
+ if (!text.startsWith(ANCHOR_V2_PREFIX))
82
+ return null;
83
+ const rest = text.slice(ANCHOR_V2_PREFIX.length);
84
+ // Format: executorDID:requesterDID:taskId:traceRoot
85
+ // DIDs contain colons (did:atel:ed25519:xxx), so we need smart parsing
86
+ // Split by ':' and reconstruct DIDs
87
+ const parts = rest.split(':');
88
+ // Minimum: did:atel:ed25519:key : did:atel:ed25519:key : taskId : traceRoot = 4+4+1+1 = 10 parts
89
+ if (parts.length < 10)
90
+ return null;
91
+ // Each DID is 4 parts: did:atel:ed25519:base58
92
+ const executorDid = parts.slice(0, 4).join(':');
93
+ const requesterDid = parts.slice(4, 8).join(':');
94
+ const taskId = parts[8];
95
+ const traceRoot = parts.slice(9).join(':');
96
+ if (!executorDid.startsWith('did:atel:') || !requesterDid.startsWith('did:atel:'))
97
+ return null;
98
+ return { version: 1, executorDid, requesterDid, taskId, traceRoot };
99
+ }
100
+ /** @inheritdoc */
101
+ async anchor(hash, metadata) {
102
+ if (!this.keypair) {
103
+ throw new Error('Solana: Cannot anchor without a private key');
104
+ }
105
+ const memoData = SolanaAnchorProvider.encodeMemo(hash, metadata);
106
+ const instruction = new TransactionInstruction({
107
+ keys: [{ pubkey: this.keypair.publicKey, isSigner: true, isWritable: true }],
108
+ programId: MEMO_PROGRAM_ID,
109
+ data: memoData,
110
+ });
111
+ const transaction = new Transaction().add(instruction);
112
+ try {
113
+ const signature = await sendAndConfirmTransaction(this.connection, transaction, [this.keypair], { commitment: 'confirmed' });
114
+ // Fetch the confirmed transaction to get slot/block info
115
+ let blockNumber;
116
+ try {
117
+ const txInfo = await this.connection.getTransaction(signature, {
118
+ commitment: 'confirmed',
119
+ maxSupportedTransactionVersion: 0,
120
+ });
121
+ blockNumber = txInfo?.slot;
122
+ }
123
+ catch {
124
+ // Non-critical
125
+ }
126
+ return {
127
+ hash,
128
+ txHash: signature,
129
+ chain: 'solana',
130
+ timestamp: Date.now(),
131
+ blockNumber,
132
+ metadata,
133
+ };
134
+ }
135
+ catch (err) {
136
+ const message = err instanceof Error ? err.message : String(err);
137
+ throw new Error(`Solana anchor failed: ${message}`);
138
+ }
139
+ }
140
+ /** @inheritdoc */
141
+ async verify(hash, txHash) {
142
+ try {
143
+ const txInfo = await this.connection.getTransaction(txHash, {
144
+ commitment: 'confirmed',
145
+ maxSupportedTransactionVersion: 0,
146
+ });
147
+ if (!txInfo) {
148
+ return {
149
+ valid: false,
150
+ hash,
151
+ txHash,
152
+ chain: this.chain,
153
+ detail: 'Transaction not found',
154
+ };
155
+ }
156
+ // Search through instructions for a memo matching our hash
157
+ const message = txInfo.transaction.message;
158
+ let foundHash = null;
159
+ for (let i = 0; i < message.compiledInstructions.length; i++) {
160
+ const ix = message.compiledInstructions[i];
161
+ const keys = message.getAccountKeys();
162
+ const programId = keys.get(ix.programIdIndex);
163
+ if (programId?.equals(MEMO_PROGRAM_ID)) {
164
+ foundHash = SolanaAnchorProvider.decodeMemo(Buffer.from(ix.data));
165
+ if (foundHash)
166
+ break;
167
+ }
168
+ }
169
+ // Fallback: check log messages for memo content
170
+ if (!foundHash && txInfo.meta?.logMessages) {
171
+ for (const log of txInfo.meta.logMessages) {
172
+ if (log.includes(ANCHOR_PREFIX)) {
173
+ const idx = log.indexOf(ANCHOR_PREFIX);
174
+ foundHash = log.slice(idx + ANCHOR_PREFIX.length);
175
+ break;
176
+ }
177
+ }
178
+ }
179
+ if (foundHash === null) {
180
+ return {
181
+ valid: false,
182
+ hash,
183
+ txHash,
184
+ chain: this.chain,
185
+ detail: 'No anchor memo found in transaction',
186
+ };
187
+ }
188
+ const valid = foundHash === hash;
189
+ const blockTimestamp = txInfo.blockTime ? txInfo.blockTime * 1000 : undefined;
190
+ return {
191
+ valid,
192
+ hash,
193
+ txHash,
194
+ chain: this.chain,
195
+ blockTimestamp,
196
+ detail: valid
197
+ ? 'Hash matches on-chain memo'
198
+ : `Hash mismatch: expected "${hash}", found "${foundHash}"`,
199
+ };
200
+ }
201
+ catch (err) {
202
+ const message = err instanceof Error ? err.message : String(err);
203
+ return {
204
+ valid: false,
205
+ hash,
206
+ txHash,
207
+ chain: this.chain,
208
+ detail: `Verification error: ${message}`,
209
+ };
210
+ }
211
+ }
212
+ /** @inheritdoc */
213
+ async lookup(hash) {
214
+ // On-chain lookup without an indexer is not feasible for Solana.
215
+ // In production, integrate with a Solana indexer or Helius API.
216
+ return [];
217
+ }
218
+ /** @inheritdoc */
219
+ async isAvailable() {
220
+ try {
221
+ await this.connection.getSlot();
222
+ return true;
223
+ }
224
+ catch {
225
+ return false;
226
+ }
227
+ }
228
+ /**
229
+ * Query all ATEL anchor transactions for a given wallet address.
230
+ * Parses v2 structured memos to extract DID and task info.
231
+ *
232
+ * @param walletAddress - Solana wallet public key (base58)
233
+ * @param options - limit (default 100), filterDid (only return records involving this DID)
234
+ * @returns Array of parsed anchor memos with tx info
235
+ */
236
+ async queryByWallet(walletAddress, options) {
237
+ const limit = options?.limit ?? 100;
238
+ const pubkey = new PublicKey(walletAddress);
239
+ const results = [];
240
+ try {
241
+ const signatures = await this.connection.getSignaturesForAddress(pubkey, { limit });
242
+ for (const sig of signatures) {
243
+ try {
244
+ const txInfo = await this.connection.getTransaction(sig.signature, {
245
+ commitment: 'confirmed',
246
+ maxSupportedTransactionVersion: 0,
247
+ });
248
+ if (!txInfo)
249
+ continue;
250
+ // Search for ATEL memo in instructions
251
+ const message = txInfo.transaction.message;
252
+ for (let i = 0; i < message.compiledInstructions.length; i++) {
253
+ const ix = message.compiledInstructions[i];
254
+ const keys = message.getAccountKeys();
255
+ const programId = keys.get(ix.programIdIndex);
256
+ if (!programId?.equals(MEMO_PROGRAM_ID))
257
+ continue;
258
+ const memoText = Buffer.from(ix.data).toString('utf-8');
259
+ const parsed = SolanaAnchorProvider.decodeMemoV2(memoText);
260
+ if (!parsed)
261
+ continue;
262
+ // Filter by DID if requested
263
+ if (options?.filterDid && parsed.executorDid !== options.filterDid && parsed.requesterDid !== options.filterDid)
264
+ continue;
265
+ results.push({
266
+ ...parsed,
267
+ txHash: sig.signature,
268
+ blockTime: txInfo.blockTime ? txInfo.blockTime * 1000 : undefined,
269
+ });
270
+ }
271
+ // Fallback: check log messages
272
+ if (txInfo.meta?.logMessages) {
273
+ for (const log of txInfo.meta.logMessages) {
274
+ if (!log.includes(ANCHOR_V2_PREFIX))
275
+ continue;
276
+ const idx = log.indexOf(ANCHOR_V2_PREFIX);
277
+ const parsed = SolanaAnchorProvider.decodeMemoV2(log.slice(idx));
278
+ if (!parsed)
279
+ continue;
280
+ if (options?.filterDid && parsed.executorDid !== options.filterDid && parsed.requesterDid !== options.filterDid)
281
+ continue;
282
+ if (!results.some(r => r.txHash === sig.signature)) {
283
+ results.push({ ...parsed, txHash: sig.signature, blockTime: txInfo.blockTime ? txInfo.blockTime * 1000 : undefined });
284
+ }
285
+ }
286
+ }
287
+ }
288
+ catch {
289
+ // Skip individual tx failures
290
+ }
291
+ }
292
+ }
293
+ catch {
294
+ // Query failed — return empty
295
+ }
296
+ return results;
297
+ }
298
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * ContentAuditor — Protocol-level security auditing for ATEL payloads
3
+ *
4
+ * Detects common attack patterns that should be blocked at protocol level,
5
+ * regardless of agent capabilities or business logic.
6
+ */
7
+ export interface AuditResult {
8
+ safe: boolean;
9
+ reason?: string;
10
+ severity?: 'low' | 'medium' | 'high' | 'critical';
11
+ pattern?: string;
12
+ }
13
+ export interface AuditConfig {
14
+ enableInjectionCheck?: boolean;
15
+ enablePathTraversalCheck?: boolean;
16
+ enableCommandCheck?: boolean;
17
+ enableCredentialCheck?: boolean;
18
+ enableRecursionCheck?: boolean;
19
+ maxDepth?: number;
20
+ customPatterns?: Array<{
21
+ pattern: RegExp;
22
+ reason: string;
23
+ severity: AuditResult['severity'];
24
+ }>;
25
+ }
26
+ export declare class ContentAuditor {
27
+ private config;
28
+ constructor(config?: AuditConfig);
29
+ /**
30
+ * Audit a payload for protocol-level security issues
31
+ */
32
+ audit(payload: unknown, context?: {
33
+ action?: string;
34
+ from?: string;
35
+ }): AuditResult;
36
+ /**
37
+ * Calculate nesting depth of an object (DoS protection)
38
+ */
39
+ private getDepth;
40
+ /**
41
+ * Audit multiple payloads in batch
42
+ */
43
+ auditBatch(payloads: Array<{
44
+ payload: unknown;
45
+ context?: {
46
+ action?: string;
47
+ from?: string;
48
+ };
49
+ }>): AuditResult[];
50
+ }
51
+ /**
52
+ * Default auditor instance with standard config
53
+ */
54
+ export declare const defaultAuditor: ContentAuditor;
@@ -0,0 +1,141 @@
1
+ /**
2
+ * ContentAuditor — Protocol-level security auditing for ATEL payloads
3
+ *
4
+ * Detects common attack patterns that should be blocked at protocol level,
5
+ * regardless of agent capabilities or business logic.
6
+ */
7
+ const DEFAULT_CONFIG = {
8
+ enableInjectionCheck: true,
9
+ enablePathTraversalCheck: true,
10
+ enableCommandCheck: true,
11
+ enableCredentialCheck: true,
12
+ enableRecursionCheck: true,
13
+ maxDepth: 10,
14
+ customPatterns: [],
15
+ };
16
+ /**
17
+ * Protocol-level attack patterns
18
+ * These should be blocked regardless of agent capabilities
19
+ */
20
+ const ATTACK_PATTERNS = {
21
+ // SQL/NoSQL injection
22
+ injection: [
23
+ { pattern: /(\bOR\b|\bAND\b)\s+['"]?\d+['"]?\s*=\s*['"]?\d+/i, reason: 'SQL injection pattern', severity: 'critical' },
24
+ { pattern: /UNION\s+SELECT/i, reason: 'SQL UNION injection', severity: 'critical' },
25
+ { pattern: /;\s*DROP\s+TABLE/i, reason: 'SQL DROP command', severity: 'critical' },
26
+ { pattern: /\$where\s*:/i, reason: 'MongoDB $where injection', severity: 'critical' },
27
+ { pattern: /\{\s*\$ne\s*:\s*null\s*\}/i, reason: 'NoSQL injection pattern', severity: 'high' },
28
+ ],
29
+ // Path traversal
30
+ pathTraversal: [
31
+ { pattern: /\.\.[\/\\]/g, reason: 'Path traversal attempt', severity: 'high' },
32
+ { pattern: /[\/\\]etc[\/\\]passwd/i, reason: 'System file access attempt', severity: 'critical' },
33
+ { pattern: /[\/\\]\.ssh[\/\\]/i, reason: 'SSH directory access', severity: 'critical' },
34
+ { pattern: /[\/\\]\.aws[\/\\]/i, reason: 'AWS credentials access', severity: 'critical' },
35
+ ],
36
+ // Command injection
37
+ command: [
38
+ { pattern: /\b(rm|del|rmdir)\s+-[rf]+/i, reason: 'Destructive file operation', severity: 'critical' },
39
+ { pattern: /`[^`]*`/g, reason: 'Shell command backticks', severity: 'high' },
40
+ { pattern: /\$\([^)]*\)/g, reason: 'Shell command substitution', severity: 'high' },
41
+ { pattern: /&&|\|\|/g, reason: 'Shell command chaining', severity: 'medium' },
42
+ { pattern: />\s*[\/\\]/g, reason: 'Shell output redirection', severity: 'medium' },
43
+ { pattern: /\bsudo\b/i, reason: 'Privilege escalation attempt', severity: 'critical' },
44
+ { pattern: /\bchmod\s+777/i, reason: 'Dangerous permission change', severity: 'high' },
45
+ ],
46
+ // Credential/secret access
47
+ credential: [
48
+ { pattern: /private[_-]?key/i, reason: 'Private key access', severity: 'critical' },
49
+ { pattern: /secret[_-]?key/i, reason: 'Secret key access', severity: 'critical' },
50
+ { pattern: /api[_-]?key/i, reason: 'API key access', severity: 'high' },
51
+ { pattern: /password/i, reason: 'Password access', severity: 'high' },
52
+ { pattern: /\.env/i, reason: 'Environment file access', severity: 'high' },
53
+ { pattern: /\.pem\b/i, reason: 'Certificate file access', severity: 'high' },
54
+ ],
55
+ };
56
+ export class ContentAuditor {
57
+ config;
58
+ constructor(config = {}) {
59
+ this.config = { ...DEFAULT_CONFIG, ...config };
60
+ }
61
+ /**
62
+ * Audit a payload for protocol-level security issues
63
+ */
64
+ audit(payload, context) {
65
+ // Convert payload to searchable string
66
+ const payloadStr = JSON.stringify(payload);
67
+ // Check recursion depth (nested objects can cause DoS)
68
+ if (this.config.enableRecursionCheck) {
69
+ const depth = this.getDepth(payload);
70
+ if (depth > this.config.maxDepth) {
71
+ return {
72
+ safe: false,
73
+ reason: `Payload depth (${depth}) exceeds limit (${this.config.maxDepth})`,
74
+ severity: 'high',
75
+ };
76
+ }
77
+ }
78
+ // Check injection patterns
79
+ if (this.config.enableInjectionCheck) {
80
+ for (const { pattern, reason, severity } of ATTACK_PATTERNS.injection) {
81
+ if (pattern.test(payloadStr)) {
82
+ return { safe: false, reason, severity, pattern: pattern.source };
83
+ }
84
+ }
85
+ }
86
+ // Check path traversal
87
+ if (this.config.enablePathTraversalCheck) {
88
+ for (const { pattern, reason, severity } of ATTACK_PATTERNS.pathTraversal) {
89
+ if (pattern.test(payloadStr)) {
90
+ return { safe: false, reason, severity, pattern: pattern.source };
91
+ }
92
+ }
93
+ }
94
+ // Check command injection
95
+ if (this.config.enableCommandCheck) {
96
+ for (const { pattern, reason, severity } of ATTACK_PATTERNS.command) {
97
+ if (pattern.test(payloadStr)) {
98
+ return { safe: false, reason, severity, pattern: pattern.source };
99
+ }
100
+ }
101
+ }
102
+ // Check credential access
103
+ if (this.config.enableCredentialCheck) {
104
+ for (const { pattern, reason, severity } of ATTACK_PATTERNS.credential) {
105
+ if (pattern.test(payloadStr)) {
106
+ return { safe: false, reason, severity, pattern: pattern.source };
107
+ }
108
+ }
109
+ }
110
+ // Check custom patterns
111
+ for (const { pattern, reason, severity } of this.config.customPatterns) {
112
+ if (pattern.test(payloadStr)) {
113
+ return { safe: false, reason, severity, pattern: pattern.source };
114
+ }
115
+ }
116
+ return { safe: true };
117
+ }
118
+ /**
119
+ * Calculate nesting depth of an object (DoS protection)
120
+ */
121
+ getDepth(obj, currentDepth = 0) {
122
+ if (obj === null || typeof obj !== 'object') {
123
+ return currentDepth;
124
+ }
125
+ if (Array.isArray(obj)) {
126
+ return Math.max(currentDepth, ...obj.map(item => this.getDepth(item, currentDepth + 1)));
127
+ }
128
+ const depths = Object.values(obj).map(value => this.getDepth(value, currentDepth + 1));
129
+ return depths.length > 0 ? Math.max(...depths) : currentDepth;
130
+ }
131
+ /**
132
+ * Audit multiple payloads in batch
133
+ */
134
+ auditBatch(payloads) {
135
+ return payloads.map(({ payload, context }) => this.audit(payload, context));
136
+ }
137
+ }
138
+ /**
139
+ * Default auditor instance with standard config
140
+ */
141
+ export const defaultAuditor = new ContentAuditor();
@@ -0,0 +1,146 @@
1
+ /**
2
+ * Module: Collaboration Anchor
3
+ *
4
+ * Enhanced on-chain anchoring for multi-agent collaboration scenarios.
5
+ * Records the full lifecycle of agent collaboration on-chain:
6
+ *
7
+ * 1. Handshake Anchor — proves two agents established a verified session
8
+ * 2. Task Delegation Anchor — proves a task was delegated with consent
9
+ * 3. Execution Proof Anchor — proves task execution result (existing ProofBundle)
10
+ * 4. Trust Score Anchor — proves trust score at a point in time
11
+ * 5. Dispute Evidence Anchor — immutable evidence for dispute resolution
12
+ *
13
+ * Each anchor is a SHA-256 hash of the relevant data, stored on-chain
14
+ * via the existing AnchorManager infrastructure.
15
+ */
16
+ import type { AnchorManager, AnchorRecord, ChainId } from '../anchor/index.js';
17
+ import type { ProofBundle } from '../proof/index.js';
18
+ import type { Session } from '../handshake/index.js';
19
+ /** Types of collaboration events that can be anchored */
20
+ export type CollaborationAnchorType = 'handshake' | 'task_delegation' | 'execution_proof' | 'trust_score' | 'dispute_evidence' | 'key_rotation';
21
+ /** A collaboration anchor record with typed metadata */
22
+ export interface CollaborationAnchorRecord {
23
+ /** The type of collaboration event */
24
+ type: CollaborationAnchorType;
25
+ /** The hash that was anchored */
26
+ hash: string;
27
+ /** The on-chain anchor record */
28
+ anchor: AnchorRecord;
29
+ /** Participants involved */
30
+ participants: string[];
31
+ /** Human-readable description */
32
+ description: string;
33
+ /** Timestamp of the collaboration event */
34
+ eventTimestamp: string;
35
+ }
36
+ /** Task delegation data for anchoring */
37
+ export interface TaskDelegationData {
38
+ /** Requestor DID */
39
+ requestorDid: string;
40
+ /** Executor DID */
41
+ executorDid: string;
42
+ /** Task type */
43
+ taskType: string;
44
+ /** Consent token hash */
45
+ consentHash: string;
46
+ /** Policy hash */
47
+ policyHash: string;
48
+ /** Delegation timestamp */
49
+ timestamp: string;
50
+ /** Negotiated terms hash (if any) */
51
+ termsHash?: string;
52
+ }
53
+ /** Trust score snapshot for anchoring */
54
+ export interface TrustScoreSnapshot {
55
+ /** Agent DID */
56
+ agentDid: string;
57
+ /** Trust score at this point */
58
+ score: number;
59
+ /** Number of completed tasks */
60
+ completedTasks: number;
61
+ /** Number of failed tasks */
62
+ failedTasks: number;
63
+ /** Snapshot timestamp */
64
+ timestamp: string;
65
+ /** Previous snapshot hash (for chain linking) */
66
+ previousHash?: string;
67
+ }
68
+ /** Dispute evidence for anchoring */
69
+ export interface DisputeEvidence {
70
+ /** Dispute ID */
71
+ disputeId: string;
72
+ /** Complainant DID */
73
+ complainantDid: string;
74
+ /** Respondent DID */
75
+ respondentDid: string;
76
+ /** Related proof bundle hash */
77
+ proofHash: string;
78
+ /** Related task delegation hash */
79
+ delegationHash: string;
80
+ /** Evidence description */
81
+ description: string;
82
+ /** Timestamp */
83
+ timestamp: string;
84
+ }
85
+ /**
86
+ * Manages on-chain anchoring of multi-agent collaboration events.
87
+ *
88
+ * Builds on top of AnchorManager to provide typed, structured
89
+ * anchoring for the full collaboration lifecycle.
90
+ */
91
+ export declare class CollaborationAnchor {
92
+ private readonly anchorManager;
93
+ private readonly defaultChain;
94
+ private readonly records;
95
+ constructor(anchorManager: AnchorManager, defaultChain?: ChainId | string);
96
+ /**
97
+ * Anchor a handshake session establishment.
98
+ * Proves that two agents verified each other's identity at a specific time.
99
+ */
100
+ anchorHandshake(session: Session, chain?: ChainId | string): Promise<CollaborationAnchorRecord>;
101
+ /**
102
+ * Anchor a task delegation event.
103
+ * Proves that a task was delegated with specific consent and policy.
104
+ */
105
+ anchorTaskDelegation(delegation: TaskDelegationData, chain?: ChainId | string): Promise<CollaborationAnchorRecord>;
106
+ /**
107
+ * Anchor an execution proof bundle.
108
+ * Proves the result of a task execution with full Merkle proof.
109
+ */
110
+ anchorExecutionProof(proof: ProofBundle, chain?: ChainId | string): Promise<CollaborationAnchorRecord>;
111
+ /**
112
+ * Anchor a trust score snapshot.
113
+ * Creates an immutable record of an agent's trust score at a point in time.
114
+ * Links to previous snapshot for chain integrity.
115
+ */
116
+ anchorTrustScore(snapshot: TrustScoreSnapshot, chain?: ChainId | string): Promise<CollaborationAnchorRecord>;
117
+ /**
118
+ * Anchor dispute evidence.
119
+ * Creates an immutable record for dispute resolution.
120
+ */
121
+ anchorDisputeEvidence(evidence: DisputeEvidence, chain?: ChainId | string): Promise<CollaborationAnchorRecord>;
122
+ /**
123
+ * Anchor a key rotation event.
124
+ * Proves that an agent rotated their encryption keys at a specific time.
125
+ */
126
+ anchorKeyRotation(agentDid: string, rotationSeq: number, newPublicKeyHash: string, chain?: ChainId | string): Promise<CollaborationAnchorRecord>;
127
+ /**
128
+ * Get all collaboration anchor records.
129
+ */
130
+ getRecords(): CollaborationAnchorRecord[];
131
+ /**
132
+ * Get records by type.
133
+ */
134
+ getRecordsByType(type: CollaborationAnchorType): CollaborationAnchorRecord[];
135
+ /**
136
+ * Get records involving a specific agent.
137
+ */
138
+ getRecordsByParticipant(did: string): CollaborationAnchorRecord[];
139
+ /**
140
+ * Verify a collaboration anchor against the chain.
141
+ */
142
+ verifyAnchor(record: CollaborationAnchorRecord): Promise<{
143
+ valid: boolean;
144
+ detail: string;
145
+ }>;
146
+ }