@atomicmail/agent-skill 0.1.0 → 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.
Files changed (39) hide show
  1. package/README.md +56 -0
  2. package/SKILL.md +67 -187
  3. package/esm/{skill/scripts/lib/auth.d.ts → lib/src/agent-auth-http.d.ts} +1 -17
  4. package/esm/lib/src/agent-auth-http.d.ts.map +1 -0
  5. package/esm/lib/src/agent-auth-http.js +76 -0
  6. package/esm/{skill/scripts/lib/credentials.d.ts → lib/src/agent-credentials-store.d.ts} +4 -1
  7. package/esm/lib/src/agent-credentials-store.d.ts.map +1 -0
  8. package/esm/{skill/scripts/lib/credentials.js → lib/src/agent-credentials-store.js} +28 -8
  9. package/esm/lib/src/agent-help-content.d.ts +4 -0
  10. package/esm/lib/src/agent-help-content.d.ts.map +1 -0
  11. package/esm/lib/src/agent-help-content.js +236 -0
  12. package/esm/lib/src/agent-jmap.d.ts +49 -0
  13. package/esm/lib/src/agent-jmap.d.ts.map +1 -0
  14. package/esm/lib/src/agent-jmap.js +130 -0
  15. package/esm/lib/src/agent-jwt.d.ts +14 -0
  16. package/esm/lib/src/agent-jwt.d.ts.map +1 -0
  17. package/esm/lib/src/agent-jwt.js +29 -0
  18. package/esm/lib/src/agent-pow.d.ts +5 -0
  19. package/esm/lib/src/agent-pow.d.ts.map +1 -0
  20. package/esm/lib/src/agent-pow.js +49 -0
  21. package/esm/lib/src/agent-session.d.ts +62 -0
  22. package/esm/lib/src/agent-session.d.ts.map +1 -0
  23. package/esm/lib/src/agent-session.js +206 -0
  24. package/esm/lib/src/agent-vars.d.ts +23 -0
  25. package/esm/lib/src/agent-vars.d.ts.map +1 -0
  26. package/esm/lib/src/agent-vars.js +65 -0
  27. package/esm/skill/scripts/cli.d.ts +3 -0
  28. package/esm/skill/scripts/cli.d.ts.map +1 -0
  29. package/esm/skill/scripts/cli.js +309 -0
  30. package/package.json +3 -4
  31. package/esm/skill/scripts/jmap_request.d.ts +0 -3
  32. package/esm/skill/scripts/jmap_request.d.ts.map +0 -1
  33. package/esm/skill/scripts/jmap_request.js +0 -265
  34. package/esm/skill/scripts/lib/auth.d.ts.map +0 -1
  35. package/esm/skill/scripts/lib/auth.js +0 -163
  36. package/esm/skill/scripts/lib/credentials.d.ts.map +0 -1
  37. package/esm/skill/scripts/signup.d.ts +0 -3
  38. package/esm/skill/scripts/signup.d.ts.map +0 -1
  39. package/esm/skill/scripts/signup.js +0 -170
