@kamal0808/anytoany 0.3.0 → 0.3.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.
Files changed (3) hide show
  1. package/README.md +57 -79
  2. package/cli.js +69 -1
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,92 +1,70 @@
1
- # `any` — Milestone 1
1
+ # `any` — message people from inside Claude
2
2
 
3
- A deliberately tiny message relay + CLI so two machines (each running a Claude
4
- Code session) can **send / inbox / reply** and, once that feels magical,
5
- **delegate tasks**.
3
+ Send a message to a friend and it lands **inside their Claude Desktop** — a
4
+ banner pops, they click it, a Claude Code session opens that reads the message
5
+ and helps them reply. AI-mediated messaging, human-in-the-loop.
6
6
 
7
- No auth. No websockets. No database. One ~180-line HTTP server over a JSON file,
8
- and one CLI. Zero dependencies (Node ≥ 18 for global `fetch`; you have 25).
9
-
10
- ```
11
- MacBook Air (@kamal) Mac Mini (@yash)
12
- any CLI ─────────┐ ┌─────── any CLI
13
- ▼ ▼
14
- relay.js on the Mac Mini (Tailscale 100.92.24.17:4747)
15
- └─ data/messages.json
16
7
  ```
17
-
18
- ## Setup (once per machine)
19
-
20
- Requires **Node 18** (for global `fetch`). Note the `any` shim runs whatever
21
- `node` is first on your `PATH` — if a shell defaults to an old Node (e.g. nvm
22
- pinned to 14), bare `any` will crash. Fix per machine with `nvm use` (an
23
- `.nvmrc` pinning 22 is included) or, to make it stick for every shell:
24
- `nvm alias default 22`.
25
-
26
- From the repo root on **each** Mac:
27
-
28
- ```bash
29
- cd any
30
- npm link # puts `any` on your PATH (or just use: node any/cli.js …)
8
+ you: any send @friend "hey"
9
+ hosted relay (Cloudflare Worker + D1)
10
+ → friend's machine: watcher polls (cheap, 0 tokens idle)
11
+ 🔔 clickable macOS banner
12
+ click claude://code/new opens a Claude Code session IN Claude Desktop
13
+ runs `any inbox` reads drafts friend approves any reply → back to you
31
14
  ```
32
15
 
33
- Identity is auto-detected from hostname (`mac-mini` `@yash`,
34
- `macbook-air` → `@kamal`). To be explicit:
16
+ ## Install (anyone, one command)
35
17
 
36
18
  ```bash
37
- any register @kamal # on the MacBook Air
38
- any register @yash # on the Mac Mini
19
+ npx @kamal0808/anytoany@latest setup
39
20
  ```
21
+ Pick a unique `@handle` (+ optional display name). No token, no secrets. It
22
+ registers you, installs a background banner watcher, and you're on the network.
23
+ macOS + Node 18+ + Claude Desktop.
40
24
 
41
- ## Run the relay (on the Mac Mini — it's always on)
25
+ ## Use
42
26
 
43
27
  ```bash
44
- cd any
45
- node relay.js # listens on 0.0.0.0:4747
28
+ any send @handle "text" # message anyone by their handle
29
+ any inbox # your new messages
30
+ any read <id> # open one
31
+ any reply <id> "text" # reply
32
+ any whoami # your handle + status
46
33
  ```
47
34
 
