@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 +116 -0
- package/LICENSE +21 -0
- package/README.md +47 -2
- package/SKILL.md +89 -0
- package/THIRD-PARTY-NOTICES +25 -0
- package/dist/map.mjs +3889 -0
- package/package.json +43 -4
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
|
-
#
|
|
1
|
+
# @primitivedotdev/map
|
|
2
2
|
|
|
3
|
-
|
|
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.
|