vibedate 0.3.1 → 0.4.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 +16 -10
- package/dist/{chunk-3VT4EOBX.js → chunk-43IYNWES.js} +401 -212
- package/dist/{chunk-OVO2CQ7X.js → chunk-ZB56ZBAR.js} +2 -2
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +485 -73
- package/dist/index.d.ts +130 -31
- package/dist/index.js +13 -3
- package/dist/mcp.js +2 -2
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
|
-
import { VibeEvent, Harness,
|
|
2
|
-
export { Harness, UsageSnapshot, createConsentLedger } from '@pooriaarab/vibe-core';
|
|
1
|
+
import { VibeEvent, UsageSnapshot, UsageSource, Harness, HarnessUsageOptions } from '@pooriaarab/vibe-core';
|
|
2
|
+
export { Harness, UsageSnapshot, UsageSource, createConsentLedger } from '@pooriaarab/vibe-core';
|
|
3
|
+
import { KeyObject } from 'node:crypto';
|
|
3
4
|
|
|
4
5
|
type Frame = {
|
|
5
6
|
t: 'hello';
|
|
6
7
|
handle: string;
|
|
7
8
|
league: string;
|
|
8
9
|
harness: string;
|
|
10
|
+
verified?: boolean;
|
|
11
|
+
pubkey?: string;
|
|
12
|
+
nonce?: string;
|
|
13
|
+
sig?: string;
|
|
9
14
|
} | {
|
|
10
15
|
t: 'msg';
|
|
11
16
|
id: string;
|
|
@@ -57,11 +62,7 @@ interface ReceivedMedia {
|
|
|
57
62
|
|
|
58
63
|
interface PeerLink {
|
|
59
64
|
/** The validated identity of the remote peer (from the hello handshake). */
|
|
60
|
-
readonly hello:
|
|
61
|
-
handle: string;
|
|
62
|
-
league: string;
|
|
63
|
-
harness: string;
|
|
64
|
-
};
|
|
65
|
+
readonly hello: PeerHello;
|
|
65
66
|
/** Send a line of text as a `msg` frame. */
|
|
66
67
|
send(text: string): void;
|
|
67
68
|
/** Read a file from disk and send it as a chunked media transfer. */
|
|
@@ -99,14 +100,36 @@ declare const TOPIC_PREFIX = "vibedate:";
|
|
|
99
100
|
* entire discovery mechanism. Pure.
|
|
100
101
|
*/
|
|
101
102
|
declare function leagueTopic(leagueName: string): Buffer;
|
|
102
|
-
/**
|
|
103
|
+
/**
|
|
104
|
+
* The fields that ever leave the machine over a peer connection: handle, league,
|
|
105
|
+
* harness, and (optionally) the self-asserted usage-verification flag plus the
|
|
106
|
+
* identity proof (pubkey/nonce/sig). NEVER raw usage — no token totals, no logs.
|
|
107
|
+
* `verified`/`pubkey` are undefined for legacy peers that predate them; both
|
|
108
|
+
* `undefined` and `false` display as unverified (~).
|
|
109
|
+
*/
|
|
103
110
|
interface PeerHello {
|
|
104
111
|
readonly handle: string;
|
|
105
112
|
readonly league: string;
|
|
106
113
|
readonly harness: string;
|
|
114
|
+
/**
|
|
115
|
+
* Self-asserted: the sender's usage came from real local logs (see readUsage).
|
|
116
|
+
* Bound to the sender's key by the identity signature when `pubkey` is present.
|
|
117
|
+
*/
|
|
118
|
+
readonly verified?: boolean;
|
|
119
|
+
/** Raw ed25519 public key (64 hex) — the persistent identity this hello signs. */
|
|
120
|
+
readonly pubkey?: string;
|
|
121
|
+
/** Random per-hello nonce (hex) covered by the signature. */
|
|
122
|
+
readonly nonce?: string;
|
|
123
|
+
/** ed25519 signature (128 hex) over `handle|league|harness|verified|nonce`. */
|
|
124
|
+
readonly sig?: string;
|
|
125
|
+
/**
|
|
126
|
+
* LOCAL-DERIVED, never on the wire: true when this hello's signature verified
|
|
127
|
+
* against its pubkey (see classifyHelloIdentity). Marked 🔑 in the UI.
|
|
128
|
+
*/
|
|
129
|
+
readonly identityVerified?: boolean;
|
|
107
130
|
}
|
|
108
131
|
/** One-line privacy notice printed before joining the swarm. */
|
|
109
|
-
declare const LIVE_NOTICE = "live discovery: sharing only your handle + league + harness (never raw usage) with same-league peers on the public DHT";
|
|
132
|
+
declare const LIVE_NOTICE = "live discovery: sharing only your handle + league + harness + verified flag + identity pubkey (never raw usage) with same-league peers on the public DHT";
|
|
110
133
|
/**
|
|
111
134
|
* Serialize a hello to the single JSON line sent on connect. Built key-by-key
|
|
112
135
|
* from the allowlist — even if a caller sneaks extra properties onto the
|
|
@@ -124,6 +147,8 @@ declare function parseHandshake(raw: string | Buffer): PeerHello | null;
|
|
|
124
147
|
interface StoredPeer extends PeerHello {
|
|
125
148
|
readonly firstSeenAt: string;
|
|
126
149
|
readonly lastSeenAt: string;
|
|
150
|
+
/** LOCAL metadata: when the last `msg` from this peer arrived (never on the wire). */
|
|
151
|
+
readonly lastMessageAt?: string;
|
|
127
152
|
}
|
|
128
153
|
/** Load persisted live peers, or `[]` if none/corrupt. Local-only data. */
|
|
129
154
|
declare function loadPeers(dir?: string): StoredPeer[];
|
|
@@ -135,6 +160,12 @@ declare function recordPeer(hello: PeerHello, dir?: string, now?: Date): {
|
|
|
135
160
|
peer: StoredPeer;
|
|
136
161
|
isNew: boolean;
|
|
137
162
|
};
|
|
163
|
+
/**
|
|
164
|
+
* Stamp `lastMessageAt` on a stored peer (a `msg` just arrived from them).
|
|
165
|
+
* Local metadata only; never on the wire. Returns false when the handle isn't
|
|
166
|
+
* a known peer. Never throws — best-effort bookkeeping.
|
|
167
|
+
*/
|
|
168
|
+
declare function recordPeerMessage(handle: string, dir?: string, now?: Date): boolean;
|
|
138
169
|
/** Injection point for the match notification (defaults to vibe-core notify). */
|
|
139
170
|
type NotifySink = (event: VibeEvent) => void;
|
|
140
171
|
interface DiscoveryOptions {
|
|
@@ -208,14 +239,74 @@ interface DiscoverySession {
|
|
|
208
239
|
declare function startDiscovery(opts: DiscoveryOptions): Promise<DiscoverySession>;
|
|
209
240
|
|
|
210
241
|
/**
|
|
211
|
-
*
|
|
242
|
+
* Persistent ed25519 identity — binds a handle to a keypair so a peer cannot
|
|
243
|
+
* impersonate it.
|
|
212
244
|
*
|
|
213
|
-
*
|
|
214
|
-
*
|
|
215
|
-
*
|
|
245
|
+
* The keypair lives at `~/.vibedating/identity.json` (mode 0600), generated on
|
|
246
|
+
* first use and reused across runs. A hello that carries a `pubkey` must also
|
|
247
|
+
* carry a valid `sig` over the canonical claims string
|
|
248
|
+
* `handle|league|harness|verified|nonce`; anything else claiming a key is an
|
|
249
|
+
* impersonation attempt and the peer is DROPPED. A hello with no `pubkey` at
|
|
250
|
+
* all is a legacy peer — accepted, but never identity-verified.
|
|
216
251
|
*
|
|
217
|
-
*
|
|
252
|
+
* node:crypto only — no new dependency. The private key never leaves the file;
|
|
253
|
+
* only the raw public key (64 hex) and signatures (128 hex) travel on hellos.
|
|
254
|
+
*/
|
|
255
|
+
|
|
256
|
+
/** A loaded identity: the raw public key (wire form) plus both key objects. */
|
|
257
|
+
interface Identity {
|
|
258
|
+
/** Raw 32-byte ed25519 public key, hex (64 chars) — the wire form. */
|
|
259
|
+
readonly publicKeyHex: string;
|
|
260
|
+
readonly publicKey: KeyObject;
|
|
261
|
+
readonly privateKey: KeyObject;
|
|
262
|
+
/** ISO timestamp of key generation (first connect). */
|
|
263
|
+
readonly createdAt: string;
|
|
264
|
+
}
|
|
265
|
+
/** The hello fields a signature commits to (a PeerHello minus its proof). */
|
|
266
|
+
interface HelloClaims {
|
|
267
|
+
readonly handle: string;
|
|
268
|
+
readonly league: string;
|
|
269
|
+
readonly harness: string;
|
|
270
|
+
readonly verified?: boolean;
|
|
271
|
+
}
|
|
272
|
+
/** The wire proof attached to a hello: pubkey + nonce + signature, all hex. */
|
|
273
|
+
interface IdentityProof {
|
|
274
|
+
readonly pubkey: string;
|
|
275
|
+
readonly nonce: string;
|
|
276
|
+
readonly sig: string;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Load the persistent keypair, generating + storing it (mode 0600) on first
|
|
280
|
+
* use. A missing or corrupt file is (re)generated — never throws on disk
|
|
281
|
+
* content. Idempotent across runs: same file → same key → same pubkey.
|
|
282
|
+
*/
|
|
283
|
+
declare function loadOrCreateIdentity(dir?: string): Identity;
|
|
284
|
+
/**
|
|
285
|
+
* The canonical string an identity signature commits to:
|
|
286
|
+
* `handle|league|harness|verified|nonce` — verified rendered as `true`/`false`.
|
|
287
|
+
* Pure; both sides compute it byte-identically or the signature cannot verify.
|
|
288
|
+
*/
|
|
289
|
+
declare function canonicalHelloClaims(claims: HelloClaims & {
|
|
290
|
+
nonce: string;
|
|
291
|
+
}): string;
|
|
292
|
+
/**
|
|
293
|
+
* Sign hello claims with the persistent identity. A fresh random 16-byte nonce
|
|
294
|
+
* per call, so two hellos never share a signature. Returns only the wire proof
|
|
295
|
+
* fields — the private key stays put.
|
|
218
296
|
*/
|
|
297
|
+
declare function signHelloClaims(identity: Identity, claims: HelloClaims): IdentityProof;
|
|
298
|
+
/**
|
|
299
|
+
* Verify a claimed proof against hello claims. NEVER throws — any anomaly
|
|
300
|
+
* (bad hex, bad key, bad signature) is simply `false`.
|
|
301
|
+
*/
|
|
302
|
+
declare function verifyHelloClaims(claims: HelloClaims, proof: IdentityProof): boolean;
|
|
303
|
+
/** What an incoming hello's identity material amounts to. */
|
|
304
|
+
type IdentityVerdict = 'verified' | 'legacy' | 'drop';
|
|
305
|
+
/**
|
|
306
|
+
* Classify an incoming hello's identity claim. Pure decision, no IO — the
|
|
307
|
+
* caller (discovery) turns 'drop' into "never recorded, never paired".
|
|
308
|
+
*/
|
|
309
|
+
declare function classifyHelloIdentity(hello: HelloClaims & Partial<IdentityProof>): IdentityVerdict;
|
|
219
310
|
|
|
220
311
|
/**
|
|
221
312
|
* A usage league (volume bucket). `max` is inclusive; the top tier is open-ended
|
|
@@ -277,26 +368,34 @@ declare const TOKENS_ENV = "VIBEDATING_TOKENS";
|
|
|
277
368
|
*/
|
|
278
369
|
declare const DEMO_TOTAL_TOKENS = 23400000;
|
|
279
370
|
/**
|
|
280
|
-
*
|
|
281
|
-
*
|
|
282
|
-
*
|
|
283
|
-
*
|
|
284
|
-
*
|
|
285
|
-
* 3. the demo value {@link DEMO_TOTAL_TOKENS} → `verified: false`.
|
|
286
|
-
*
|
|
287
|
-
* The snapshot's `totalTokens` is the only thing that must never leave the
|
|
288
|
-
* machine; everything downstream consumes only the league bucket.
|
|
371
|
+
* A usage snapshot with honest provenance. `source` says where `totalTokens`
|
|
372
|
+
* came from; `verified` is true ONLY for `source === 'real'` (measured from
|
|
373
|
+
* the harness's own local session logs). The token total is the one thing that
|
|
374
|
+
* must never leave the machine; everything downstream consumes only the league
|
|
375
|
+
* bucket plus the verified flag.
|
|
289
376
|
*/
|
|
290
|
-
|
|
377
|
+
interface LocalUsageSnapshot extends UsageSnapshot {
|
|
378
|
+
/** Where the total came from: measured locally, self-reported, or demo. */
|
|
379
|
+
readonly source: UsageSource;
|
|
380
|
+
/** Short human-facing provenance note from the reader (local display only). */
|
|
381
|
+
readonly detail?: string;
|
|
382
|
+
}
|
|
291
383
|
/**
|
|
292
|
-
*
|
|
384
|
+
* Usage reader, backed by vibe-core's {@link readHarnessUsage}. Resolution order:
|
|
385
|
+
*
|
|
386
|
+
* 1. a self-reported value — explicit `opts.selfReportTokens`, or the
|
|
387
|
+
* {@link TOKENS_ENV} env var (suffix-friendly: `12M`, `1.2B`), or vibe-core's
|
|
388
|
+
* own `VIBE_TOKENS` env → `source: 'self-report'` → `verified: false`.
|
|
389
|
+
* 2. the harness's REAL local session logs (claude-code / codex / gemini / pi /
|
|
390
|
+
* kimi), read from disk by vibe-core → `source: 'real'` → `verified: true`.
|
|
391
|
+
* 3. the demo value {@link DEMO_TOTAL_TOKENS} → `source: 'demo'` →
|
|
392
|
+
* `verified: false`.
|
|
293
393
|
*
|
|
294
|
-
*
|
|
295
|
-
*
|
|
296
|
-
*
|
|
297
|
-
* visible at the call site.
|
|
394
|
+
* The demo arm keeps vibedating's own demo total (10M league, non-empty demo
|
|
395
|
+
* pool) rather than vibe-core's smaller placeholder, so demo behavior is
|
|
396
|
+
* unchanged. Raw usage never leaves the machine.
|
|
298
397
|
*/
|
|
299
|
-
declare function
|
|
398
|
+
declare function readUsage(harness?: Harness, opts?: HarnessUsageOptions): Promise<LocalUsageSnapshot>;
|
|
300
399
|
/**
|
|
301
400
|
* Parse a self-reported token count: a plain integer (`23400000`), or a suffixed
|
|
302
401
|
* value (`12M`, `1.2B`, `500k`, `500K`). Returns `undefined` for anything that is
|
|
@@ -324,4 +423,4 @@ declare const CANDIDATES: readonly Candidate[];
|
|
|
324
423
|
*/
|
|
325
424
|
declare function matches(myLeague: string, candidates?: readonly Candidate[]): Candidate[];
|
|
326
425
|
|
|
327
|
-
export { BELOW_LEAGUE, CANDIDATES, type Candidate, DEMO_TOTAL_TOKENS, type DiscoveryOptions, type DiscoverySession, LEAGUES, LIVE_NOTICE, type League, type PeerHello, type StoredPeer, TOKENS_ENV, TOPIC_PREFIX, allLeagueNames, league, leagueIndex, leagueTopic, leaguesWithin, loadPeers, matches, parseHandshake, parseTokensEnv, readUsage, recordPeer, serializeHandshake, startDiscovery,
|
|
426
|
+
export { BELOW_LEAGUE, CANDIDATES, type Candidate, DEMO_TOTAL_TOKENS, type DiscoveryOptions, type DiscoverySession, type HelloClaims, type Identity, type IdentityProof, type IdentityVerdict, LEAGUES, LIVE_NOTICE, type League, type LocalUsageSnapshot, type PeerHello, type StoredPeer, TOKENS_ENV, TOPIC_PREFIX, allLeagueNames, canonicalHelloClaims, classifyHelloIdentity, league, leagueIndex, leagueTopic, leaguesWithin, loadOrCreateIdentity, loadPeers, matches, parseHandshake, parseTokensEnv, readUsage, recordPeer, recordPeerMessage, serializeHandshake, signHelloClaims, startDiscovery, verifyHelloClaims };
|
package/dist/index.js
CHANGED
|
@@ -7,21 +7,26 @@ import {
|
|
|
7
7
|
TOKENS_ENV,
|
|
8
8
|
TOPIC_PREFIX,
|
|
9
9
|
allLeagueNames,
|
|
10
|
+
canonicalHelloClaims,
|
|
11
|
+
classifyHelloIdentity,
|
|
10
12
|
createConsentLedger,
|
|
11
13
|
league,
|
|
12
14
|
leagueIndex,
|
|
13
15
|
leagueTopic,
|
|
14
16
|
leaguesWithin,
|
|
17
|
+
loadOrCreateIdentity,
|
|
15
18
|
loadPeers,
|
|
16
19
|
matches,
|
|
17
20
|
parseHandshake,
|
|
18
21
|
parseTokensEnv,
|
|
19
22
|
readUsage,
|
|
20
23
|
recordPeer,
|
|
24
|
+
recordPeerMessage,
|
|
21
25
|
serializeHandshake,
|
|
26
|
+
signHelloClaims,
|
|
22
27
|
startDiscovery,
|
|
23
|
-
|
|
24
|
-
} from "./chunk-
|
|
28
|
+
verifyHelloClaims
|
|
29
|
+
} from "./chunk-43IYNWES.js";
|
|
25
30
|
export {
|
|
26
31
|
BELOW_LEAGUE,
|
|
27
32
|
CANDIDATES,
|
|
@@ -31,18 +36,23 @@ export {
|
|
|
31
36
|
TOKENS_ENV,
|
|
32
37
|
TOPIC_PREFIX,
|
|
33
38
|
allLeagueNames,
|
|
39
|
+
canonicalHelloClaims,
|
|
40
|
+
classifyHelloIdentity,
|
|
34
41
|
createConsentLedger,
|
|
35
42
|
league,
|
|
36
43
|
leagueIndex,
|
|
37
44
|
leagueTopic,
|
|
38
45
|
leaguesWithin,
|
|
46
|
+
loadOrCreateIdentity,
|
|
39
47
|
loadPeers,
|
|
40
48
|
matches,
|
|
41
49
|
parseHandshake,
|
|
42
50
|
parseTokensEnv,
|
|
43
51
|
readUsage,
|
|
44
52
|
recordPeer,
|
|
53
|
+
recordPeerMessage,
|
|
45
54
|
serializeHandshake,
|
|
55
|
+
signHelloClaims,
|
|
46
56
|
startDiscovery,
|
|
47
|
-
|
|
57
|
+
verifyHelloClaims
|
|
48
58
|
};
|
package/dist/mcp.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vibedate",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Dating by tokens — matched by usage league across agentic CLIs. Raw usage stays local; only your league is shared. CLI + local web app + MCP. Local-first.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
32
|
-
"@pooriaarab/vibe-core": "^0.
|
|
32
|
+
"@pooriaarab/vibe-core": "^0.3.0",
|
|
33
33
|
"hyperswarm": "^4.17.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|