package/README.md ADDED
@@ -0,0 +1,56 @@
1
+ # @atomicmail/agent-skill
2
+
3
+ Atomic Mail AgentSkill CLI for AI agents. It exposes three commands: `register`,
4
+ `jmap_request`, and `help` (same surface as `@atomicmail/mcp`).
5
+
6
+ ## Install / run
7
+
8
+ ```bash
9
+ npx --package=@atomicmail/agent-skill atomicmail --help
10
+ ```
11
+
12
+ From source:
13
+
14
+ ```bash
15
+ deno run -A scripts/cli.ts --help
16
+ ```
17
+
18
+ ## Quick start
19
+
20
+ ```bash
21
+ npx --package=@atomicmail/agent-skill atomicmail register \
22
+ --username "myagent"
23
+
24
+ npx --package=@atomicmail/agent-skill atomicmail jmap_request \
25
+ --ops '[["Mailbox/get", {"accountId": "$ACCOUNT_ID"}, "m0"]]'
26
+ ```
27
+
28
+ ## Placeholder substitution
29
+
30
+ - Built-in placeholders: `$ACCOUNT_ID`, `$INBOX`
31
+ - Custom placeholders: any `$VAR_NAME` via `--vars '{"VAR_NAME":"value"}'`
32
+ - Works for both `--ops` and `--ops-file`
33
+
34
+ Example:
35
+
36
+ ```bash
37
+ npx --package=@atomicmail/agent-skill atomicmail jmap_request \
38
+ --ops-file send_email.json \
39
+ --vars '{"TO":"alice@example.com","SUBJECT":"Hello","BODY":"Hi there"}'
40
+ ```
41
+
42
+ ## Shared state
43
+
44
+ Credential files in `~/.atomicmail` (mode `0600`):
45
+
46
+ - `credentials.json`
47
+ - `session.jwt`
48
+ - `capability.jwt`
49
+
50
+ The skill and MCP server share this layout.
51
+
52
+ ## Overriding defaults
53
+
54
+ - Endpoints: `--auth-url`, `--api-url` or `ATOMIC_MAIL_AUTH_URL`, `ATOMIC_MAIL_API_URL`
55
+ - Credentials path: `--credentials-dir` or `ATOMIC_MAIL_CREDENTIALS_DIR`
56
+ - PoW salt: `--scrypt-salt` or `ATOMIC_MAIL_SCRYPT_SALT`
package/SKILL.md CHANGED
@@ -1,242 +1,122 @@
1
1
  ---
2
- name: atomic-mail
3
- description: Read and write email through the Atomic Mail ESP from an AI agent. Handles the proof-of-work authentication and JMAP protocol so the agent only needs to think in JMAP method calls. Use when the user asks to register an Atomic Mail inbox, list mailboxes, fetch emails, send email, or otherwise programmatically interact with their Atomic Mail account.
2
+ name: atomicmail
3
+ description: Read and write email through the Atomic Mail ESP from an AI agent. Handles proof-of-work authentication and JMAP so the agent thinks in JMAP method calls. Use when the user asks to register an email inbox, list mailboxes, fetch or send email.
4
4
  license: MIT
5
- compatibility: Requires Deno 2.0+ to run scripts directly, or Node 20+ / Bun 1.1+ via `npx @atomic-mail/agent-skill` after publishing. Needs network access to the configured Atomic Mail auth-service and api-service.
6
- metadata:
7
- author: atomic-mail
8
- version: "0.1.0"
5
+ compatibility: Requires Deno 2.0+ to run scripts directly, or Node 20+ / Bun 1.1+ via `npx @atomicmail/agent-skill` after publishing. Needs network access to the configured auth-service and api-service.
9
6
  ---
10
7
 
11
8
  # Atomic Mail
12
9
 
13
- Atomic Mail is an AI-agent-first email service provider (ESP) that exposes a
14
- programmable inbox over JMAP. It uses a custom proof-of-work (PoW) signup flow
15
- plus three short-lived JWTs (challenge -> session -> capability). This skill
16
- hides all of that behind two CLI scripts so the agent can focus on JMAP.
10
+ Atomic Mail exposes a programmable inbox over JMAP with PoW signup and JWT
11
+ rotation. This skill ships a single CLI entrypoint with three commands:
12
+ **`register`**, **`jmap_request`**, and **`help`** matching the MCP server.
17
13
 
18
14
  ## When to use this skill
19
15
 
20
- Use this skill when the user wants to:
16
+ - Register a new inbox or log in with an existing API key.
17
+ - Send JMAP batches (inline JSON or preset files).
18
+ - Read built-in documentation (JMAP cheatsheet, presets, troubleshooting).
21
19
 
