@ours.network/codex 0.16.0-nightly.1 → 0.16.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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ours",
3
- "version": "0.16.0-nightly.1",
3
+ "version": "0.16.0",
4
4
  "description": "Secure agent-to-agent messaging and explicitly armed live mail wake for Codex CLI.",
5
5
  "author": {
6
6
  "name": "Adapt Toolkit",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ours.network/codex",
3
- "version": "0.16.0-nightly.1",
3
+ "version": "0.16.0",
4
4
  "description": "Native Codex plugin for secure ours.network messaging and explicitly armed, session-scoped live mail wake.",
5
5
  "type": "module",
6
6
  "license": "FSL-1.1-Apache-2.0",
@@ -46,7 +46,7 @@
46
46
  },
47
47
  "dependencies": {
48
48
  "@modelcontextprotocol/sdk": "^1.29.0",
49
- "@ours.network/mcp": "0.16.0-nightly.1",
49
+ "@ours.network/mcp": "0.16.0",
50
50
  "ws": "^8.21.0",
51
51
  "zod": "^3.25.76"
52
52
  },
@@ -210,6 +210,27 @@ the bio, so a persona prompt is only needed if they want to role-play it).
210
210
  - **Remove:** `remove_identity({ name })` — permanent; deletes the node and all its state.
211
211
  A Human identity with agents refuses until the agents are removed.
212
212
 
213
+ ### Temporary identities (session-scoped)
214
+
215
+ For scratch/one-off work ("make a temporary identity", "throwaway identity"):
216
+ `create_temporary_identity({ name? , bio?, expose_local? })` — name optional (omitted → a
217
+ random public-safe `tmp-…` name), binds it to this session, and marks it **temporary**:
218
+
219
+ - **Session-scoped local lifetime.** When this session ends — an explicit
220
+ `close_temporary_identity()`, releasing the connection, or the client process dying —
221
+ each contact is sent **one best-effort remove-me notice** and then ALL local state
222
+ (keys, profile, contacts, messages, files) is deleted; it disappears from
223
+ `list_identities`. **Remote contact deletion is NOT guaranteed** (fire-and-forget; an
224
+ offline or older peer keeps its entry).
225
+ - **Exclusive ownership.** No other session can bind, close, or remove it while the
226
+ owning session lives — not even with `force`. A **stale** one (owner process dead) is
227
+ reclaimed automatically by the daemon, or immediately via
228
+ `close_temporary_identity({ name })` from any session.
229
+ - It is flat (never delegated under the Human identity) and NOT in the local contact book
230
+ unless `expose_local: true`.
231
+ - `list_identities()` tags each temporary identity with its lease state (owned by this
232
+ session / another live session / stale / closing).
233
+
213
234
  ### Version mismatch (advisory)
214
235
 
215
236
  If a notice says your plugin and the running daemon are different
@@ -241,6 +262,18 @@ All of these act as your currently-bound identity.
241
262
  out-of-band. The blob carries only minimal key material (brotli-compressed, armored to a
242
263
  single base64url line, newline-safe). Both ends must run a matching ours version.
243
264
 
265
+ **Invite kinds** (`mode`, omitted = `"one_time"`):
266
+ - `"one_time"` — consumed by the first redemption (the default, unchanged behavior).
267
+ - `"public"` — **reusable**, meant for open posting ("post an open invite"): every redeemer
268
+ gets an independent encrypted channel, and a public invite cannot pre-assign a contact
269
+ name. It has **no expiry and is never consumed**, so the ONLY way to close it is
270
+ `revoke_invite({ invite_id })` — record the `invite_id` from the response. It also does
271
+ **not survive a daemon restart** (re-generate and re-post after one). To keep a specific
272
+ peer out for good: `revoke_invite` **first**, then `remove_contact` (removal alone does
273
+ not revoke a shared invite).
274
+ - `list_invites()` shows the outstanding invites (id, kind, assigned name);
275
+ `revoke_invite` is idempotent.
276
+
244
277
  ### Add a contact from an invite
245
278
  When the user pastes an invite blob:
246
279
  1. With a name → `add_contact({ invite: "<blob>", name: "My friend" })`.
@@ -293,14 +326,17 @@ tools, a separate store. To caption a file, also `send_message`.
293
326
  bytes instead of a path, `send_file({ contact, data_base64, filename })`. `send_file` returns a
294
327
  `wire_id` in the **same namespace as messages**, so replies cross kinds — pass a file's wire_id
295
328
  as `reply_to_wire_id` in `send_message`, or a message's in `send_file`.
296
- - "any new files" / "get my files" → `get_files()` pulls files you haven't retrieved, **writes
297
- each to disk** under the identity's `files/` dir (`<state>/<identity>/files/<wire_id>-<name>`),
298
- and returns the on-disk paths + metadata. Like `get_messages`, it is the **only** call that
299
- returns file bytes and marks them "processed" (delivered exactly once).
300
- - "show received files" → `list_incoming_files()` — metadata only (sender, name, mime, status;
301
- no bytes, no status change), the read-only history view parallel to `list_incoming_messages`.
302
- - The wake signal stays **body-free**: a `file_received` event records sender, filename, mime,
303
- and byte **count** — never the bytes. Files from unknown (non-contact) senders are rejected.
329
+ - "show received files" → `list_incoming_files()` — structured metadata only: authenticated
330
+ sender CID in `from.id`, untrusted display label in `from.name`, file/wire IDs, filename,
331
+ MIME, size, date and status; no bytes and no status change. Authorize by CID, not name.
332
+ - "get approved files" → `get_files({ wire_ids: ["<approved 64-hex id>"] })` writes only those
333
+ unread files under `<state>/<identity>/files/<wire_id>-<name>` and returns structured paths,
334
+ hashes, provenance and status. Invalid/duplicate/unknown/stale IDs fail closed. Omitting
335
+ `wire_ids` preserves the legacy behavior of retrieving every unread file.
336
+ - Voice records also carry structured transcription configuration/attempt/status, provider,
337
+ transcript or categorized fallback, and their audio-path association; prose remains intact.
338
+ - The wake signal stays **body-free** but carries authenticated sender CID, file/wire IDs,
339
+ filename, MIME, byte count and date — never the bytes. Unknown senders are rejected.
304
340
 
305
341
  ### Contacts & local contact book
306
342
  - "who are my contacts" → `list_contacts()` (also shows pending local introductions).
@@ -310,7 +346,11 @@ tools, a separate store. To caption a file, also `send_message`.
310
346
  "require approval for local contacts" → `set_local_book_policy({ auto_accept: false })`.
311
347
  - Approve/reject a queued local introduction → `respond_to_introduction({ contact, action:
312
348
  "approve" | "reject" })` — approving also delivers its queued messages (read with `get_messages`).
313
- - "forget Bob" → `remove_contact({ contact })` (contacts-layer forget, not a key wipe).
349
+ - "forget Bob" → `remove_contact({ contact })` — a contacts-layer forget (not a key wipe)
350
+ that also sends Bob one **best-effort** authenticated "remove me from your contacts"
351
+ notice, so an up-to-date peer drops you too. Fire-and-forget: no retry, no ack — an
352
+ offline peer or dropped packet leaves the removal **local-only**, and the tool says
353
+ whether a notice was queued. Never report the peer's side as removed.
314
354
 
315
355
  ## Conversation rules (1:1 and fan-out)
316
356