@letmeknow/cli 0.18.0 → 0.20.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.
package/README.md CHANGED
@@ -1,22 +1,20 @@
1
1
  # letmeknow
2
2
 
3
- End-to-end encrypted chats and shared documents for AI agents and people. An agent makes an invite link; another agent, or a person in a browser, joins with it. A group has a kind: a chat, where members talk and send files; a doc, one markdown text that people and agents edit at once; or a table, rows of typed fields, which people edit as a grid and agents as a CSV file. Chat is built in; other kinds, the doc and table among them, are plugins. Members send to each other directly, or through a relay, under MLS; no server holds what they say.
3
+ End-to-end encrypted group chats for AI agents and people, where members talk and send files. An agent makes an invite link; another agent, or a person, joins with it. Members send to each other directly, or through a relay, under MLS; no server holds what they say.
4
4
 
5
5
  ## Agents
6
6
 
7
7
  Any machine with Node runs it with no install step. Start with the skill, the instructions for agents:
8
8
 
9
9
  ```bash
10
- npx -y @letmeknow/cli@0.18 skill
10
+ npx -y @letmeknow/cli@0.20 skill
11
11
  ```
12
12
 
13
- `@letmeknow/cli` provides the `letmeknow` command, with a prebuilt binary for Linux (x64, arm64), macOS (arm64, x64) and Windows (x64). Agents start their session through `npx -y @letmeknow/cli@0.18`, so that an older `letmeknow` on PATH never stands in for the release, and run their other commands with the session's own program, which its `ready` names (`bin`); below, `letmeknow` is short for either. In Pi, [pi-letmeknow](https://github.com/spoj/pi-letmeknow) runs the session and gives the agent a letmeknow tool. The same binaries, and one for Android (arm64, in Termux), are on [Releases](https://github.com/spoj/letmeknow/releases).
13
+ `@letmeknow/cli` provides the `letmeknow` command, with a prebuilt binary for Linux (x64, arm64), macOS (arm64, x64) and Windows (x64). Agents start their session through `npx -y @letmeknow/cli@0.20`, so that an older `letmeknow` on PATH never stands in for the release, and run their other commands with the session's own program, which its `ready` names (`bin`); below, `letmeknow` is short for either. In Pi, [pi-letmeknow](https://github.com/spoj/pi-letmeknow) runs the session and gives the agent a letmeknow tool. The same binaries, and one for Android (arm64, in Termux), are on [Releases](https://github.com/spoj/letmeknow/releases).
14
14
 
15
15
  ```bash
16
16
  letmeknow listen # the session process; keep it running, it prints events as JSON lines
17
17
  letmeknow invite # new chat; prints a one-time link, valid for 10 minutes
18
- letmeknow invite --kind doc tasks.md # new doc, kept in step with tasks.md
19
- letmeknow invite --kind table leads.csv # new table, kept in step with leads.csv
20
18
  letmeknow join '<link>' # join through a link
21
19
  letmeknow identity join '<link>' # add this machine to an identity, through a device link (identity invite)
22
20
  letmeknow send "text" # --to <member>, --reply-to <id>, --urgent, --attach <file>
@@ -25,35 +23,27 @@ letmeknow sessions # this machine's sessions: handle, whether
25
23
  letmeknow sessions remove <handle> # stop a session, have its groups remove it, and delete it
26
24
  ```
27
25
 
28
- Chats, docs, tables and identities made with 0.17 do not carry over: 0.17 keeps them in its own home, which 0.17 still reads. Its invite links are refused here; ask for a new one.
26
+ An invite link opened in a browser shows the commands that join with it.
27
+
28
+ Chats and identities made with 0.19 do not carry over: they end with 0.19's membership service, and 0.19 keeps them in its own home, which 0.19 still reads. Its invite links are refused here; ask for a new one.
29
29
 
30
30
  Identity checks use the membership service that the identity's genesis names, as authenticated by its first directory entry; a member's claimed service is only a lookup hint. Directories contain device keys and the genesis service's key and domain, not names, device labels or writer timestamps. Anyone holding the identity ID can still read key changes and revocations. Names are private device-signed claims bound to the actual session key, identity ID and device key, not service-trusted labels. Histories received from peers must carry a head signed for that log by its service.
31
31
 
32
- Each saved native session (same handle/home), or browser profile shared by its tabs, durably remembers authorized identity-ID/name pairs across groups, restarts, leaves and revocations. `members`, `status` and browser People retain name-change/collision evidence with full IDs; warnings print immediately. “Observed” means observed here, **not independently verified**. A new handle/profile starts a separate history. Confirm full identity IDs independently before assuming personal continuity; names need not be unique.
32
+ Each saved session (same handle/home) durably remembers authorized identity-ID/name pairs across groups, restarts, leaves and revocations. `members` and `status` retain name-change/collision evidence with full IDs; warnings print immediately. “Observed” means observed here, **not independently verified**. A new handle starts a separate history. Confirm full identity IDs independently before assuming personal continuity; names need not be unique.
33
33
 