22
- - Register a new Atomic Mail inbox (signup with a username).
23
- - Re-authenticate an existing Atomic Mail account using its API key.
24
- - Read, search, or modify email via JMAP (`Mailbox/get`, `Email/query`,
25
- `Email/get`, `Email/set`, etc.).
26
- - Send email via JMAP (`EmailSubmission/set` with the
27
- `urn:ietf:params:jmap:submission` capability).
28
- - Discover the JMAP session object (`/.well-known/jmap`) to find the `accountId`
29
- before issuing other JMAP method calls.
20
+ ## Commands
30
21
 
31
- ## Available scripts
32
-
33
- - **`scripts/signup.ts`** — One-time setup: performs PoW signup or login and
34
- writes credentials to disk. Run once per agent session/inbox.
35
- - **`scripts/jmap_request.ts`** — Sends JMAP requests using the saved
36
- credentials. Auto-rotates the session and capability JWTs as they expire.
37
-
38
- Both scripts are invokable three ways. Pick the one that matches the runtime the
39
- user has installed:
22
+ All invocations use `scripts/cli.ts` or the published binary **`atomicmail`**:
40
23
 
41
24
  ```bash
42
- # Deno (preferred — runs source directly)
43
- deno run -A scripts/signup.ts ...
44
- deno run -A scripts/jmap_request.ts ...
45
-
46
- # Node (after the npm package is installed/published)
47
- npx -y @atomic-mail/agent-skill atomic-mail-signup ...
48
- npx -y @atomic-mail/agent-skill atomic-mail-jmap ...
49
-
50
- # Bun
51
- bunx -y @atomic-mail/agent-skill atomic-mail-signup ...
52
- bunx -y @atomic-mail/agent-skill atomic-mail-jmap ...
25
+ # Deno (repo)
26
+ deno run -A scripts/cli.ts register --username alice
27
+ deno run -A scripts/cli.ts jmap_request --ops-file x.json
28
+ deno run -A scripts/cli.ts help --topic presets
29
+
30
+ # Node / Bun (after publish)
31
+ npx --package=@atomicmail/agent-skill atomicmail register --username "myagent" ...
32
+ npx --package=@atomicmail/agent-skill atomicmail jmap_request --ops-file send_hello.json
53
33
  ```
54
34
 
55
- > The agent should always pass `--help` first if it is unsure of the exact flag
56
- > spelling. Both scripts print full usage to stdout and exit `0`.
57
-
58
- ## Required configuration
35
+ Run **`atomicmail --help`** or **`atomicmail <command> --help`** for flags.
59
36
 
60
- The auth and API base URLs come from the Atomic Mail deployment. Pass them as
61
- flags or set them in the environment:
37
+ ## Defaults
62
38
 
63
- | Flag | Env var | Description |
64
- | --------------- | ------------------------- | ------------------------------------------------------- |
65
- | `--auth-url` | `ATOMIC_MAIL_AUTH_URL` | Base URL of `auth-service` (PoW + JWT minting). |
66
- | `--api-url` | `ATOMIC_MAIL_API_URL` | Base URL of `api-service` (JMAP). |
67
- | `--scrypt-salt` | `ATOMIC_MAIL_SCRYPT_SALT` | Optional PoW salt override (defaults match `auth-service`). |
68
-
69
- If the user does not know the URLs, ask them — they are deployment-specific.
39
+ - `authUrl`: `https://auth.atomicmail.ai`
40
+ - `apiUrl`: `https://api.atomicmail.ai`
41
+ - credentials directory: `~/.atomicmail`
70
42
 
71
43
  ## Workflow
72
44
 
73
- ### 1. First-time signup (new account)
45
+ ### 1. Register (new account)
74
46
 
75
47
  ```bash
76
- deno run -A scripts/signup.ts \
77
- --auth-url "$ATOMIC_MAIL_AUTH_URL" \
78
- --api-url "$ATOMIC_MAIL_API_URL" \
79
- --username "alice" \
80
- --out-dir "./.atomic-mail"
48
+ deno run -A scripts/cli.ts register \
49
+ --username "alice"
81
50
  ```
