@sentinel-atl/reputation 0.1.1

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/README.md ADDED
@@ -0,0 +1,48 @@
1
+ # @sentinel-atl/reputation
2
+
3
+ Weighted reputation scoring with negative vouches, Sybil resistance, and rate-limited vouching.
4
+
5
+ ## Features
6
+
7
+ - **Weighted scoring** — 90-day half-life exponential decay
8
+ - **Negative vouches** — 2x weight multiplier for accountability
9
+ - **Quarantine** — automatic at 3+ verified negative vouches
10
+ - **Sybil resistance** — rate-limited vouching (1 vouch per source→target per 24h)
11
+
12
+ ## Install
13
+
14
+ ```bash
15
+ npm install @sentinel-atl/reputation
16
+ ```
17
+
18
+ ## Quick Start
19
+
20
+ ```ts
21
+ import { ReputationEngine } from '@sentinel-atl/reputation';
22
+
23
+ const engine = new ReputationEngine();
24
+
25
+ engine.vouch({
26
+ sourceDid: 'did:key:z6MkAlice...',
27
+ targetDid: 'did:key:z6MkBob...',
28
+ score: 0.9,
29
+ evidence: 'Completed task successfully',
30
+ });
31
+
32
+ const rep = engine.getReputation('did:key:z6MkBob...');
33
+ console.log(rep.score); // 0.9
34
+ console.log(rep.quarantined); // false
35
+ ```
36
+
37
+ ## API
38
+
39
+ | Method | Description |
40
+ |---|---|
41
+ | `new ReputationEngine()` | Create a reputation engine |
42
+ | `vouch(vouch)` | Submit a vouch (positive or negative) |
43
+ | `getReputation(did)` | Get current reputation score |
44
+ | `isQuarantined(did)` | Check quarantine status |
45
+
46
+ ## License
47
+
48
+ MIT
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=reputation.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reputation.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/reputation.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,181 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { ReputationEngine } from '../index.js';
3
+ function makeVouch(overrides = {}) {
4
+ return {
5
+ voucherDid: 'did:key:z6MkVoucher',
6
+ subjectDid: 'did:key:z6MkSubject',
7
+ polarity: 'positive',
8
+ weight: 0.8,
9
+ voucherVerified: true,
10
+ timestamp: new Date().toISOString(),
11
+ ...overrides,
12
+ };
13
+ }
14
+ describe('ReputationEngine', () => {
15
+ describe('addVouch', () => {
16
+ it('accepts a valid vouch', () => {
17
+ const engine = new ReputationEngine();
18
+ const result = engine.addVouch(makeVouch());
19
+ expect(result.allowed).toBe(true);
20
+ });
21
+ it('rejects self-vouching', () => {
22
+ const engine = new ReputationEngine();
23
+ const result = engine.addVouch(makeVouch({ voucherDid: 'did:key:z6MkSame', subjectDid: 'did:key:z6MkSame' }));
24
+ expect(result.allowed).toBe(false);
25
+ expect(result.reason).toContain('Self-vouching');
26
+ });
27
+ it('rate-limits: 1 vouch per peer per 24h', () => {
28
+ const engine = new ReputationEngine();
29
+ const vouch = makeVouch();
30
+ engine.addVouch(vouch);
31
+ const second = engine.addVouch(vouch);
32
+ expect(second.allowed).toBe(false);
33
+ expect(second.reason).toContain('Rate limit');
34
+ });
35
+ it('allows vouching for different subjects', () => {
36
+ const engine = new ReputationEngine();
37
+ const r1 = engine.addVouch(makeVouch({ subjectDid: 'did:key:z6MkA' }));
38
+ const r2 = engine.addVouch(makeVouch({ subjectDid: 'did:key:z6MkB' }));
39
+ expect(r1.allowed).toBe(true);
40
+ expect(r2.allowed).toBe(true);
41
+ });
42
+ });
43
+ describe('computeScore', () => {
44
+ it('returns neutral 50 for unknown agents', () => {
45
+ const engine = new ReputationEngine();
46
+ const score = engine.computeScore('did:key:z6MkUnknown');
47
+ expect(score.score).toBe(50);
48
+ expect(score.totalVouches).toBe(0);
49
+ expect(score.isQuarantined).toBe(false);
50
+ });
51
+ it('increases score with positive vouches', () => {
52
+ const engine = new ReputationEngine();
53
+ engine.addVouch(makeVouch({
54
+ voucherDid: 'did:key:z6MkV1',
55
+ subjectDid: 'did:key:z6MkTarget',
56
+ polarity: 'positive',
57
+ weight: 0.8,
58
+ }));
59
+ const score = engine.computeScore('did:key:z6MkTarget');
60
+ expect(score.score).toBeGreaterThan(50);
61
+ expect(score.positiveVouches).toBe(1);
62
+ });
63
+ it('decreases score with negative vouches', () => {
64
+ const engine = new ReputationEngine();
65
+ engine.addVouch(makeVouch({
66
+ voucherDid: 'did:key:z6MkV1',
67
+ subjectDid: 'did:key:z6MkTarget',
68
+ polarity: 'negative',
69
+ weight: 0.8,
70
+ reason: 'scope_violation',
71
+ }));
72
+ const score = engine.computeScore('did:key:z6MkTarget');
73
+ expect(score.score).toBeLessThan(50);
74
+ expect(score.negativeVouches).toBe(1);
75
+ });
76
+ it('negative vouches weigh 2x (safety bias)', () => {
77
+ const engine = new ReputationEngine();
78
+ // One positive
79
+ engine.addVouch(makeVouch({
80
+ voucherDid: 'did:key:z6MkV1',
81
+ subjectDid: 'did:key:z6MkTarget',
82
+ polarity: 'positive',
83
+ weight: 0.5,
84
+ }));
85
+ // One negative with same weight — should dominate
86
+ engine.addVouch(makeVouch({
87
+ voucherDid: 'did:key:z6MkV2',
88
+ subjectDid: 'did:key:z6MkTarget',
89
+ polarity: 'negative',
90
+ weight: 0.5,
91
+ }));
92
+ const score = engine.computeScore('did:key:z6MkTarget');
93
+ expect(score.score).toBeLessThan(50); // Negative wins due to 2x multiplier
94
+ });
95
+ it('caps unverified agent influence at 0.3', () => {
96
+ const engine = new ReputationEngine();
97
+ // High-weight vouch from unverified agent
98
+ engine.addVouch(makeVouch({
99
+ voucherDid: 'did:key:z6MkUnverified',
100
+ subjectDid: 'did:key:z6MkTarget',
101
+ polarity: 'positive',
102
+ weight: 1.0,
103
+ voucherVerified: false,
104
+ }));
105
+ const scoreUnverified = engine.computeScore('did:key:z6MkTarget');
106
+ // Same vouch from verified agent
107
+ const engine2 = new ReputationEngine();
108
+ engine2.addVouch(makeVouch({
109
+ voucherDid: 'did:key:z6MkVerified',
110
+ subjectDid: 'did:key:z6MkTarget2',
111
+ polarity: 'positive',
112
+ weight: 1.0,
113
+ voucherVerified: true,
114
+ }));
115
+ const scoreVerified = engine2.computeScore('did:key:z6MkTarget2');
116
+ // Verified should have more impact
117
+ expect(scoreVerified.score).toBeGreaterThan(scoreUnverified.score);
118
+ });
119
+ it('quarantines agent with 3+ independent verified negative vouches', () => {
120
+ const engine = new ReputationEngine();
121
+ const subject = 'did:key:z6MkBadAgent';
122
+ // 3 independent verified negative vouches
123
+ for (let i = 1; i <= 3; i++) {
124
+ engine.addVouch(makeVouch({
125
+ voucherDid: `did:key:z6MkVerifiedV${i}`,
126
+ subjectDid: subject,
127
+ polarity: 'negative',
128
+ weight: 0.7,
129
+ voucherVerified: true,
130
+ reason: 'scope_violation',
131
+ }));
132
+ }
133
+ const score = engine.computeScore(subject);
134
+ expect(score.isQuarantined).toBe(true);
135
+ expect(score.quarantineReason).toContain('3');
136
+ });
137
+ it('does not quarantine with only 2 negatives', () => {
138
+ const engine = new ReputationEngine();
139
+ const subject = 'did:key:z6MkBorderline';
140
+ for (let i = 1; i <= 2; i++) {
141
+ engine.addVouch(makeVouch({
142
+ voucherDid: `did:key:z6MkV${i}`,
143
+ subjectDid: subject,
144
+ polarity: 'negative',
145
+ weight: 0.7,
146
+ voucherVerified: true,
147
+ }));
148
+ }
149
+ const score = engine.computeScore(subject);
150
+ expect(score.isQuarantined).toBe(false);
151
+ });
152
+ });
153
+ describe('getVouches', () => {
154
+ it('returns all vouches for a DID', () => {
155
+ const engine = new ReputationEngine();
156
+ engine.addVouch(makeVouch({
157
+ voucherDid: 'did:key:z6MkV1',
158
+ subjectDid: 'did:key:z6MkTarget',
159
+ }));
160
+ engine.addVouch(makeVouch({
161
+ voucherDid: 'did:key:z6MkV2',
162
+ subjectDid: 'did:key:z6MkTarget',
163
+ }));
164
+ const vouches = engine.getVouches('did:key:z6MkTarget');
165
+ expect(vouches).toHaveLength(2);
166
+ });
167
+ it('returns empty array for unknown DID', () => {
168
+ const engine = new ReputationEngine();
169
+ expect(engine.getVouches('did:key:z6MkUnknown')).toEqual([]);
170
+ });
171
+ });
172
+ describe('unavailableScore', () => {
173
+ it('returns a neutral score', () => {
174
+ const score = ReputationEngine.unavailableScore('did:key:z6MkOffline');
175
+ expect(score.score).toBe(50);
176
+ expect(score.source).toBe('unavailable');
177
+ expect(score.isQuarantined).toBe(false);
178
+ });
179
+ });
180
+ });
181
+ //# sourceMappingURL=reputation.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reputation.test.js","sourceRoot":"","sources":["../../src/__tests__/reputation.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * @sentinel-atl/reputation — Weighted Trust Scoring Engine
3
+ *
4
+ * Unlike simple "thumbs up" systems, Sentinel reputation is:
5
+ * - Weighted: vouches from high-reputation agents count more
6
+ * - Time-decayed: stale vouches lose influence (90-day half-life)
7
+ * - Sybil-resistant: unverified agents have capped influence
8
+ * - Negative-capable: bad agents get penalized, not just ignored
9
+ * - Rate-limited: 1 vouch per peer per 24h, burst detection
10
+ *
11
+ * Score range: 0–100. New agents start at 50 (neutral).
12
+ */
13
+ import type { NegativeReason } from '@sentinel-atl/core';
14
+ export interface Vouch {
15
+ /** DID of the agent issuing the vouch */
16
+ voucherDid: string;
17
+ /** DID of the agent being vouched for */
18
+ subjectDid: string;
19
+ /** Positive or negative */
20
+ polarity: 'positive' | 'negative';
21
+ /** Weight: 0-1, based on voucher's own reputation */
22
+ weight: number;
23
+ /** Whether the voucher has a verified human principal */
24
+ voucherVerified: boolean;
25
+ /** Reason (for negative vouches) */
26
+ reason?: NegativeReason;
27
+ /** ISO 8601 timestamp */
28
+ timestamp: string;
29
+ }
30
+ export interface ReputationScore {
31
+ did: string;
32
+ score: number;
33
+ totalVouches: number;
34
+ positiveVouches: number;
35
+ negativeVouches: number;
36
+ isQuarantined: boolean;
37
+ quarantineReason?: string;
38
+ lastUpdated: string;
39
+ source: 'live' | 'cached' | 'unavailable';
40
+ }
41
+ export interface VouchRateLimitResult {
42
+ allowed: boolean;
43
+ reason?: string;
44
+ retryAfterMs?: number;
45
+ }
46
+ export declare class ReputationEngine {
47
+ /** All vouches indexed by subject DID */
48
+ private vouches;
49
+ /** Rate limit tracking: `${voucherDid}:${subjectDid}` → last vouch time */
50
+ private vouchTimestamps;
51
+ /** Hourly vouch counts per voucher for burst detection */
52
+ private hourlyVouchCounts;
53
+ /**
54
+ * Check if a vouch is allowed (rate limits + self-vouch rejection).
55
+ */
56
+ checkVouchRateLimit(voucherDid: string, subjectDid: string): VouchRateLimitResult;
57
+ /**
58
+ * Record a vouch (positive or negative).
59
+ */
60
+ addVouch(vouch: Vouch): VouchRateLimitResult;
61
+ /**
62
+ * Compute reputation score for an agent.
63
+ *
64
+ * Formula: score = 50 + Σ(polarity × vouch_weight × time_decay × verified_factor)
65
+ * Clamped to [0, 100].
66
+ *
67
+ * Negative vouches carry 2x weight (safety bias).
68
+ * Unverified vouchers capped at 0.3 influence.
69
+ */
70
+ computeScore(did: string): ReputationScore;
71
+ /**
72
+ * Get all vouches for a DID (for audit/dispute resolution).
73
+ */
74
+ getVouches(did: string): Vouch[];
75
+ /**
76
+ * Create a "cached" score for offline/degraded mode.
77
+ */
78
+ static unavailableScore(did: string): ReputationScore;
79
+ }
80
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEzD,MAAM,WAAW,KAAK;IACpB,yCAAyC;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,yCAAyC;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,2BAA2B;IAC3B,QAAQ,EAAE,UAAU,GAAG,UAAU,CAAC;IAClC,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC;IACf,yDAAyD;IACzD,eAAe,EAAE,OAAO,CAAC;IACzB,oCAAoC;IACpC,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,yBAAyB;IACzB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,OAAO,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,aAAa,CAAC;CAC3C;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAoBD,qBAAa,gBAAgB;IAC3B,yCAAyC;IACzC,OAAO,CAAC,OAAO,CAA8B;IAC7C,2EAA2E;IAC3E,OAAO,CAAC,eAAe,CAA6B;IACpD,0DAA0D;IAC1D,OAAO,CAAC,iBAAiB,CAA6D;IAEtF;;OAEG;IACH,mBAAmB,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,oBAAoB;IAqCjF;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,oBAAoB;IAyB5C;;;;;;;;OAQG;IACH,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe;IAmD1C;;OAEG;IACH,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,EAAE;IAIhC;;OAEG;IACH,MAAM,CAAC,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe;CAYtD"}
package/dist/index.js ADDED
@@ -0,0 +1,172 @@
1
+ /**
2
+ * @sentinel-atl/reputation — Weighted Trust Scoring Engine
3
+ *
4
+ * Unlike simple "thumbs up" systems, Sentinel reputation is:
5
+ * - Weighted: vouches from high-reputation agents count more
6
+ * - Time-decayed: stale vouches lose influence (90-day half-life)
7
+ * - Sybil-resistant: unverified agents have capped influence
8
+ * - Negative-capable: bad agents get penalized, not just ignored
9
+ * - Rate-limited: 1 vouch per peer per 24h, burst detection
10
+ *
11
+ * Score range: 0–100. New agents start at 50 (neutral).
12
+ */
13
+ const NEUTRAL_SCORE = 50;
14
+ const HALF_LIFE_DAYS = 90;
15
+ const HALF_LIFE_MS = HALF_LIFE_DAYS * 24 * 60 * 60 * 1000;
16
+ const NEGATIVE_WEIGHT_MULTIPLIER = 2;
17
+ const UNVERIFIED_AGENT_CAP = 0.3; // Max influence of unverified agents
18
+ const QUARANTINE_THRESHOLD = 3; // Negative vouches from independent verified agents
19
+ const MAX_VOUCHES_PER_PEER_PER_DAY = 1;
20
+ const BURST_THRESHOLD_PER_HOUR = 10;
21
+ /**
22
+ * Compute time-decay factor for a vouch.
23
+ * Exponential decay with 90-day half-life.
24
+ */
25
+ function timeDecay(vouchTimestamp, now = Date.now()) {
26
+ const age = now - new Date(vouchTimestamp).getTime();
27
+ return Math.pow(0.5, age / HALF_LIFE_MS);
28
+ }
29
+ export class ReputationEngine {
30
+ /** All vouches indexed by subject DID */
31
+ vouches = new Map();
32
+ /** Rate limit tracking: `${voucherDid}:${subjectDid}` → last vouch time */
33
+ vouchTimestamps = new Map();
34
+ /** Hourly vouch counts per voucher for burst detection */
35
+ hourlyVouchCounts = new Map();
36
+ /**
37
+ * Check if a vouch is allowed (rate limits + self-vouch rejection).
38
+ */
39
+ checkVouchRateLimit(voucherDid, subjectDid) {
40
+ // Self-vouch rejection
41
+ if (voucherDid === subjectDid) {
42
+ return { allowed: false, reason: 'Self-vouching is not allowed' };
43
+ }
44
+ // Per-peer rate limit: 1 vouch per peer per 24h
45
+ const pairKey = `${voucherDid}:${subjectDid}`;
46
+ const lastVouch = this.vouchTimestamps.get(pairKey);
47
+ if (lastVouch) {
48
+ const elapsed = Date.now() - lastVouch;
49
+ const dayMs = 24 * 60 * 60 * 1000;
50
+ if (elapsed < dayMs) {
51
+ return {
52
+ allowed: false,
53
+ reason: 'Rate limit: 1 vouch per peer per 24 hours',
54
+ retryAfterMs: dayMs - elapsed,
55
+ };
56
+ }
57
+ }
58
+ // Burst detection: >10 vouches/hour triggers suppression
59
+ const hourly = this.hourlyVouchCounts.get(voucherDid);
60
+ const now = Date.now();
61
+ if (hourly && now - hourly.windowStart < 3600_000) {
62
+ if (hourly.count >= BURST_THRESHOLD_PER_HOUR) {
63
+ return {
64
+ allowed: false,
65
+ reason: 'Burst vouch pattern detected. Temporarily suppressed.',
66
+ retryAfterMs: 3600_000 - (now - hourly.windowStart),
67
+ };
68
+ }
69
+ }
70
+ return { allowed: true };
71
+ }
72
+ /**
73
+ * Record a vouch (positive or negative).
74
+ */
75
+ addVouch(vouch) {
76
+ const rateCheck = this.checkVouchRateLimit(vouch.voucherDid, vouch.subjectDid);
77
+ if (!rateCheck.allowed)
78
+ return rateCheck;
79
+ // Record the vouch
80
+ const existing = this.vouches.get(vouch.subjectDid) ?? [];
81
+ existing.push(vouch);
82
+ this.vouches.set(vouch.subjectDid, existing);
83
+ // Update rate limit tracking
84
+ const pairKey = `${vouch.voucherDid}:${vouch.subjectDid}`;
85
+ this.vouchTimestamps.set(pairKey, Date.now());
86
+ // Update hourly count
87
+ const now = Date.now();
88
+ const hourly = this.hourlyVouchCounts.get(vouch.voucherDid);
89
+ if (!hourly || now - hourly.windowStart >= 3600_000) {
90
+ this.hourlyVouchCounts.set(vouch.voucherDid, { count: 1, windowStart: now });
91
+ }
92
+ else {
93
+ hourly.count++;
94
+ }
95
+ return { allowed: true };
96
+ }
97
+ /**
98
+ * Compute reputation score for an agent.
99
+ *
100
+ * Formula: score = 50 + Σ(polarity × vouch_weight × time_decay × verified_factor)
101
+ * Clamped to [0, 100].
102
+ *
103
+ * Negative vouches carry 2x weight (safety bias).
104
+ * Unverified vouchers capped at 0.3 influence.
105
+ */
106
+ computeScore(did) {
107
+ const agentVouches = this.vouches.get(did) ?? [];
108
+ const now = Date.now();
109
+ let weightedSum = 0;
110
+ let positiveCount = 0;
111
+ let negativeCount = 0;
112
+ let independentVerifiedNegatives = new Set();
113
+ for (const vouch of agentVouches) {
114
+ const decay = timeDecay(vouch.timestamp, now);
115
+ const verifiedFactor = vouch.voucherVerified
116
+ ? vouch.weight
117
+ : Math.min(vouch.weight, UNVERIFIED_AGENT_CAP);
118
+ const effectiveWeight = decay * verifiedFactor;
119
+ if (vouch.polarity === 'positive') {
120
+ weightedSum += effectiveWeight;
121
+ positiveCount++;
122
+ }
123
+ else {
124
+ weightedSum -= effectiveWeight * NEGATIVE_WEIGHT_MULTIPLIER;
125
+ negativeCount++;
126
+ if (vouch.voucherVerified) {
127
+ independentVerifiedNegatives.add(vouch.voucherDid);
128
+ }
129
+ }
130
+ }
131
+ // Normalize: weightedSum is roughly in [-N, N], scale to [0, 100] around 50
132
+ const rawScore = NEUTRAL_SCORE + weightedSum * 10;
133
+ const score = Math.max(0, Math.min(100, Math.round(rawScore * 100) / 100));
134
+ // Quarantine check
135
+ const isQuarantined = independentVerifiedNegatives.size >= QUARANTINE_THRESHOLD;
136
+ return {
137
+ did,
138
+ score,
139
+ totalVouches: agentVouches.length,
140
+ positiveVouches: positiveCount,
141
+ negativeVouches: negativeCount,
142
+ isQuarantined,
143
+ quarantineReason: isQuarantined
144
+ ? `${independentVerifiedNegatives.size} independent verified negative vouches`
145
+ : undefined,
146
+ lastUpdated: new Date().toISOString(),
147
+ source: 'live',
148
+ };
149
+ }
150
+ /**
151
+ * Get all vouches for a DID (for audit/dispute resolution).
152
+ */
153
+ getVouches(did) {
154
+ return this.vouches.get(did) ?? [];
155
+ }
156
+ /**
157
+ * Create a "cached" score for offline/degraded mode.
158
+ */
159
+ static unavailableScore(did) {
160
+ return {
161
+ did,
162
+ score: NEUTRAL_SCORE,
163
+ totalVouches: 0,
164
+ positiveVouches: 0,
165
+ negativeVouches: 0,
166
+ isQuarantined: false,
167
+ lastUpdated: new Date().toISOString(),
168
+ source: 'unavailable',
169
+ };
170
+ }
171
+ }
172
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@sentinel-atl/reputation",
3
+ "version": "0.1.1",
4
+ "description": "Weighted reputation scoring with negative vouches, Sybil resistance, and rate-limited vouching",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "scripts": {
15
+ "build": "tsc",
16
+ "test": "vitest run",
17
+ "lint": "tsc --noEmit",
18
+ "clean": "rm -rf dist"
19
+ },
20
+ "dependencies": {
21
+ "@sentinel-atl/core": "*"
22
+ },
23
+ "devDependencies": {
24
+ "typescript": "^5.7.0",
25
+ "vitest": "^3.0.0",
26
+ "@types/node": "^20.0.0"
27
+ },
28
+ "license": "Apache-2.0",
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "https://github.com/sentinel-atl/project-sentinel.git",
32
+ "directory": "packages/reputation"
33
+ },
34
+ "keywords": [
35
+ "ai-agent",
36
+ "trust",
37
+ "identity",
38
+ "did",
39
+ "verifiable-credentials",
40
+ "mcp",
41
+ "security"
42
+ ],
43
+ "homepage": "https://github.com/sentinel-atl/project-sentinel#readme",
44
+ "bugs": {
45
+ "url": "https://github.com/sentinel-atl/project-sentinel/issues"
46
+ },
47
+ "files": [
48
+ "dist",
49
+ "README.md"
50
+ ]
51
+ }