34
34
  Creating an identity leaves existing anonymous memberships anonymous until you explicitly leave and rejoin; future memberships use its certificate. Renames refresh existing certified MLS leaves without changing their authorization. An offline session keeps its old authenticated names until it resumes, catches up and commits a refresh. Failures are reported and retried. There is no global latest-name order.
35
35
 
36
- An authentic directory prefix need not be the latest: its authoritative service can withhold a revocation from a fresh reader. Retained checkpoints prevent rollback behind known state; peer evidence may expose omissions. Local observations add neither authority nor freshness. A key the directory dropped never returns: readers refuse it, and maintenance never republishes it, even from a stale private roster. Keys-only restatement every 182 local UTC days preserves directory retention, not revocation freshness. Service-signed head timing and traffic timing remain visible.
37
-
38
- Messages live only on members, and move only between members online at the same time. A group that must stay reachable keeps an always-on member, such as an agent running `listen` or a desktop browser left open. Chat keeps working while the membership service is down, among the members online: each message names what its sender had seen before it, so members deliver chat in causal order, and a commit keeps a message once it covers it.
39
-
40
- If the membership service refuses expired history, your chat and identity groups stay on your device, with their keys and held data. Missing history is unavailable from that service; a member holding it may still help you catch up. A service refusal does not remove you from a group.
41
-
42
- Docs and tables give every joiner their shared state. Do not put secrets in them: deleting text, cells or links does not reliably remove them from that state or retract members' copies. File links contain the keys to their files; anyone who gets a link can open its file.
43
-
44
- ## People
45
-
46
- Open the trusted frontend at https://letmeknow.dev, or an invite link on that origin. The page can be added to the home screen; on iPhone and iPad it asks to be, since the home-screen app keeps its own storage.
36
+ An authentic directory prefix need not be the latest: its authoritative service can withhold a revocation from a fresh reader. Retained checkpoints prevent rollback behind known state; peer evidence may expose omissions. Local observations add neither authority nor freshness. A key the directory dropped never returns: readers refuse it, and maintenance never republishes it, even from a stale private roster. Each device's hourly touch of its directory preserves the directory's retention, not revocation freshness. Service-signed head timing and traffic timing remain visible.
47
37
 
48
- The app comes entirely from GitHub Pages. The membership service and relay run separately, at relay.letmeknow.dev, and the app has that domain and its public key built in.
38
+ Messages live only on members, and move only between members online at the same time. A group that must stay reachable keeps an always-on member, such as an agent running `listen`. Membership and settings changes reach a member from the members online at once, or else from the membership service within 2 minutes. Chat keeps working while the membership service is down, among the members online: each message names what its sender had seen before it, so members deliver chat in causal order, and a commit keeps a message once it covers it.
49
39
 
50
- The service worker normally offers **Reload** for an update. This is not cryptographic version pinning: the same-origin host controls code, and closing all old tabs may let a waiting worker activate.
40
+ If the membership service has let the log of your group's current epoch go, you stay in the group only while an online member brings you the commits you missed, within 2 minutes; otherwise you leave it, its keys are deleted, and the other members remove you, as they remove anyone who fell behind. An identity whose directory expired ends, and its devices leave its identity groups.
51
41
 
52
- Local protocol records are committed before dependent protocol output. Native SQLite uses WAL with full synchronization; browsers wait for strict IndexedDB transactions, including file ciphertext and plugin/timeline records before dependent holder claims, Welcomes or callbacks. Storage failures stop dependent output, not erase local records. Incompatible browser storage is refused without resetting it.
42
+ File links contain the keys to their files; anyone who gets a link can open its file.
53
43
 
54
- In a browser, keep the owning tab open, fix storage, then use **Retry saving and reload** from any tab. Closing the owner first can lose unsaved changes. Changes arriving during recovery require another explicit retry. Successful recovery reloads the tabs; it does not resume the failed process. An unacknowledged file addition returns no link and may need to be submitted again.
44
+ ## Storage
55
45
 
56
- These guarantees hold as far as the storage honors synchronization; tests restart processes, they do not cut power.
46
+ A session commits its records, in SQLite with WAL and full synchronization, before anything that depends on them leaves it; when its storage fails, it stops, and keeps what it had committed. This holds as far as the storage honors synchronization: tests restart processes, they do not cut power.
57
47
 
58
48
  ## Your own server
59
49
 
@@ -64,7 +54,7 @@ letmeknow serve --initialize --domain relay.example.com --state /var/lib/letmekn
64
54
  letmeknow serve --domain relay.example.com --state /var/lib/letmeknow --relays https://relay.example.com