82
51
 
83
- This writes three files into `--out-dir`:
84
-
85
- - `credentials.json` — `{ apiKey, inboxId, authUrl, apiUrl, scryptSalt }`. The
86
- agent should store the `apiKey` securely; it is the long-lived secret.
87
- - `session.jwt` — 4-hour session token.
88
- - `capability.jwt` — 2-minute capability token used as the JMAP bearer.
52
+ Writes `credentials.json`, `session.jwt`, `capability.jwt`. Prints JSON
53
+ including `inbox` and `accountId`.
89
54
 
90
- The script prints a JSON summary to stdout that includes `inboxId` and `apiKey`.
91
- Save these in the agent's persistent memory (or echo them back to the user) —
92
- they are the only durable identifiers.
55
+ ### 2. Register (existing API key, in case losing the credentials file)
93
56
 
94
- ### 2. Re-authenticate (existing API key)
57
+ ```bash
58
+ deno run -A scripts/cli.ts register \
59
+ --api-key "..."
60
+ ```
95
61
 
96
- If `credentials.json` already exists, this is normally not needed —
97
- `jmap_request.ts` will auto-renew session/capability tokens via the stored API
98
- key. Use `signup.ts --api-key` only if the user wants to start a fresh
99
- credentials directory from a known API key.
62
+ ### 3. JMAP request
100
63
 
101
64
  ```bash
102
- deno run -A scripts/signup.ts \
103
- --auth-url "$ATOMIC_MAIL_AUTH_URL" \
104
- --api-url "$ATOMIC_MAIL_API_URL" \
105
- --api-key "11111111-2222-3333-4444-555555555555" \
106
- --out-dir "./.atomic-mail"
65
+ deno run -A scripts/cli.ts jmap_request \
66
+ --ops '[["Mailbox/get", {"accountId": "$ACCOUNT_ID"}, "m0"]]'
107
67
  ```
108
68
 
109
- ### 3. Discover the JMAP session
69
+ `$ACCOUNT_ID` and `$INBOX` resolve from the session/credentials. Other
70
+ placeholders such as `$TO` or `$SUBJECT` require `--vars` with a JSON object of
71
+ strings (same substitution applies to `--ops` and `--ops-file`).
110
72
 
111
- Run this **once** before any other JMAP call to learn the `accountId` and
112
- mailbox structure.
73
+ Preset file:
113
74
 
114
75
  ```bash
115
- deno run -A scripts/jmap_request.ts \
116
- --credentials-dir "./.atomic-mail" \
117
- --session
76
+ deno run -A scripts/cli.ts jmap_request \
77
+ --ops-file fetch_last_100.json
118
78
  ```
119
79
 
120
- The response JSON contains `primaryAccounts`, `accounts`, `capabilities`, etc.
121
- Extract the `accountId` for the user's primary mail account from
122
- `primaryAccounts["urn:ietf:params:jmap:mail"]`.
123
-
124
- ### 4. Send a JMAP request (inline ops)
80
+ With custom placeholders:
125
81
 
126
82
  ```bash
127
- deno run -A scripts/jmap_request.ts \
128
- --credentials-dir "./.atomic-mail" \
129
- --ops '[["Mailbox/get", {"accountId": "ACCOUNT_ID"}, "m0"]]'
83
+ deno run -A scripts/cli.ts jmap_request \
84
+ --ops-file send_email.json \
85
+ --vars '{"TO":"alice@example.com","SUBJECT":"Hello","BODY":"Hi there"}'
130
86
  ```
131
87
 
132
- For multiple method calls or capabilities, pass a full envelope:
88
+ ### 4. Help
133
89
 
