@primitivedotdev/map 0.0.0-stage → 0.2.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/CONFORMANCE.md ADDED
@@ -0,0 +1,116 @@
1
+ # map transport conformance
2
+
3
+ map is plain email. The `map` CLI does all its mail
4
+ through one small interface, `Transport` (`packages/map-public/src/transport.ts`), so
5
+ map can run on any mail provider that has an adapter for it. This suite is how
6
+ an adapter shows that it carries map: it checks the interface rules on the
7
+ adapter directly, then runs the real `map` commands (get, send, update, wait,
8
+ approve, object, argue, history) end to end against a map repo, through the
9
+ adapter. Files and mail only: no git.
10
+
11
+ It is meant to be clear and honest, not exhaustive. A pass means these checks
12
+ passed on that date with those two mailboxes; it is not a load test or a
13
+ security audit.
14
+
15
+ ## The interface
16
+
17
+ An adapter is an ES module whose default export returns a `Transport`:
18
+
19
+ | Method | Rule |
20
+ | --- | --- |
21
+ | `send({ from, fromName?, to, subject, body, attachments? })` | Sends a new message (not a reply) and returns a non-empty id, different for each send, that `waitReply` accepts. Attachments are file paths; each arrives under its file name, byte for byte. `fromName`, when given, is the From display name. |
22
+ | `waitReply(sentId, { me, from, timeoutSec, since? })` | The earliest reply to that sent message, from `from` to `me`, received at or after `since`. Each call returns one reply; callers step past it with `since`. Replies that arrived before the call count. A timeout returns `null`; it is not an error. |
23
+ | `get(id)` | The message: subject, sender, recipient, received time, plain text body, attachments (file name and part index), and when the provider has them `message_id`, `in_reply_to`, `references` and `from_header`. |
24
+ | `download(id, part, out)` | Saves one attachment to `out` and returns its bytes. |
25
+ | `reply(id, { from, body })` | Replies on the thread of an inbound message, so its In-Reply-To and References name that message. |
26
+ | `list({ me, after?, limit?, cursor? })` | Inbound mail to `me` only, newest first, a page at a time. |
27
+ | `tail({ me, cursor?, from?, limit?, wait? })` | New inbound mail to `me` only, oldest first, after a cursor (or a time on the first call); returns the next cursor. `wait` may long-poll. |
28
+ | `search({ me, q?, from?, to?, subject?, body?, threadId?, sort?, limit?, cursor? })` | Mail that matches, newest first by default, and when it can, the provider command that ran it (map prints it so people learn the mailbox is the record). map's history commands are built on it. |
29
+ | `defaultAddress()` | The address this login sends from when it has exactly one, else `null`. |
30
+ | `describe()` (optional) | Provider name and version, for the report. |
31
+
32
+ Pick an adapter with `MAP_TRANSPORT`: a built in name (`primitive`) or the
33
+ path of the module.
34
+
35
+ ## The checks
36
+
37
+ Run in this order. Later checks are skipped when one they build on failed.
38
+
39
+ | # | Check | How |
40
+ | --- | --- | --- |
41
+ | 1.1 | send returns a stable id | A sends B two mails: two distinct ids, both delivered. |
42
+ | 1.2 | an attachment round-trips | A sends B 4096 random bytes (with NUL, 0xff and CRLF) as `conformance-blob.bin`; B reads the same name and bytes. |
43
+ | 1.3 | waitReply returns each reply once, in order | B replies twice to a mail from A before A waits; A's waits return reply one, then reply two, then time out. |
44
+ | 1.4 | a reply threads | The reply's In-Reply-To and References name the Message-ID of the mail it answers. |
45
+ | 1.5 | the inbox is mine only | `list` and `tail` for A, and `list` for B, hold only mail to that address. |
46
+ | 1.6 | a timeout is a timeout | A 5 s `waitReply` with no reply returns `null` and does not throw. |
47
+ | 1.7 | search | A mails B a unique word; a search of B's mail for the word, and one by subject, return it, and nothing addressed elsewhere. |
48
+ | 2.0 | create a repo by email | B mails `new@<host>` with `Map-Create`, `Map-Handle` and `Map-Allow: <A>`; B owns the new repo. |
49
+ | 2.1 | get, edit, send | A runs `map get <repo> a`, edits, `map send`: landed. `map update` then leaves `map diff` empty. |
50
+ | 2.2 | conflict, update, send | B gets a copy, A lands an edit to line one, B sends its own edit of line one: conflict naming the file. B's `map update` writes conflict markers; B resolves and sends: landed. |
51
+ | 2.3 | binary and rename | A adds a PNG and renames a file and sends; a fresh `map get` matches A's folder byte for byte. |
52
+ | 2.4a | consent on | B sends `map settings <repo> "Map-Consent: owners" "Map-Consent-Window: 5"`. |
53
+ | 2.4 | consent ask, approve | B changes a line A wrote. A gets `[map consent <pid>]`; `map approve <pid>` lands B's change. |
54
+ | 2.5 | objection and argument | B changes another of A's lines; A runs `map object`; B's `map send` reports A's objection; B runs `map argue`; A gets the round 2 ask for that same push, quoting B's argument; A approves and B's `map wait` returns LANDED. |
55
+ | 2.6 | history is mail | `map history` finds the objection in B's mail; `map log` lists the commits (from commit mail in this account, or from the repo's answer to a `Map-Log` mail). |
56
+ | 3.1 | forged display name | A sends the repo a settings line with From `"<B>" <A>` (B owns the repo). The repo must not apply it. |
57
+
58
+ B owns the repo and A only contributes because map never asks a repo owner for
59
+ consent as a line owner.
60
+
61
+ ## Running it
62
+
63
+ You need Node 22 or newer and two mailboxes (A and B) that the adapter can
64
+ send from and read, both able to get mail from the repo host.
65
+
66
+ ```sh
67
+ npm install -g @primitivedotdev/map # map-conformance comes with it
68
+ map-conformance transport --adapter ./my-adapter.mjs \
69
+ --a alice@example.org --b bob@example.org \
70
+ [--repo-host map.dev] [--json] [--out report.md]
71
+ ```
72
+
73
+ `--adapter primitive` uses the built in Primitive adapter. The run takes
74
+ about 5 to 10 minutes, mostly map's review of each push. It prints each check
75
+ as it goes, then a Markdown report (JSON with `--json`). Exit status is 0
76
+ only when every check passed.
77
+
78
+ The run creates its own repo by email from B, so it needs nothing from the
79
+ repo host's operators. The host allows 5 new repos per address and 20 per
80
+ domain in any 24 hours. If B cannot create one, pass `--repo <address>` for a
81
+ repo that B owns and A may send to; it should be fresh, since the checks edit
82
+ `notes.txt`, `docs/` and `assets/`. A new address gets a handle on its first
83
+ repo (`--handle` picks it; an address that has one keeps it).
84
+
85
+ ## What these checks cannot tell you
86
+
87
+ - 3.1 shows what the repo did with the mail the adapter sent. Whether a
88
+ forged display name is caught depends on the repo host checking the From
89
+ address and the provider's DKIM or DMARC results, not on the adapter alone.
90
+ - Search covers inbound mail only (on Primitive, `primitive emails search`).
91
+ It cannot see mail you sent: your changes, arguments and replies, unless
92
+ the repo copied them back to you. The repo's own mail (its commit log,
93
+ reviews, verdicts to others) is inbound only for the account that hosts
94
+ the repo; everyone else sees what map sent them, and `map log` asks the
95
+ repo by mail (`Map-Log`) when the mailbox holds no commit mail.
96
+ - 1.4 needs the adapter to report Message-ID and In-Reply-To. An adapter that
97
+ cannot will fail it, even if its replies do thread.
98
+ - Times in the report include map's review and the provider's delivery; they
99
+ are not a benchmark.
100
+
101
+ ## Adding a provider
102
+
103
+ A pull request for a new provider must include:
104
+
105
+ 1. The adapter under `packages/transports/<provider>/`, as its own module
106
+ whose default export returns a `Transport`. It may import only the types
107
+ from `packages/map-public/src/transport.ts`.
108
+ 2. A `README.md` there that says how to log in, what the two mailboxes need
109
+ (accounts, domains, DNS) and any limits.
110
+ 3. The report of a passing run, committed as
111
+ `packages/map-public/conformance/<provider>.md`.
112
+ 4. No provider code anywhere else: no changes to the CLI, the engine or other
113
+ adapters.
114
+
115
+ `packages/transports/primitive/` is the reference, and
116
+ [`conformance/primitive.md`](conformance/primitive.md) is its report.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Primitive
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,48 @@
1
- # Temporary Holding Version
1
+ # @primitivedotdev/map
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ The `map` command for [map.dev](https://www.map.dev), where every repo is an email address (`owner-repo@map.dev`) and everything about it is mail: you get the code as an attachment, send a change as a patch, and the reviews, verdicts and history arrive as mail too.
4
+
5
+ ## Setup
6
+
7
+ ```sh
8
+ npx -y @primitivedotdev/map init
9
+ ```
10
+
11
+ `init` checks your mail login (the `primitive` CLI is the first supported provider), puts `map` on your PATH, records the address you send from, and installs the agent skill. Agents can run it unattended with `--provider primitive --yes`. Node 22 or newer.
12
+
13
+ ## The flow
14
+
15
+ ```sh
16
+ map get owner-repo@map.dev work && cd work # the code at the tip, in a folder
17
+ # edit the files
18
+ map diff # what you would send
19
+ map send "Add retries to the fetcher" # mails the change and waits for the verdict
20
+ map update # bring the folder to the new tip
21
+ ```
22
+
23
+ If the verdict takes longer than the wait, `map send` prints `PENDING` with the push id; `map wait <push id>` keeps waiting.
24
+
25
+ When someone changes lines you wrote, you are asked first:
26
+
27
+ ```sh
28
+ map inbox # mail that needs you
29
+ map show <push id> # the ask in full, with the diff
30
+ map approve <push id> # or: map object <push id> "<reason>"
31
+ map argue <push id> "<text>" # answer an objection to your change
32
+ ```
33
+
34
+ History is mail search: `map log` lists commits, `map history <words>` finds the reviews, objections and arguments, and each prints the search it ran.
35
+
36
+ ## More
37
+
38
+ - `map help` lists every command.
39
+ - `map skill` prints the agent skill.
40
+ - `map conformance transport` checks a mail provider adapter; see `CONFORMANCE.md`.
41
+
42
+ ## Other mail providers
43
+
44
+ map talks to mail through a transport adapter, and the `primitive` CLI is the first one. An adapter for another provider is a module that implements the transport interface (`map` loads it from `MAP_TRANSPORT=<path>`); `map conformance transport --adapter <path>` checks it against a real mailbox, and `CONFORMANCE.md` describes the checks. Contributions of new adapters are welcome.
45
+
46
+ ## License
47
+
48
+ MIT. Bundled third-party code and its license are listed in `THIRD-PARTY-NOTICES`.
package/SKILL.md ADDED
@@ -0,0 +1,89 @@
1
+ ---
2
+ name: map
3
+ description: Work on a map repo, a code host where each repo is an email address like owner-repo@map.dev, with plain files and email. Use when a task names a map.dev repo address, or when mail with a "[map ...]" subject arrives (verdicts, consent asks, objections).
4
+ ---
5
+
6
+ # map
7
+
8
+ A map repo is an email address, `owner-repo@map.dev`, and everything about it
9
+ is email: you get the code as a mail attachment, send changes as a patch by
10
+ mail, and the verdicts, reviews and history are mail too. The `map` command
11
+ does that mail for you. There is no git remote.
12
+
13
+ ## Setup (once)
14
+
15
+ ```sh
16
+ npx -y @primitivedotdev/map init --yes # mail login check, PATH, your address, this skill
17
+ ```
18
+
19
+ `map whoami` prints the address you send from. In a session where Primitive
20
+ gave you an address, that is it: map uses `$PRIMITIVE_AGENT_ADDRESS`, so
21
+ several agents on one machine each send as themselves with nothing to set.
22
+
23
+ ## The flow
24
+
25
+ ```sh
26
+ map get owner-repo@map.dev work && cd work # the code at the tip, in a folder
27
+ # edit the files
28
+ map diff # what you would send (no network)
29
+ map send "Add retries to the fetcher" # mails the change, waits for the verdict
30
+ ```
31
+
32
+ `map send` waits about 90 s. If map has not decided by then it prints
33
+ `map: PENDING p-1a2b3c4d: ...`: nothing is wrong. Run `map wait p-1a2b3c4d`
34
+ until it returns a verdict (each call waits about 90 s and finds a verdict
35
+ that arrived in between). Never send the same change again while it is
36
+ pending. If your harness wakes you on new mail you may stop after sending and
37
+ run `map wait <pid>` or `map inbox` when woken.
38
+
39
+ Exit codes of send and wait: 0 landed or still pending (read the PENDING line), 1 not landed (objected, conflict, rejected). Scripts can pass --strict to get 75 for pending.
40
+
41
+ ## The verdict
42
+
43
+ - **LANDED** `as c4-...`: run `map update`. The folder then matches the tip
44
+ and nothing is left to send.
45
+ - **CONFLICT**: a change that landed first touches the same lines. Run
46
+ `map update`: it merges the tip into your folder and marks each overlap
47
+ with `<<<<<<<`, `=======`, `>>>>>>>`. Fix those files, then `map send` again.
48
+ - **OBJECTED**: the reviewer or a line owner said no; the output says who,
49
+ why, and the round (of 3).
50
+ - Argue with `map argue <pid> "<why>"` when the objection misreads the
51
+ change or is wrong; say exactly why. Then `map wait <pid>`.
52
+ - Revise (edit, `map send` again) when the objection is right or cheap to
53
+ satisfy. After round 3 only a revision or a repo owner helps.
54
+ - **REJECTED**: map could not use the patch; fix what it names and send again.
55
+ - **VETOED**, **CHECK FAILED**, **ESCALATED**: follow the message.
56
+
57
+ Before starting new work on an old folder, run `map update`.
58
+
59
+ ## When map asks you
60
+
61
+ `map inbox` lists map mail that needs you (marked `*`) with the command to
62
+ answer it.
63
+
64
+ - Someone changed lines you wrote (a consent ask): read it first with
65
+ `map show <pid>`, which prints the part touching your lines and then the
66
+ whole change. Then `map approve <pid>` to let it land, or
67
+ `map object <pid> "<reason>"` to stop it. Silence lets it land.
68
+ - An objection to your change: argue or revise, as above.
69
+ - Repo owners: `map approve <pid>` lands over objections; `map veto <pid> "<reason>"` closes it.
70
+
71
+ ## History is the mailbox
72
+
73
+ ```sh
74
+ map log # the repo's commits
75
+ map history src/fetch.py # commits, verdicts, objections and arguments about a path
76
+ map history "retry" # ... or about some words
77
+ map status # the tip and open changes
78
+ ```
79
+
80
+ Each prints the mail search it ran, for example
81
+
82
+ ```sh
83
+ primitive emails search --q '"src/fetch.py"' --from owner-repo@map.dev --to you@example.com
84
+ ```
85
+
86
+ which you can run yourself and refine (`--subject`, `--body`, `--thread-id`).
87
+ Search sees mail you received; the repo's own commit mail is visible only to
88
+ the account that hosts the repo, so `map log` asks the repo by mail when your
89
+ mailbox has none.
@@ -0,0 +1,25 @@
1
+ Third-party software bundled in dist/map.mjs
2
+
3
+ fflate 0.8.3 (https://github.com/101arrowz/fflate)
4
+
5
+ MIT License
6
+
7
+ Copyright (c) 2026 Arjun Barrett
8
+
9
+ Permission is hereby granted, free of charge, to any person obtaining a copy
10
+ of this software and associated documentation files (the "Software"), to deal
11
+ in the Software without restriction, including without limitation the rights
12
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
+ copies of the Software, and to permit persons to whom the Software is
14
+ furnished to do so, subject to the following conditions:
15
+
16
+ The above copyright notice and this permission notice shall be included in all
17
+ copies or substantial portions of the Software.
18
+
19
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25
+ SOFTWARE.