vibedate 0.7.1 → 0.8.0

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.
@@ -1,3 +1,9 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __export = (target, all) => {
3
+ for (var name in all)
4
+ __defProp(target, name, { get: all[name], enumerable: true });
5
+ };
6
+
1
7
  // src/index.ts
2
8
  import { readHarnessUsage } from "@pooriaarab/vibe-core";
3
9
  import { createConsentLedger as createConsentLedger2 } from "@pooriaarab/vibe-core";
@@ -1378,6 +1384,7 @@ function matches(myLeague, candidates = CANDIDATES) {
1378
1384
  }
1379
1385
 
1380
1386
  export {
1387
+ __export,
1381
1388
  parseFrame,
1382
1389
  defaultStateDir,
1383
1390
  connectProfile,
package/dist/cli.js CHANGED
@@ -1,12 +1,19 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- runMcp
4
- } from "./chunk-ZD6JBWEW.js";
3
+ createPairing,
4
+ daemonStatus,
5
+ ensureHandle,
6
+ installDaemonService,
7
+ removeDaemonState,
8
+ runMcp,
9
+ startDaemon,
10
+ stopDaemon,
11
+ uninstallDaemonService,
12
+ writeDaemonState
13
+ } from "./chunk-JBADPOR5.js";
5
14
  import {
6
15
  CANDIDATES,
7
- DEFAULT_HANDLE,
8
16
  LIVE_NOTICE,
9
- MAX_HANDLE_LEN,
10
17
  ROOM_TOPIC_PREFIX,
11
18
  TOPIC_PREFIX,
12
19
  addBlock,
@@ -23,7 +30,6 @@ import {
23
30
  leagueTopic,
24
31
  leaguesWithin,
25
32
  loadBlocklist,
26
- loadHandle,
27
33
  loadOrCreateIdentity,
28
34
  loadOrCreateNostrKey,
29
35
  loadPeers,
@@ -40,423 +46,13 @@ import {
40
46
  signHelloClaims,
41
47
  startDiscovery,
42
48
  startRoom
43
- } from "./chunk-HDHJLZZG.js";
49
+ } from "./chunk-S7MO5OSO.js";
44
50
 
45
51
  // src/cli.ts
46
52
  import readline from "readline";
47
53
  import "url";
48
54
  import process2 from "process";
49
55
 
50
- // src/handlegen.ts
51
- import { randomBytes } from "crypto";
52
- var FIRST = [
53
- "segfault",
54
- "yak",
55
- "vibe",
56
- "null",
57
- "async",
58
- "await",
59
- "heap",
60
- "stack",
61
- "sudo",
62
- "regex",
63
- "token",
64
- "prompt",
65
- "context",
66
- "merge",
67
- "rebase",
68
- "hotfix",
69
- "flaky",
70
- "cursed",
71
- "based",
72
- "quantum",
73
- "turbo",
74
- "neural",
75
- "agentic",
76
- "kernel",
77
- "docker",
78
- "kube",
79
- "lambda",
80
- "pointer",
81
- "buffer",
82
- "packet",
83
- "syscall",
84
- "runtime",
85
- "monad",
86
- "borrow",
87
- "cache",
88
- "deadlock",
89
- "localhost",
90
- "darkmode",
91
- "wasm",
92
- "diff"
93
- ];
94
- var SECOND = [
95
- "sommelier",
96
- "shaver",
97
- "goblin",
98
- "nomad",
99
- "gremlin",
100
- "wizard",
101
- "bard",
102
- "pirate",
103
- "ninja",
104
- "monk",
105
- "prophet",
106
- "oracle",
107
- "smith",
108
- "farmer",
109
- "whisperer",
110
- "tamer",
111
- "connoisseur",
112
- "maximalist",
113
- "enjoyer",
114
- "dealer",
115
- "herder",
116
- "wrangler",
117
- "juggler",
118
- "mechanic",
119
- "surgeon",
120
- "detective",
121
- "librarian",
122
- "alchemist",
123
- "overlord",
124
- "apprentice",
125
- "sensei",
126
- "chef",
127
- "dj",
128
- "ranger",
129
- "paladin",
130
- "barbarian",
131
- "summoner",
132
- "cartographer",
133
- "archivist",
134
- "plumber"
135
- ];
136
- var SUFFIX = [
137
- "prime",
138
- "9000",
139
- "3000",
140
- "max",
141
- "ultra",
142
- "xl",
143
- "mk2",
144
- "777",
145
- "404",
146
- "1337",
147
- "2077",
148
- "xd"
149
- ];
150
- function cryptoRand() {
151
- return randomBytes(4).readUInt32BE(0) / 2 ** 32;
152
- }
153
- function pick(list, rand) {
154
- return list[Math.min(list.length - 1, Math.floor(rand() * list.length))];
155
- }
156
- function generateHandle(rand = cryptoRand) {
157
- const first = pick(FIRST, rand);
158
- const second = pick(SECOND, rand);
159
- let body = `${first}_${second}`;
160
- if (rand() < 0.5) {
161
- const withSuffix = `${body}_${pick(SUFFIX, rand)}`;
162
- if (withSuffix.length + 1 <= MAX_HANDLE_LEN) body = withSuffix;
163
- }
164
- const canonical = normalizeHandle(body);
165
- if (canonical === null) throw new Error(`handle generator produced an invalid handle: ${body}`);
166
- return canonical;
167
- }
168
- function ensureHandle(dir = defaultStateDir()) {
169
- const env = process.env["VIBEDATING_HANDLE"];
170
- if (env !== void 0 && env.trim() !== "") {
171
- const canonical = normalizeHandle(env);
172
- if (canonical !== null) return { handle: canonical, generated: false };
173
- }
174
- const persisted = loadHandle(dir);
175
- if (persisted !== DEFAULT_HANDLE) return { handle: persisted, generated: false };
176
- const generated = generateHandle();
177
- return { handle: saveHandle(generated, dir), generated: true };
178
- }
179
-
180
- // src/daemon.ts
181
- import { spawn, spawnSync } from "child_process";
182
- import { mkdirSync, openSync, readFileSync, rmSync, writeFileSync } from "fs";
183
- import os from "os";
184
- import path from "path";
185
- function daemonStatePath(dir) {
186
- return path.join(dir, "daemon.json");
187
- }
188
- function daemonLogPath(dir) {
189
- return path.join(dir, "daemon.log");
190
- }
191
- function readDaemonState(dir = defaultStateDir()) {
192
- try {
193
- const raw = readFileSync(daemonStatePath(dir), "utf8");
194
- const data = JSON.parse(raw);
195
- if (typeof data["pid"] !== "number" || !Number.isInteger(data["pid"]) || data["pid"] <= 0 || typeof data["startedAt"] !== "string" || typeof data["any"] !== "boolean" || typeof data["version"] !== "string") {
196
- return null;
197
- }
198
- return { pid: data["pid"], startedAt: data["startedAt"], any: data["any"], version: data["version"] };
199
- } catch {
200
- return null;
201
- }
202
- }
203
- function writeDaemonState(dir, state) {
204
- mkdirSync(dir, { recursive: true });
205
- writeFileSync(daemonStatePath(dir), JSON.stringify(state, null, 2) + "\n", "utf8");
206
- }
207
- function removeDaemonState(dir = defaultStateDir()) {
208
- try {
209
- rmSync(daemonStatePath(dir), { force: true });
210
- } catch {
211
- }
212
- }
213
- function isPidAlive(pid, kill = process.kill) {
214
- try {
215
- kill(pid, 0);
216
- return true;
217
- } catch (err) {
218
- return err.code === "EPERM";
219
- }
220
- }
221
- function daemonStatus(dir = defaultStateDir(), alive = isPidAlive) {
222
- const state = readDaemonState(dir);
223
- if (state === null) return { running: false, state: null };
224
- if (alive(state.pid)) return { running: true, state };
225
- removeDaemonState(dir);
226
- return { running: false, state: null };
227
- }
228
- function defaultSpawn(execPath, scriptPath, args, logPath) {
229
- mkdirSync(path.dirname(logPath), { recursive: true });
230
- const fd = openSync(logPath, "a");
231
- const child = spawn(execPath, [scriptPath, ...args], {
232
- detached: true,
233
- stdio: ["ignore", fd, fd]
234
- });
235
- child.unref();
236
- if (child.pid === void 0) throw new Error("could not spawn daemon child process");
237
- return child.pid;
238
- }
239
- function startDaemon(opts) {
240
- const dir = opts.dir ?? defaultStateDir();
241
- const status = daemonStatus(dir, opts.alive);
242
- if (status.running && status.state !== null) {
243
- return { started: false, reason: `already running (pid ${status.state.pid})` };
244
- }
245
- const execPath = opts.execPath ?? process.execPath;
246
- const scriptPath = opts.scriptPath ?? process.argv[1];
247
- if (scriptPath === void 0) return { started: false, reason: "cannot locate the CLI entry point" };
248
- const args = ["daemon", "run", ...opts.any ? ["--any"] : []];
249
- const spawnProcess = opts.spawnProcess ?? ((a, logPath) => defaultSpawn(execPath, scriptPath, [...a], logPath));
250
- const pid = spawnProcess(args, daemonLogPath(dir));
251
- writeDaemonState(dir, { pid, startedAt: (/* @__PURE__ */ new Date()).toISOString(), any: opts.any, version: opts.version });
252
- return { started: true, pid };
253
- }
254
- async function stopDaemon(opts = {}) {
255
- const dir = opts.dir ?? defaultStateDir();
256
- const kill = opts.kill ?? process.kill;
257
- const alive = opts.alive ?? ((pid) => isPidAlive(pid, kill));
258
- const state = readDaemonState(dir);
259
- if (state === null) return { stopped: false, reason: "not running" };
260
- if (!alive(state.pid)) {
261
- removeDaemonState(dir);
262
- return { stopped: false, reason: "not running (cleaned stale pidfile)" };
263
- }
264
- try {
265
- kill(state.pid, "SIGTERM");
266
- } catch {
267
- }
268
- const deadline = Date.now() + (opts.waitMs ?? 2e3);
269
- while (Date.now() < deadline && alive(state.pid)) {
270
- await new Promise((r) => setTimeout(r, 50));
271
- }
272
- removeDaemonState(dir);
273
- return { stopped: true, pid: state.pid };
274
- }
275
- var DAEMON_SERVICE_LABEL = "ai.vibedating.daemon";
276
- var SYSTEMD_UNIT_NAME = "vibedating.service";
277
- function daemonServicePath(platform = process.platform, homeDir = os.homedir()) {
278
- if (platform === "darwin") {
279
- return path.join(homeDir, "Library", "LaunchAgents", `${DAEMON_SERVICE_LABEL}.plist`);
280
- }
281
- if (platform === "linux") {
282
- return path.join(homeDir, ".config", "systemd", "user", SYSTEMD_UNIT_NAME);
283
- }
284
- return null;
285
- }
286
- function serviceArgv(execPath, scriptPath, any) {
287
- return [execPath, scriptPath, "daemon", "run", ...any ? ["--any"] : []];
288
- }
289
- function renderLaunchdPlist(opts) {
290
- const args = serviceArgv(opts.execPath, opts.scriptPath, opts.any).map((a) => ` <string>${a}</string>`).join("\n");
291
- return `<?xml version="1.0" encoding="UTF-8"?>
292
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
293
- <plist version="1.0">
294
- <dict>
295
- <key>Label</key>
296
- <string>${DAEMON_SERVICE_LABEL}</string>
297
- <key>ProgramArguments</key>
298
- <array>
299
- ${args}
300
- </array>
301
- <key>RunAtLoad</key>
302
- <true/>
303
- <key>KeepAlive</key>
304
- <false/>
305
- <key>StandardOutPath</key>
306
- <string>${opts.logPath}</string>
307
- <key>StandardErrorPath</key>
308
- <string>${opts.logPath}</string>
309
- </dict>
310
- </plist>
311
- `;
312
- }
313
- function renderSystemdUnit(opts) {
314
- const execStart = serviceArgv(opts.execPath, opts.scriptPath, opts.any).join(" ");
315
- return `[Unit]
316
- Description=vibedating notify-only daemon (alerts on new matches; never opens chat/video)
317
-
318
- [Service]
319
- ExecStart=${execStart}
320
- Restart=on-failure
321
- RestartSec=10
322
-
323
- [Install]
324
- WantedBy=default.target
325
- `;
326
- }
327
- var defaultRun = (cmd, args) => spawnSync(cmd, args, { stdio: "inherit" }).status === 0;
328
- function installDaemonService(opts) {
329
- const platform = opts.platform ?? process.platform;
330
- const homeDir = opts.homeDir ?? os.homedir();
331
- const run = opts.run ?? defaultRun;
332
- const servicePath = daemonServicePath(platform, homeDir);
333
- if (servicePath === null) {
334
- return {
335
- installed: false,
336
- servicePath: null,
337
- detail: `unsupported platform (${platform}) \u2014 run \`vibedate daemon start\` manually instead`
338
- };
339
- }
340
- const execPath = opts.execPath ?? process.execPath;
341
- const scriptPath = opts.scriptPath ?? process.argv[1];
342
- if (scriptPath === void 0) {
343
- return { installed: false, servicePath, detail: "cannot locate the CLI entry point" };
344
- }
345
- mkdirSync(path.dirname(servicePath), { recursive: true });
346
- if (platform === "darwin") {
347
- const logPath = daemonLogPath(opts.dir ?? defaultStateDir());
348
- writeFileSync(servicePath, renderLaunchdPlist({ execPath, scriptPath, any: opts.any, logPath }), "utf8");
349
- const uid = process.getuid?.() ?? 501;
350
- run("launchctl", ["bootout", `gui/${uid}`, servicePath]);
351
- if (!run("launchctl", ["bootstrap", `gui/${uid}`, servicePath])) {
352
- return { installed: false, servicePath, detail: "launchctl bootstrap failed \u2014 service written but not loaded" };
353
- }
354
- return { installed: true, servicePath, detail: "launchd agent installed \u2014 the daemon starts on login" };
355
- }
356
- writeFileSync(servicePath, renderSystemdUnit({ execPath, scriptPath, any: opts.any }), "utf8");
357
- run("systemctl", ["--user", "daemon-reload"]);
358
- if (!run("systemctl", ["--user", "enable", "--now", SYSTEMD_UNIT_NAME])) {
359
- return { installed: false, servicePath, detail: "systemctl enable failed \u2014 unit written but not started" };
360
- }
361
- return { installed: true, servicePath, detail: "systemd --user service installed \u2014 the daemon starts on login" };
362
- }
363
- function uninstallDaemonService(opts) {
364
- const platform = opts.platform ?? process.platform;
365
- const homeDir = opts.homeDir ?? os.homedir();
366
- const run = opts.run ?? defaultRun;
367
- const servicePath = daemonServicePath(platform, homeDir);
368
- if (servicePath === null) {
369
- return {
370
- installed: false,
371
- servicePath: null,
372
- detail: `unsupported platform (${platform})`
373
- };
374
- }
375
- if (platform === "darwin") {
376
- const uid = process.getuid?.() ?? 501;
377
- run("launchctl", ["bootout", `gui/${uid}`, servicePath]);
378
- } else {
379
- run("systemctl", ["--user", "disable", "--now", SYSTEMD_UNIT_NAME]);
380
- run("systemctl", ["--user", "daemon-reload"]);
381
- }
382
- try {
383
- rmSync(servicePath, { force: true });
384
- } catch {
385
- }
386
- return { installed: false, servicePath, detail: "login service removed \u2014 the daemon no longer starts on login" };
387
- }
388
-
389
- // src/pairing.ts
390
- function createPairing() {
391
- const queue = [];
392
- const matchCbs = /* @__PURE__ */ new Set();
393
- let current;
394
- const emit = (link) => {
395
- for (const cb of matchCbs) cb(link);
396
- };
397
- const watch = (link) => {
398
- link.onClose(() => {
399
- if (current === link) {
400
- current = void 0;
401
- const nextUp = queue.shift();
402
- if (nextUp !== void 0) {
403
- current = nextUp;
404
- emit(current);
405
- } else {
406
- emit(void 0);
407
- }
408
- } else {
409
- const idx = queue.indexOf(link);
410
- if (idx >= 0) queue.splice(idx, 1);
411
- }
412
- });
413
- };
414
- return {
415
- get available() {
416
- return queue.length;
417
- },
418
- current() {
419
- return current;
420
- },
421
- add(link) {
422
- watch(link);
423
- if (current === void 0) {
424
- current = link;
425
- emit(link);
426
- } else {
427
- queue.push(link);
428
- }
429
- },
430
- next() {
431
- if (current !== void 0) {
432
- current.close();
433
- current = void 0;
434
- }
435
- const nextUp = queue.shift();
436
- if (nextUp !== void 0) {
437
- current = nextUp;
438
- }
439
- emit(current);
440
- return current;
441
- },
442
- open(handle2) {
443
- const idx = queue.findIndex((l) => l.hello.handle === handle2);
444
- if (idx < 0) return void 0;
445
- const link = queue.splice(idx, 1)[0];
446
- if (current !== void 0) {
447
- current.close();
448
- current = void 0;
449
- }
450
- current = link;
451
- emit(current);
452
- return current;
453
- },
454
- onMatch(cb) {
455
- matchCbs.add(cb);
456
- }
457
- };
458
- }
459
-
460
56
  // src/server.ts
461
57
  import http from "http";
462
58
  import { randomUUID } from "crypto";
@@ -2608,7 +2204,7 @@ async function handle(req, res, opts) {
2608
2204
  }
2609
2205
 
2610
2206
  // src/cli.ts
2611
- var VERSION = "0.7.1";
2207
+ var VERSION = "0.8.0";
2612
2208
  function parsePort(raw) {
2613
2209
  const n = Number(raw);
2614
2210
  if (!Number.isInteger(n) || n < 1 || n > 65535) return void 0;
@@ -3084,10 +2680,16 @@ async function cmdLiveViaRelay(profile, to) {
3084
2680
  ` \xB7 relayed to ${sanitizePeerText(l.hello.handle)} (${l.hello.league}${qual} \xB7 ${l.hello.harness}) ${usageMark(l.hello)}${idMark(l.hello)}
3085
2681
  `
3086
2682
  );
3087
- l.onMessage((m) => {
3088
- process2.stdout.write(` <${sanitizePeerText(l.hello.handle)}> ${sanitizePeerText(m.text)}
2683
+ });
2684
+ pairing.onMessage((from, m) => {
2685
+ process2.stdout.write(` <${sanitizePeerText(from)}> ${sanitizePeerText(m.text)}
3089
2686
  `);
3090
- });
2687
+ });
2688
+ pairing.onQueued((from, n) => {
2689
+ process2.stdout.write(
2690
+ ` \xB7 ${sanitizePeerText(from)} sent a message (${n} queued) \u2014 /open ${sanitizePeerText(from)} to read
2691
+ `
2692
+ );
3091
2693
  });
3092
2694
  pairing.add(link);
3093
2695
  process2.stdout.write(" type to chat \xB7 /quit\n");
@@ -3166,10 +2768,16 @@ async function cmdLive(dating, any, to, keepAlive, viaRelay) {
3166
2768
  ` \xB7 matched ${sanitizePeerText(link.hello.handle)} (${link.hello.league}${qual} \xB7 ${link.hello.harness}) ${usageMark(link.hello)}${idMark(link.hello)}
3167
2769
  `
3168
2770
  );
3169
- link.onMessage((m) => {
3170
- process2.stdout.write(` <${sanitizePeerText(link.hello.handle)}> ${sanitizePeerText(m.text)}
2771
+ });
2772
+ pairing.onMessage((from, m) => {
2773
+ process2.stdout.write(` <${sanitizePeerText(from)}> ${sanitizePeerText(m.text)}
3171
2774
  `);
3172
- });
2775
+ });
2776
+ pairing.onQueued((from, n) => {
2777
+ process2.stdout.write(
2778
+ ` \xB7 ${sanitizePeerText(from)} sent a message (${n} queued) \u2014 /open ${sanitizePeerText(from)} to read
2779
+ `
2780
+ );
3173
2781
  });
3174
2782
  const { topics, acceptLeague } = discoveryScope(profile.league, any);
3175
2783
  const session = await startDiscovery({
@@ -3607,7 +3215,7 @@ Usage:
3607
3215
  --room <name> opens the room view instead: roster +
3608
3216
  group chat + full-mesh group video (~6 people; an SFU
3609
3217
  is the upgrade path for bigger rooms).
3610
- vibedating mcp Run the stdio MCP server (profile, matches)
3218
+ vibedating mcp Run the stdio MCP server (full agent-native tools: live/room/discover/media)
3611
3219
  vibedating --version
3612
3220
  vibedating --help
3613
3221