134
90
  ```bash
135
- deno run -A scripts/jmap_request.ts \
136
- --credentials-dir "./.atomic-mail" \
137
- --ops '{
138
- "using": ["urn:ietf:params:jmap:core","urn:ietf:params:jmap:mail"],
139
- "methodCalls": [
140
- ["Mailbox/get", {"accountId": "ACCOUNT_ID"}, "m0"],
141
- ["Email/query", {"accountId": "ACCOUNT_ID", "limit": 10}, "q0"]
142
- ]
143
- }'
91
+ deno run -A scripts/cli.ts help
92
+ deno run -A scripts/cli.ts help --topic jmap_cheatsheet
144
93
  ```
145
94
 
146
- ### 5. Send a JMAP request (preset file)
95
+ ## npm package
147
96
 
148
- For repeated tasks, save the JMAP body to a file and reuse it. The file may
149
- contain either a `methodCalls` array or a full `{ using, methodCalls }`
150
- envelope.
97
+ From the `skill/` directory:
151
98
 
152
99
  ```bash
153
- cat > fetch_last_100.json <<'EOF'
154
- [
155
- ["Email/query", {
156
- "accountId": "ACCOUNT_ID",
157
- "limit": 100,
158
- "sort": [{ "property": "receivedAt", "isAscending": false }]
159
- }, "q0"],
160
- ["Email/get", {
161
- "accountId": "ACCOUNT_ID",
162
- "#ids": { "resultOf": "q0", "name": "Email/query", "path": "/ids" },
163
- "properties": ["id","threadId","subject","from","receivedAt","preview"]
164
- }, "g0"]
165
- ]
166
- EOF
167
-
168
- deno run -A scripts/jmap_request.ts \
169
- --credentials-dir "./.atomic-mail" \
170
- --ops-file fetch_last_100.json
100
+ deno task build:npm
101
+ cd npm && npm publish --access public
171
102
  ```
172
103
 
173
- The agent can build a small library of these preset files (`send_email.json`,
174
- `mark_read.json`, etc.) and reuse them across runs.
104
+ The published **`atomicmail`** binary exposes `register`, `jmap_request`, and
105
+ `help`.
175
106
 
176
- ### 6. Send email
107
+ ## Security
177
108
 
178
- Send is a JMAP `EmailSubmission/set` plus an optional `Email/set` to upload the
179
- draft. Remember to add the submission capability to `using`:
109
+ - `credentials.json` holds the API key (mode `0600`). Do not commit it.
110
+ - JWT files are bearer secrets do not log them.
180
111
 
181
- ```bash
182
- deno run -A scripts/jmap_request.ts \
183
- --credentials-dir "./.atomic-mail" \
184
- --using "urn:ietf:params:jmap:core,urn:ietf:params:jmap:mail,urn:ietf:params:jmap:submission" \
185
- --ops-file send_email.json
186
- ```
112
+ ## Overriding defaults
187
113
 