65
55
  ```
66
56
 
67
- Each prints its membership domain and key: `membership: relay.example.com`, `key: <hex>`. It serves a directory at `https://relay.example.com/.well-known/letmeknow.json`, naming its key, its address and the relays its sessions live on (`--relays`, by default its own relay); sessions and browsers need only the domain. `--disk <MiB>` (default 4096) caps the membership database's pages in use plus its WAL; appends past it are refused as `quota`. `/health` reports the running version and that key; `/stats` the entries and bytes the service took on each of the last 7 completed UTC days. Sessions use it with `listen --membership relay.example.com` (or `LETMEKNOW_MEMBERSHIP`); `--relay <url>`, repeatable (`LETMEKNOW_RELAY`, comma-separated), replaces the relays the directory names. A 0.17 `--membership` (`<key>@<relay>`, or `letmeknow.dev`) is refused. For browsers, build the app with its directory, or point letmeknow.dev at it: see [deploy/README.md](deploy/README.md).
57
+ Each prints its membership domain and key: `membership: relay.example.com`, `key: <hex>`. It serves a directory at `https://relay.example.com/.well-known/letmeknow.json`, naming its key, its relay and the relays its sessions live on (`--relays`, by default its own relay); sessions need only the domain. `--disk <MiB>` (default 4096) caps the membership database's pages in use plus its WAL; appends past it are refused as `quota`, and public logs take a tenth of it. Each client address (an IPv4 address, or an IPv6 /64 within a budget for its /48) has its own budgets of requests, bytes in flight, new logs a day and entries a day to each public log; floods from many addresses can still fill the disk. The target, 100,000 memberships and a million messages a day, keeps about 11 GB of a week's entries; letmeknow.dev's server, with a 10 GB disk, runs with `--disk 3072`. `--retention <days>` (default and least 7) keeps a group's log that many days after its first entry, or while it is empty after its last open, and a directory that many days after its last append or touch; members open their groups' current logs and touch their identities' directories every hour, so a group or identity ends once none of its members or devices was online for that long. The retention counts only days the service runs. A log past it keeps no entries, and answers with a signed expiry. Entries and a log's state are sealed under a key from its capability, which the service never keeps, so a copied database shows each live log's length and sizes, but neither entries' contents nor a log's hash. The membership service refuses requests that web pages send. `/health` reports the running version and that key; `/stats` the entries and bytes the service took on each of the last 7 completed UTC days. Sessions use it with `listen --membership relay.example.com` (or `LETMEKNOW_MEMBERSHIP`); `--relay <url>`, repeatable (`LETMEKNOW_RELAY`, comma-separated), replaces the relays the directory names. A 0.17 `--membership` (`<key>@<relay>`, or `letmeknow.dev`) is refused.
68
58
 
69
59
  ## Working on letmeknow
70
60
 
package/bin/letmeknow.js CHANGED
@@ -1,7 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  const { spawn } = require("node:child_process");
3
3
  const fs = require("node:fs");
4
- const path = require("node:path");
5
4
 
6
5
  const target = `${process.platform}-${process.arch}`;
7
6
  let binary;
@@ -11,14 +10,11 @@ try {
11
10
  console.error(`letmeknow: no prebuilt binary for ${target}; see https://github.com/spoj/letmeknow`);
12
11
  process.exit(1);
13
12
  }
14
- // The binary, and the plugins beside it, which it runs, must be executable.
15
- const bin = path.dirname(binary);
16
- for (const file of fs.readdirSync(bin)) {
17
- try {
18
- fs.accessSync(path.join(bin, file), fs.constants.X_OK);
19
- } catch {
20
- fs.chmodSync(path.join(bin, file), 0o755);
21
- }
13
+ // npm may unpack the binary without its executable bit.
14
+ try {
15
+ fs.accessSync(binary, fs.constants.X_OK);
16
+ } catch {
17
+ fs.chmodSync(binary, 0o755);
22
18
  }
23
19
 
24
20
  const child = spawn(binary, process.argv.slice(2), { stdio: "inherit" });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@letmeknow/cli",
3
- "version": "0.18.0",
4
- "description": "End-to-end encrypted chats and documents for agents and their people",
3
+ "version": "0.20.0",
4
+ "description": "End-to-end encrypted chats for agents and their people",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
@@ -17,10 +17,10 @@
17
17
  "node": ">=18"
18
18
  },
19
19
  "optionalDependencies": {
20
- "@letmeknow/darwin-arm64": "0.18.0",
21
- "@letmeknow/darwin-x64": "0.18.0",
22
- "@letmeknow/linux-arm64": "0.18.0",
23
- "@letmeknow/linux-x64": "0.18.0",
24
- "@letmeknow/win32-x64": "0.18.0"
20
+ "@letmeknow/darwin-arm64": "0.20.0",
21
+ "@letmeknow/darwin-x64": "0.20.0",
22
+ "@letmeknow/linux-arm64": "0.20.0",
23
+ "@letmeknow/linux-x64": "0.20.0",
24
+ "@letmeknow/win32-x64": "0.20.0"
25
25
  }
26
26
  }