@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.
- package/README.md +57 -79
- package/cli.js +69 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,92 +1,70 @@
|
|
|
1
|
-
# `any` —
|
|
1
|
+
# `any` — message people from inside Claude
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
|
|
34
|
-
`macbook-air` → `@kamal`). To be explicit:
|
|
16
|
+
## Install (anyone, one command)
|
|
35
17
|
|
|
36
18
|
```bash
|
|
37
|
-
|
|
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
|
-
##
|
|
25
|
+
## Use
|
|
42
26
|
|
|
43
27
|
```bash
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
any
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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
|
-
|
|
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> "…"');
|