188
- ## Token rotation (handled automatically)
189
-
190
- `jmap_request.ts` checks both JWTs before every request:
191
-
192
- - If `capability.jwt` is within 20 s of expiry, it calls
193
- `POST /api/v1/capability` with the existing session JWT and rewrites
194
- `capability.jwt`.
195
- - If `session.jwt` is within 60 s of expiry (or missing), it re-runs the full
196
- PoW handshake using the API key from `credentials.json`, then rewrites both
197
- `session.jwt` and `capability.jwt`.
198
-
199
- The agent does not need to call `signup.ts` again to refresh tokens — it only
200
- needs to call `signup.ts` for the very first registration of an account.
201
-
202
- ## Troubleshooting
203
-
204
- - **`Could not read credentials file ... Did you run signup first?`** — Run
205
- `signup.ts` once with `--username` (new account) or `--api-key` (existing
206
- account) to create the file set.
207
- - **`auth-service /api/v1/session returned 409`** — The challenge was consumed
208
- (likely a duplicate request or a clock skew). Just rerun `signup.ts` or the
209
- failing `jmap_request.ts` once; a fresh challenge will be issued.
210
- - **`auth-service /api/v1/session returned 401`** — The `apiKey` in
211
- `credentials.json` is unknown or suspended. Re-register with `--username` or
212
- get a new API key from the operator.
213
- - **PoW takes a long time on first run** — Difficulty is fixed at 6 leading zero
214
- bits, which averages ~64 scrypt iterations. Each scrypt is ~16 MB and ~200-500
215
- ms, so the whole solve typically completes in under 30 seconds on a modern
216
- laptop.
217
- - **`Capability JWT did not contain an inboxId claim`** — Almost certainly a
218
- server/version mismatch. Verify `--auth-url` points to a current
219
- `auth-service` deployment.
220
-
221
- ## Security notes
222
-
223
- - `credentials.json` contains the long-lived API key. The script writes it with
224
- mode `0600`, but the agent must not echo the file's contents into shared logs
225
- or commit it to source control.
226
- - Pick a credentials directory that is private to the agent's runtime user (e.g.
227
- `~/.config/atomic-mail/` or a per-task working dir).
228
- - `session.jwt` and `capability.jwt` are short-lived but should be treated as
229
- bearer credentials too — never log them.
230
-
231
- ## Building an npm package
232
-
233
- Scripts can be published as an npm package so Node and Bun environments can use
234
- them through `npx` / `bunx`. From the skill directory:
114
+ - Endpoints: `--auth-url`, `--api-url` or `ATOMIC_MAIL_AUTH_URL`,
115
+ `ATOMIC_MAIL_API_URL`
116
+ - Credentials path: `--credentials-dir` or `ATOMIC_MAIL_CREDENTIALS_DIR`
117
+ - PoW salt: `--scrypt-salt` or `ATOMIC_MAIL_SCRYPT_SALT`
235
118
 
236
- ```bash
237
- deno task build:npm # writes ./npm
238
- cd npm && npm publish --access public
239
- ```
119
+ ## Building
240
120
 