48
- The default relay URL baked into the CLI is the Mac Mini's Tailscale IP
49
- (`http://100.92.24.17:4747`), so both Macs already point at it. Override with:
50
-
51
- ```bash
52
- any relay http://100.92.24.17:4747
53
- # or: export ANY_RELAY_URL=...
54
- ```
55
-
56
- Check it from either machine:
57
-
58
- ```bash
59
- any whoami # shows identity + "relay: online"
60
- ```
61
-
62
- ## The five commands
63
-
64
- ```bash
65
- any send @yash transcript.md # a file becomes subject + body
66
- any send @yash "quick question…" # or send plain text
67
- any inbox # unread messages for you
68
- any read 3 # show #3 in full (marks it read)
69
- any reply 3 "Looks good. Ship it." # reply goes back to the sender
70
- any watch # live-poll the inbox (agent mode)
71
- ```
72
-
73
- ## The 60-second demo
74
-
75
- 1. **Mac Mini:** `node any/relay.js` (leave it running).
76
- 2. **MacBook Air:** `any send @yash transcript.md`
77
- 3. **Mac Mini:** `any inbox` → `any read 1` → `any reply 1 "Looks good. Ship it."`
78
- 4. **MacBook Air:** `any inbox` → the reply is there.
79
-
80
- That's the illusion. If it feels magical, it's worth showing to someone.
81
-
82
- ## Milestone 3 delegation (the actual point)
83
-
84
- The Mac Mini already has a Claude Code session. Paste `OPERATOR-YASH.md` into it
85
- once. From then on it runs `any watch`, and when a task arrives it executes it in
86
- Claude Code and replies with the result — autonomously. See that file.
87
-
88
- ## Config & env
89
-
90
- - Config file: `~/.any/config.json` (`{ user, relay }`)
91
- - Env overrides: `ANY_USER`, `ANY_RELAY_URL`, `ANY_HOME`
92
- - Relay env: `ANY_PORT`, `ANY_HOST`, `ANY_DATA_DIR`
35
+ ## How it works
36
+
37
+ - **Accounts:** each person claims a unique `@handle` and gets their own key.
38
+ `from` is server-verified (no spoofing); you can only read your own inbox.
39
+ Registration is open (anyone can claim a handle and DM anyone by handle).
40
+ - **Relay:** a Cloudflare Worker + D1 (`worker/`) — always-on, edge, durable.
41
+ URL: `https://anytoany-relay.kamalkhatwani69.workers.dev`.
42
+ - **CLI:** `cli.js` — published to npm as `@kamal0808/anytoany` (bin `any`).
43
+ - **Watcher banner → Desktop:** `any poke` (run by a launchd agent every ~15s)
44
+ fires a `terminal-notifier` banner whose click opens
45
+ `claude://code/new?q=…` — a *tool-capable* Claude Code session inside Claude
46
+ Desktop (it can run `any`). Set up automatically by `any setup`. macOS-only.
47
+
48
+ ## Layout
49
+
50
+ | Path | What |
51
+ |---|---|
52
+ | `cli.js` | the `any` CLI (published to npm) |
53
+ | `worker/` | the relay: Cloudflare Worker (`worker.js`) + D1 schema (`schema.sql`) |
54
+ | `relay.js` | legacy standalone Node relay (superseded by the Worker) |
55
+ | `SETUP-YASH.md` | copy-paste onboarding to send a friend |
56
+ | `CLAUDE.md` | operator notes for maintaining/deploying this |
57
+
58
+ ## Maintaining it
59
+
60
+ - **Deploy the relay:** `cd worker && npx wrangler deploy` (needs `wrangler login`).
61
+ - **Publish the CLI:** bump `version` in `package.json`, then
62
+ `npm publish --access public` (needs npm login + 2FA).
63
+ - See `CLAUDE.md` for the full operator playbook and known rough edges.
64
+
65
+ ## Not built yet
66
+
67
+ - One persistent Claude thread for all messaging (deep links only open new
68
+ sessions; would need the MCP-connector + fixed-chat approach).
69
+ - A dedicated `~/anytoany` folder per install (groups sessions, path-independent).
70
+ - Spam/abuse controls (blocking, invite-only, rate limits) — registration is open.
package/cli.js CHANGED
@@ -302,8 +302,22 @@ async function cmdPoke() {
302
302
  try {
303
303
  fs.mkdirSync(lockPath); // single-flight
304
304
  } catch {
305
- return;
305
+ // lock exists — break it if stale (a killed tick / network die() can leak it)
306
+ try {
307
+ if (Date.now() - fs.statSync(lockPath).mtimeMs > 60000) {
308
+ fs.rmdirSync(lockPath);
309
+ fs.mkdirSync(lockPath);
310
+ } else return;
311
+ } catch {
312
+ return;
313
+ }
306
314
  }
315
+ // release the lock even if a later die()/process.exit() skips the finally block
316
+ process.on('exit', () => {
317
+ try {
318
+ fs.rmdirSync(lockPath);
319
+ } catch {}
320
+ });
307
321
  try {
308
322
  const { messages } = await api(relay, 'GET', `/inbox`);
309
323
  if (!messages || !messages.length) return;
@@ -344,6 +358,57 @@ function have(cmd) {
344
358
  }
345
359
  }
346
360
 
361
+ // the anytoany skill — teaches any Claude Code session how to use `any`
362
+ function skillMd(handle) {
363
+ return `---
364
+ name: anytoany
365
+ description: Message people from the terminal via the \`any\` CLI (anytoany messaging). Use whenever the user wants to send or DM a message (or the current conversation) to a person or @handle, check their anytoany inbox, or reply to a message they received. Needs a shell (Claude Code / Cowork session).
366
+ ---
367
+
368
+ # anytoany — messaging via the \`any\` CLI
369
+
370
+ \`any\` sends messages between people through a hosted relay; a message lands in the
371
+ recipient's Claude Desktop as a banner they click to read & reply.
372
+
373
+ **On this machine you are \`${handle}\`.** Run the \`any\` CLI in the shell to act.
374
+
375
+ ## Commands
376
+ | Intent | Command |
377
+ |---|---|
378
+ | Send a message | \`any send @handle "message text"\` |
379
+ | Check new messages | \`any inbox\` (or \`any inbox --all\`) |
380
+ | Read one (marks read) | \`any read <id>\` |
381
+ | Reply to one | \`any reply <id> "text"\` |
382
+ | Who am I / status | \`any whoami\` |
383
+
384
+ ## Common asks
385
+ - "send X to @bob" → \`any send @bob "X"\`
386
+ - "send this thread to @bob" → summarize the conversation, show me, then on my ok: \`any send @bob "<summary>"\`
387
+ - "anything new?" → \`any inbox\`, then offer to read/reply
388
+ - "reply to #<id>" → draft it, then \`any reply <id> "<reply>"\`
389
+
390
+ ## Contacts
391
+ Use the \`@handle\` the person gave you. Add friends here as you learn them
392
+ (e.g. \`@pulkit\` — Pulkit). If you don't know someone's handle, ask.
393
+
394
+ ## Rules
395
+ - Handles are lowercase slugs \`a-z 0-9 _ -\`, no spaces.
396
+ - **Always confirm the exact message text with me before sending.**
397
+ - Needs a terminal — works in a Claude Code / Cowork session, not a plain chat.
398
+ `;
399
+ }
400
+
401
+ function installSkill(handle) {
402
+ try {
403
+ const dir = path.join(os.homedir(), '.claude', 'skills', 'anytoany');
404
+ fs.mkdirSync(dir, { recursive: true });
405
+ fs.writeFileSync(path.join(dir, 'SKILL.md'), skillMd(handle));
406
+ return true;
407
+ } catch {
408
+ return false;
409
+ }
410
+ }
411
+
347
412
  // one-command onboarding: claim a handle (get your key) + install the watcher
348
413
  async function cmdSetup() {
349
414
  const cfg = loadConfig();
@@ -379,6 +444,9 @@ async function cmdSetup() {
379
444
  const me = await api(cfg.relay, 'GET', '/whoami').catch(() => null);
380
445
  console.log(me ? `✓ connected as ${me.handle}` : '! could not verify with relay (continuing)');
381
446
 
447
+ // install the skill so any Claude Code session knows how to use `any`
448
+ console.log(installSkill(user) ? '✓ anytoany skill installed (Claude now knows how to message)' : '! could not install skill');
449
+
382
450
  if (process.platform !== 'darwin') {
383
451
  console.log('\nThe background banner watcher is macOS-only for now.');
384
452
  console.log('You can still use: any inbox / any read <id> / any reply <id> "…"');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kamal0808/anytoany",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "type": "module",
5
5
  "description": "Tiny CLI to send/inbox/reply messages between Claude Code sessions via the anytoany relay",
6
6
  "bin": {