vibedate 0.1.1 → 0.2.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 CHANGED
@@ -11,8 +11,9 @@ Part of the **Vibe Suite** — companion tools for agentic coding CLIs. Ships as
11
11
 
12
12
  > **Local-first.** Raw token usage is read and stored on your own machine and
13
13
  > **never leaves it.** Only the coarse league *bucket* is ever shared — never the
14
- > raw number, never per-project breakdowns. v0 has no central directory; the match
15
- > pool is a local seeded demo.
14
+ > raw number, never per-project breakdowns. Live matching is peer-to-peer over a
15
+ > DHT (no central server) and **opt-in only**; without it the pool is a local
16
+ > seeded demo.
16
17
 
17
18
  ## Status
18
19
 
@@ -42,7 +43,10 @@ vibedating connect
42
43
  # 2. See candidates in your league (same or adjacent tier)
43
44
  vibedating matches
44
45
 
45
- # 3. Open the local web app in your browser (served from your machine)
46
+ # 3. (Opt-in) find live same-league peers over the DHT no server
47
+ vibedating discover --live # shares ONLY handle + league + harness
48
+
49
+ # 4. Open the local web app in your browser (served from your machine)
46
50
  vibedating open
47
51
  ```
48
52
 
@@ -56,13 +60,27 @@ VIBEDATING_TOKENS=23400000 vibedating connect # also accepts 12M / 1.2B / 500k
56
60
 
57
61
  ```
58
62
  vibedating connect Read usage, compute + print your league
59
- vibedating matches List candidates in your league
63
+ vibedating matches [--live] List candidates in your league (live peers if any)
64
+ vibedating discover [--live] Find live same-league peers over the DHT (opt-in)
60
65
  vibedating open [--port N] Serve the local web app (default: random free port)
61
66
  vibedating mcp Run the stdio MCP server (tools: profile, matches)
62
67
  vibedating --version
63
68
  vibedating --help
64
69
  ```
65
70
 
71
+ ### Live P2P discovery (opt-in)
72
+
73
+ `vibedating discover --live` joins the public [hyperswarm](https://github.com/holepunchto/hyperswarm)
74
+ DHT on your league topic — `sha256('vibedate:' + leagueBucket)` — so same-league
75
+ peers find each other with **no central server**. On each encrypted connection
76
+ the two sides exchange a one-line hello with exactly
77
+ `{ handle, league, harness }`; raw usage is never put on the wire. Discovered
78
+ peers are stored in `~/.vibedating/peers.json` and shown by `vibedating matches`.
79
+
80
+ Live discovery is **off by default**. The `--live` flag is the explicit opt-in
81
+ (persisted as the `share:live` consent scope); every live run prints what it
82
+ shares before joining. `Ctrl+C` leaves the swarm cleanly.
83
+
66
84
  ## Three faces, one local engine
67
85
 
68
86
  The same local engine drives all three, so you can use it wherever you work:
@@ -89,9 +107,13 @@ const who = matches(lg.name, CANDIDATES); // same/adjacent-tier candidat
89
107
  - **Raw usage stays local.** `totalTokens` is read into memory, stored at
90
108
  `~/.vibedating/state.json`, and shown in the web app only behind an opt-in
91
109
  toggle. It is never transmitted.
92
- - **Only the league bucket is shared** (and in v0, only with the local demo pool).
110
+ - **Only the league bucket is shared** with the local demo pool, and (only if
111
+ you opt in with `--live`) as `{ handle, league, harness }` with same-league
112
+ peers over the hyperswarm DHT. The handshake parser whitelists those three
113
+ fields, so a peer can't even be *sent* anything else into your process.
93
114
  - Consent for sharing the league is modeled with `@pooriaarab/vibe-core`'s consent
94
115
  ledger (scope `share:league`), granted on `connect` and revocable on reset.
116
+ Live P2P discovery has its own scope (`share:live`), default **off**.
95
117
 
96
118
  ## Leagues & matching
97
119
 
@@ -1,73 +1,12 @@
1
1
  import {
2
2
  CANDIDATES,
3
- league,
3
+ loadProfile,
4
4
  matches
5
- } from "./chunk-AU7FN2LY.js";
5
+ } from "./chunk-6NWF2VD7.js";
6
6
 
7
7
  // src/mcp.ts
8
8
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
9
9
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
10
-
11
- // src/state.ts
12
- import { mkdirSync, readFileSync, rmSync, writeFileSync } from "fs";
13
- import os from "os";
14
- import path from "path";
15
- import { createConsentLedger } from "@pooriaarab/vibe-core";
16
- var CONSENT_SCOPE = "share:league";
17
- function defaultStateDir() {
18
- return path.join(os.homedir(), ".vibedating");
19
- }
20
- var FileConsentStore = class {
21
- constructor(file) {
22
- this.file = file;
23
- }
24
- file;
25
- load() {
26
- try {
27
- const raw = readFileSync(this.file, "utf8");
28
- const data = JSON.parse(raw);
29
- return data.grants ?? [];
30
- } catch {
31
- return [];
32
- }
33
- }
34
- save(grants) {
35
- mkdirSync(path.dirname(this.file), { recursive: true });
36
- writeFileSync(this.file, JSON.stringify({ grants }, null, 2) + "\n", "utf8");
37
- }
38
- };
39
- function createLedger(dir = defaultStateDir()) {
40
- return createConsentLedger(new FileConsentStore(path.join(dir, "consent.json")));
41
- }
42
- function profilePath(dir) {
43
- return path.join(dir, "state.json");
44
- }
45
- function connectProfile(snapshot, handle, dir = defaultStateDir()) {
46
- const lg = league(snapshot.totalTokens);
47
- createLedger(dir).grant(CONSENT_SCOPE, "connect: league bucket only; raw usage stays local");
48
- const state = {
49
- handle,
50
- harness: snapshot.harness,
51
- league: lg.name,
52
- leagueMin: lg.min,
53
- totalTokens: snapshot.totalTokens,
54
- verified: snapshot.verified,
55
- connectedAt: (/* @__PURE__ */ new Date()).toISOString()
56
- };
57
- mkdirSync(dir, { recursive: true });
58
- writeFileSync(profilePath(dir), JSON.stringify(state, null, 2) + "\n", "utf8");
59
- return state;
60
- }
61
- function loadProfile(dir = defaultStateDir()) {
62
- try {
63
- const raw = readFileSync(profilePath(dir), "utf8");
64
- return JSON.parse(raw);
65
- } catch {
66
- return null;
67
- }
68
- }
69
-
70
- // src/mcp.ts
71
10
  function textBlock(text) {
72
11
  return { type: "text", text };
73
12
  }
@@ -120,7 +59,5 @@ async function runMcp() {
120
59
  }
121
60
 
122
61
  export {
123
- connectProfile,
124
- loadProfile,
125
62
  runMcp
126
63
  };