241
- After publishing, `npx @atomic-mail/agent-skill atomic-mail-signup` and
242
- `npx @atomic-mail/agent-skill atomic-mail-jmap` work without Deno installed.
121
+ See repository [`AGENTS.md`](../AGENTS.md) for formatting (`deno fmt`) and
122
+ conventions.
@@ -1,19 +1,3 @@
1
- export declare const SESSION_TTL_MS: number;
2
- export declare const CAPABILITY_TTL_MS: number;
3
- export declare const CAPABILITY_SAFETY_MARGIN_MS = 20000;
4
- export declare const SESSION_SAFETY_MARGIN_MS = 60000;
5
- export interface JwtPayload {
6
- exp?: number;
7
- iat?: number;
8
- jti?: string;
9
- [key: string]: unknown;
10
- }
11
- export declare function decodeJwtPayload<T = JwtPayload>(jwt: string): T;
12
- export declare function isJwtExpired(jwt: string, marginMs: number): boolean;
13
- export declare function solvePow(challenge: string, difficulty: number, salt: string, onProgress?: (nonce: bigint) => void): Promise<{
14
- powHex: string;
15
- nonce: string;
16
- }>;
17
1
  export declare function fetchChallenge(authUrl: string): Promise<{
18
2
  challengeJWT: string;
19
3
  challenge: string;
@@ -39,4 +23,4 @@ export interface PerformPoWInput {
39
23
  onPowProgress?: (nonce: bigint) => void;
40
24
  }
41
25
  export declare function performPoWAndSession(input: PerformPoWInput): Promise<SessionResponse>;
42
- //# sourceMappingURL=auth.d.ts.map
26
+ //# sourceMappingURL=agent-auth-http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-auth-http.d.ts","sourceRoot":"","sources":["../../../src/lib/src/agent-auth-http.ts"],"names":[],"mappings":"AAoCA,wBAAsB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;IAC7D,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC,CAqBD;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,eAAe,CACnC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE;IACJ,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GACA,OAAO,CAAC,eAAe,CAAC,CAS1B;AAED,wBAAsB,eAAe,CACnC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,CAAC,CAUjB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACzC;AAED,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,eAAe,GACrB,OAAO,CAAC,eAAe,CAAC,CAgB1B"}
@@ -0,0 +1,76 @@
1
+ // auth-service HTTP: challenge → session → capability.
2
+ import { decodeJwtPayload } from "./agent-jwt.js";
3
+ import { solvePow } from "./agent-pow.js";
4
+ async function postJson(url, body, headers = {}) {
5
+ const res = await fetch(url, {
6
+ method: "POST",
7
+ headers: {
8
+ ...(body ? { "Content-Type": "application/json" } : {}),
9
+ ...headers,
10
+ },
11
+ body: body ? JSON.stringify(body) : undefined,
12
+ });
13
+ const text = await res.text();
14
+ const path = (() => {
15
+ try {
16
+ return new URL(url).pathname;
17
+ }
18
+ catch {
19
+ return url;
20
+ }
21
+ })();
22
+ if (!res.ok) {
23
+ throw new Error(`auth-service ${path} returned ${res.status}: ${text}`);
24
+ }
25
+ try {
26
+ return JSON.parse(text);
27
+ }
28
+ catch {
29
+ throw new Error(`auth-service ${path} returned non-JSON body: ${text}`);
30
+ }
31
+ }
32
+ export async function fetchChallenge(authUrl) {
33
+ const data = await postJson(`${authUrl}/api/v1/challenge`, undefined);
34
+ if (typeof data.challengeJWT !== "string") {
35
+ throw new Error("Challenge response missing challengeJWT.");
36
+ }
37
+ const payload = decodeJwtPayload(data.challengeJWT);
38
+ if (typeof payload.jti !== "string" ||
39
+ typeof payload.difficulty !== "number") {
40
+ throw new Error("Challenge JWT payload malformed (missing jti or difficulty).");
41
+ }
42
+ return {
43
+ challengeJWT: data.challengeJWT,
44
+ challenge: payload.jti,
45
+ difficulty: payload.difficulty,
46
+ };
47
+ }
48
+ export async function exchangeSession(authUrl, body) {
49
+ const data = await postJson(`${authUrl}/api/v1/session`, { ...body });
50
+ if (typeof data.sessionJWT !== "string") {
51
+ throw new Error("Session response missing sessionJWT.");
52
+ }
53
+ return {
54
+ sessionJWT: data.sessionJWT,
55
+ apiKey: typeof data.apiKey === "string" ? data.apiKey : undefined,
56
+ };
57
+ }
58
+ export async function fetchCapability(authUrl, sessionJWT) {
59
+ const data = await postJson(`${authUrl}/api/v1/capability`, undefined, { Authorization: `Bearer ${sessionJWT}` });
60
+ if (typeof data.capabilityJWT !== "string") {
61
+ throw new Error("Capability response missing capabilityJWT.");
62
+ }
63
+ return data.capabilityJWT;
64
+ }
65
+ export async function performPoWAndSession(input) {
66
+ const { authUrl, scryptSalt } = input;
67
+ const { challengeJWT, challenge, difficulty } = await fetchChallenge(authUrl);
68
+ const { powHex, nonce } = await solvePow(challenge, difficulty, scryptSalt, input.onPowProgress);
69
+ return exchangeSession(authUrl, {
70
+ challengeJWT,
71
+ powHex,
72
+ nonce,
73
+ apiKey: input.apiKey,
74
+ username: input.username,
75
+ });
76
+ }
@@ -13,6 +13,9 @@ export interface SkillFiles {
13
13
  export declare function defaultFilesFromOutDir(outDir: string): SkillFiles;
14
14
  export declare function writeCredentials(path: string, creds: Credentials): Promise<void>;
15
15
  export declare function readCredentials(path: string): Promise<Credentials>;
16
+ export declare function tryReadCredentials(path: string): Promise<Credentials | undefined>;
16
17
  export declare function writeJwtFile(path: string, jwt: string): Promise<void>;
17
18
  export declare function tryReadJwtFile(path: string): Promise<string | undefined>;
18
- //# sourceMappingURL=credentials.d.ts.map
19
+ /** Best-effort removal of credential artifacts (ignore missing files). */
20
+ export declare function unlinkCredentialArtifacts(files: SkillFiles): Promise<void>;
21
+ //# sourceMappingURL=agent-credentials-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-credentials-store.d.ts","sourceRoot":"","sources":["../../../src/lib/src/agent-credentials-store.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAOjE;AAMD,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,WAAW,GACjB,OAAO,CAAC,IAAI,CAAC,CAGf;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAiCxE;AAED,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CAOlC;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAG3E;AAED,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAO7B;AAED,0EAA0E;AAC1E,wBAAsB,yBAAyB,CAC7C,KAAK,EAAE,UAAU,GAChB,OAAO,CAAC,IAAI,CAAC,CAcf"}
@@ -1,10 +1,6 @@
1
- // Credential file I/O. Three files form a complete skill credential set:
2
- // credentials.json — long-lived: apiKey, inboxId, server URLs, PoW salt.
3
- // session.jwt — short-lived (~4h): rotates via /session + PoW.
4
- // capability.jwt — short-lived (~2min): rotates via /capability.
5
- //
6
- // Files are written with mode 0600 so other local users cannot read them.
7
- import { mkdir, readFile, writeFile } from "node:fs/promises";
1
+ // Credential file I/O shared by MCP and AgentSkill.
2
+ // Three files: credentials.json, session.jwt, capability.jwt (mode 0600).
3
+ import { mkdir, readFile, unlink, writeFile } from "node:fs/promises";
8
4
  import { dirname, join, resolve } from "node:path";
9
5
  export function defaultFilesFromOutDir(outDir) {
10
6
  const base = resolve(outDir);
@@ -28,7 +24,7 @@ export async function readCredentials(path) {
28
24
  }
29
25
  catch (err) {
30
26
  throw new Error(`Could not read credentials file '${path}': ${err.message}. ` +
31
- "Did you run signup first?");
27
+ "Did you run register first?");
32
28
  }
33
29
  let obj;
34
30
  try {
@@ -51,6 +47,15 @@ export async function readCredentials(path) {
51
47
  }
52
48
  return obj;
53
49
  }
50
+ export async function tryReadCredentials(path) {
51
+ try {
52
+ await readFile(path, "utf-8");
53
+ }
54
+ catch {
55
+ return undefined;
56
+ }
57
+ return readCredentials(path);
58
+ }
54
59
  export async function writeJwtFile(path, jwt) {
55
60
  await ensureParent(path);
56
61
  await writeFile(path, jwt, { mode: 0o600 });
@@ -64,3 +69,18 @@ export async function tryReadJwtFile(path) {
64
69
  return undefined;
65
70
  }
66
71
  }
72
+ /** Best-effort removal of credential artifacts (ignore missing files). */
73
+ export async function unlinkCredentialArtifacts(files) {
74
+ for (const p of [
75
+ files.credentialsFile,
76
+ files.sessionFile,
77
+ files.capabilityFile,
78
+ ]) {
79
+ try {
80
+ await unlink(p);
81
+ }
82
+ catch {
83
+ // ignore
84
+ }
85
+ }
86
+ }
@@ -0,0 +1,4 @@
1
+ export declare const HELP_TOPICS: Record<string, string>;
2
+ export declare const HELP_TOPIC_LIST: string[];
3
+ export declare function getHelp(topic?: string): string;
4
+ //# sourceMappingURL=agent-help-content.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-help-content.d.ts","sourceRoot":"","sources":["../../../src/lib/src/agent-help-content.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAuO9C,CAAC;AAEF,eAAO,MAAM,eAAe,UAA2B,CAAC;AAExD,wBAAgB,OAAO,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAW9C"}