@extrovert.dev/sdk 0.1.0-pre.5 → 0.1.0-pre.7

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/dist/index.d.ts CHANGED
@@ -6,7 +6,7 @@
6
6
  * on 429/5xx, honors `Retry-After`, and surfaces every failure as a typed {@link ApiError}.
7
7
  */
8
8
  /** The library version, surfaced in the User-Agent. Kept in sync with package.json by build. */
9
- declare const SDK_VERSION = "0.1.0-pre.5";
9
+ declare const SDK_VERSION = "0.1.0-pre.7";
10
10
  interface RetryOptions {
11
11
  /** Max retry attempts for idempotent requests on 429/5xx/network errors. Default 2. */
12
12
  maxRetries: number;
@@ -33,7 +33,7 @@ type ReviewInclude = "category" | "turns";
33
33
  declare function serializeInclude(include?: readonly string[]): string | undefined;
34
34
 
35
35
  /**
36
- * Extrovert API typed request/response models.
36
+ * Extrovert API: typed request/response models.
37
37
  *
38
38
  * These mirror the Extrovert V1 REST contract (`/v1`, §8 of the build spec). The Go API does not
39
39
  * exist yet; field shapes here are the source of truth the client codes against and are validated
@@ -52,13 +52,13 @@ type IsoTimestamp = string;
52
52
  * its caveats but cannot exceed them (§5).
53
53
  *
54
54
  * The `mailbox:*` scope strings are the live wire contract (stored in issued keys'
55
- * caveats) and are NOT renamed despite the public "inbox" product naming renaming
56
- * them would invalidate every key already minted. `domain:manage` gates the domains
57
- * plane; `domain:purchase` is additionally required (and is opt-in, default-off) to
58
- * buy a new domain (`POST /v1/domains` with `mode: "purchased"`). `review:act` gates
59
- * the BYO reviewer decision plane.
55
+ * caveats) and are NOT renamed despite the public "inbox" product naming: renaming
56
+ * them would invalidate every key already issued. `domain:manage` gates onboarding
57
+ * for domains the customer already controls. `commerce:request` permits quotes,
58
+ * requests, and status reads, but never a human approval transition or direct spend.
59
+ * `review:act` gates the BYO reviewer decision plane.
60
60
  */
61
- type Scope = "mailbox:create" | "mailbox:read" | "mailbox:send" | "mailbox:quota" | "mailbox:delete" | "webhook:write" | "domain:manage" | "domain:purchase" | "review:act";
61
+ type Scope = "mailbox:create" | "mailbox:read" | "mailbox:send" | "mailbox:quota" | "mailbox:credentials" | "mailbox:delete" | "webhook:write" | "domain:manage" | "domain:read" | "domain:purchase" | "commerce:request" | "review:act" | "signup:verify";
62
62
  /** How a Extrovert domain was onboarded (§7). */
63
63
  type OnboardingMode = "shared" | "purchased" | "ns_delegated" | "manual";
64
64
  /** Lifecycle status of an agent principal. */
@@ -68,35 +68,35 @@ type InboxStatus = "provisioning" | "live" | "disabled" | "deleted";
68
68
  /** Direction of a message relative to the inbox that owns it. */
69
69
  type MessageDirection = "inbound" | "outbound";
70
70
  /**
71
- * Request body for `POST /v1/enroll`. An agent redeems a `pk_enroll_...` token to mint a scoped
71
+ * Request body for `POST /v1/enroll`. An agent redeems a `pk_enroll_...` token to issue a scoped
72
72
  * agent key. Idempotent on `agent_handle` (à la AgentMail's `client_id`).
73
73
  */
74
74
  interface EnrollRequest {
75
75
  /**
76
76
  * The raw enrollment token, format `pk_enroll_<id>_<secret>`. Shown once at issue
77
- * time. REQUIRED this is the wire field the server reads (`json:"token"`); the
77
+ * time. REQUIRED: this is the wire field the server reads (`json:"token"`); the
78
78
  * request is serialized verbatim, so the field name must match the contract.
79
79
  */
80
80
  token: string;
81
81
  /**
82
82
  * Stable client-chosen handle for this agent. Redeeming twice with the same handle returns the
83
- * same agent rather than minting a new one.
83
+ * same agent rather than creating a new one.
84
84
  */
85
85
  agent_handle: string;
86
- /** Optional human-readable label for the minted agent. */
86
+ /** Optional human-readable label for the created agent. */
87
87
  agent_name?: string;
88
88
  /**
89
89
  * Optional idempotency key (sent as the `Idempotency-Key` header). A retry with
90
- * the same key replays the original enrollment response instead of re-minting.
90
+ * the same key replays the original enrollment response instead of reissuing.
91
91
  */
92
92
  client_id?: string;
93
93
  }
94
94
  /**
95
95
  * Response from `POST /v1/enroll`. The `agent_key` is the short-lived, per-agent scoped key the
96
- * agent uses for all subsequent calls never an org-wide key (§5, §14).
96
+ * agent uses for all subsequent calls: never an org-wide key (§5, §14).
97
97
  */
98
98
  interface EnrollResponse {
99
- /** The minted agent principal id, e.g. `agt_7Hq2...`. */
99
+ /** The created agent principal id, e.g. `agt_7Hq2...`. */
100
100
  agent_id: string;
101
101
  /**
102
102
  * The scoped agent key, format `pk_agent_<id>_<secret>`. Returned once. Treat as a secret and
@@ -106,13 +106,13 @@ interface EnrollResponse {
106
106
  /** Scopes granted to this key (a subset of the enrollment token's scopes). */
107
107
  scopes: Scope[];
108
108
  /**
109
- * The fixed org the minted key is bound to (the token's resolved org). The agent
109
+ * The fixed org the issued key is bound to (the token's resolved org). The agent
110
110
  * cannot change it; it is the canonical org for every subsequent call.
111
111
  */
112
112
  org_id?: string;
113
113
  /**
114
- * The fixed project the minted key is bound to (the token's resolved project). The
115
- * agent cannot change it there is no mutable project selector for a scoped key.
114
+ * The fixed project the issued key is bound to (the token's resolved project). The
115
+ * agent cannot change it: there is no mutable project selector for a scoped key.
116
116
  */
117
117
  project_id?: string;
118
118
  }
@@ -128,7 +128,7 @@ interface Agent {
128
128
  /**
129
129
  * One arbitrary metadata value stored on an inbox. The wire allows string, number,
130
130
  * or boolean (nested objects and arrays are rejected). In a PATCH (update) body a
131
- * value of `null` for a key DELETES that key (the merge/null-delete semantics
131
+ * value of `null` for a key DELETES that key (the merge/null-delete semantics :
132
132
  * see {@link UpdateInboxRequest.metadata}); a read shape ({@link Inbox.metadata})
133
133
  * never contains `null`.
134
134
  */
@@ -146,25 +146,28 @@ type InboxMetadata = Record<string, InboxMetadataValue>;
146
146
  */
147
147
  type InboxMetadataPatch = Record<string, InboxMetadataValue | null>;
148
148
  /**
149
- * Request body for `POST /v1/inboxes`. All fields optional: the default path mints an address on a
150
- * pre-warmed, pre-ACS-verified shared subdomain of `smtp.extrovert.dev`, so creation is instant.
149
+ * Request body for `POST /v1/inboxes`. All fields are optional. The default path
150
+ * creates an address on the account's platform shared domain.
151
151
  */
152
152
  interface CreateInboxRequest {
153
153
  /**
154
- * Desired local part (before the `@`). If omitted, the server generates a random handle.
155
- * Example: `agent7` -> `agent7@smtp.extrovert.dev`.
154
+ * Desired local part (before the `@`). Shared-domain names are normalized,
155
+ * must be at least 5 characters, and cannot use reserved names. If omitted,
156
+ * the server generates a random handle.
157
+ * Example: `agent7` -> `agent7@extrovertmail.com` for paid accounts or
158
+ * `agent7@free.extrovertmail.com` for free accounts.
156
159
  */
157
160
  username?: string;
158
161
  /**
159
- * Domain to mint on. Must be an org domain the calling key is scoped to. If omitted, the default
160
- * shared subdomain is used (zero-config path).
162
+ * Domain to create the inbox on. Must be an org domain the calling key is
163
+ * scoped to. If omitted, the account's shared domain is used.
161
164
  */
162
165
  domain?: string;
163
166
  /** Human-readable display name used in the `From:` header on sends. */
164
167
  display_name?: string;
165
168
  /**
166
169
  * Idempotency handle. Re-creating with the same `client_id` returns the existing inbox rather
167
- * than minting a duplicate.
170
+ * than creating a duplicate.
168
171
  */
169
172
  client_id?: string;
170
173
  /**
@@ -181,14 +184,14 @@ interface CreateInboxRequest {
181
184
  */
182
185
  metadata?: InboxMetadata;
183
186
  /**
184
- * Optional assertion that must match the key's bound project NEVER a selector.
187
+ * Optional assertion that must match the key's bound project: NEVER a selector.
185
188
  * A mismatch is a 403. The inbox is always created in the key's stored project;
186
189
  * the assertion only lets a caller defend against a misrouted key.
187
190
  */
188
191
  project_id?: string;
189
192
  /**
190
- * Whether to return the inbox credentials (IMAP/SMTP password) in the response. Defaults to
191
- * false; credentials are sealed at rest and only surfaced on explicit request.
193
+ * Whether to return paid-inbox credentials (IMAP/SMTP password) in the response.
194
+ * Requires the `mailbox:credentials` permission and defaults to false.
192
195
  */
193
196
  return_credentials?: boolean;
194
197
  }
@@ -223,15 +226,17 @@ interface UpdateInboxRequest {
223
226
  */
224
227
  metadata?: InboxMetadataPatch | null;
225
228
  /**
226
- * Optional assertion that must match the key's bound project NEVER a selector.
229
+ * Optional assertion that must match the key's bound project: NEVER a selector.
227
230
  * A mismatch is a 403.
228
231
  */
229
232
  project_id?: string;
230
233
  }
231
234
  /**
232
- * IMAP/SMTP connection config + login for an inbox, only present when
235
+ * IMAP/SMTP connection config + login for a paid inbox. Export requires the
236
+ * `mailbox:credentials` permission. On create it is present only when
233
237
  * `return_credentials` was requested. (The IMAP/SMTP host/port/password are mail
234
- * protocol internals the "credentials" of the underlying mailbox.)
238
+ * protocol internals. Exported credentials do not mean direct SMTP is enabled.
239
+ * Check `direct_smtp_enabled` on the inbox before attempting an SMTP send.)
235
240
  */
236
241
  interface InboxCredentials {
237
242
  imap_host: string;
@@ -239,7 +244,7 @@ interface InboxCredentials {
239
244
  smtp_host: string;
240
245
  smtp_port: number;
241
246
  username: string;
242
- /** Plaintext password shown once, never re-retrievable. Treat as a secret. */
247
+ /** Plaintext mailbox password. Credential reads can return it again. Treat every response as a secret. */
243
248
  password: string;
244
249
  }
245
250
  /** A provisioned inbox (read shape). */
@@ -252,7 +257,7 @@ interface Inbox {
252
257
  object?: "inbox";
253
258
  /**
254
259
  * The canonical OPAQUE inbox id and path key (`/v1/inboxes/{inbox_id}` /
255
- * `/v1/projects/{project_id}/inboxes/{inbox_id}`). Treat it as opaque do not parse
260
+ * `/v1/projects/{project_id}/inboxes/{inbox_id}`). Treat it as opaque: do not parse
256
261
  * the `pmbx_` prefix.
257
262
  */
258
263
  id: string;
@@ -261,11 +266,11 @@ interface Inbox {
261
266
  */
262
267
  org_id?: string;
263
268
  /**
264
- * The project this inbox belongs to (RFC D9) the partition key. Optional for
269
+ * The project this inbox belongs to (RFC D9): the partition key. Optional for
265
270
  * legacy/mock shapes.
266
271
  */
267
272
  project_id?: string;
268
- /** Full address, e.g. `agent7@smtp.extrovert.dev`. A within-project email alias for {@link Inbox.id}. */
273
+ /** Full address, e.g. `agent7@extrovertmail.com`. A within-project email alias for {@link Inbox.id}. */
269
274
  address: string;
270
275
  username: string;
271
276
  domain: string;
@@ -273,10 +278,17 @@ interface Inbox {
273
278
  status: InboxStatus;
274
279
  /** Onboarding mode of the domain this inbox lives on. */
275
280
  onboarding_mode: OnboardingMode;
276
- /** Agent that owns this inbox, if minted by an agent key. */
281
+ /** Agent that owns this inbox, if created by an agent key. */
277
282
  agent_id: string | null;
278
283
  /** Effective enforced rolling-24-hour recipient cap for this inbox. */
279
284
  daily_send_limit: number;
285
+ /**
286
+ * Whether raw protocol SMTP is currently allowed. It defaults to false, is
287
+ * controlled by a human per inbox, and is effective only while the inbox has a
288
+ * paid entitlement. Exported credentials do not imply this is true. API, SDK,
289
+ * and MCP sends remain governed by the Review Loop regardless of this value.
290
+ */
291
+ direct_smtp_enabled: boolean;
280
292
  /**
281
293
  * Inbound webhook registered for this inbox, if any. The wire field is
282
294
  * `webhook_url` (the server returns `webhook_url`, never `inbound_webhook_url`);
@@ -285,7 +297,7 @@ interface Inbox {
285
297
  webhook_url?: string | null;
286
298
  /**
287
299
  * Arbitrary key-value metadata stored on the inbox (AgentMail parity). Always an
288
- * object `{}` when none is set, never null. Values are string, number, or
300
+ * object: `{}` when none is set, never null. Values are string, number, or
289
301
  * boolean. Project-scoped: an agent key only reads/mutates metadata for inboxes in
290
302
  * its bound project.
291
303
  */
@@ -375,7 +387,7 @@ interface AttachmentInput {
375
387
  * A stored message in an inbox (read shape). Mirrors the canonical Go wire shape
376
388
  * (`messageResponse`): `id` is the opaque, inbox-resolvable id; `inbox` is the
377
389
  * owning address; `seen` is the native IMAP \Seen read state (Extrovert has no
378
- * Gmail-style labels read/unread is the \Seen flag); `folder` is the IMAP
390
+ * Gmail-style labels: read/unread is the \Seen flag); `folder` is the IMAP
379
391
  * mailbox; `date` is the raw `Date` header.
380
392
  */
381
393
  interface Message {
@@ -387,6 +399,8 @@ interface Message {
387
399
  from: EmailAddress;
388
400
  to: EmailAddress[];
389
401
  cc?: EmailAddress[];
402
+ /** Reply-To addresses parsed from the source message. */
403
+ reply_to?: EmailAddress[];
390
404
  subject: string;
391
405
  /** Decoded text/plain MIME alternative; null when absent and never derived from HTML. */
392
406
  text: string | null;
@@ -398,6 +412,10 @@ interface Message {
398
412
  extracted_html?: string | null;
399
413
  /** RFC 5322 `Message-ID` header value. */
400
414
  message_id: string;
415
+ /** Source RFC 5322 parent Message-ID, when present. */
416
+ in_reply_to?: string;
417
+ /** Source RFC 5322 References chain, when present. */
418
+ references?: string;
401
419
  /** IMAP folder the message lives in (e.g. `INBOX`, `Junk`). */
402
420
  folder?: string;
403
421
  /** Whether the message has been read (native IMAP \Seen flag). */
@@ -433,7 +451,7 @@ interface SearchMessagesParams {
433
451
  offset?: number;
434
452
  cursor?: string;
435
453
  }
436
- /** Request body for `PATCH /v1/inboxes/{addr}/messages/{id}` read-state toggle. */
454
+ /** Request body for `PATCH /v1/inboxes/{addr}/messages/{id}`: read-state toggle. */
437
455
  interface MarkReadRequest {
438
456
  /** true to set the \Seen flag (read), false to clear it (unread). */
439
457
  read: boolean;
@@ -490,7 +508,7 @@ interface SendRequest {
490
508
  /** Override the `Reply-To` header. */
491
509
  reply_to?: string;
492
510
  /**
493
- * Idempotency key a replay with the same key returns the first response
511
+ * Idempotency key: a replay with the same key returns the first response
494
512
  * instead of sending a second message.
495
513
  *
496
514
  * Sent as the `Idempotency-Key` HEADER and STRIPPED from the JSON body: the
@@ -520,12 +538,14 @@ interface SendRequest {
520
538
  * routes to needs_review with gate_outcome `held:low_confidence`.
521
539
  */
522
540
  category_confidence?: number;
541
+ /** Opaque token from the fresh getRules call used for this composition. */
542
+ composition_token?: string;
523
543
  }
524
544
  /**
525
545
  * Request body for the canonical thread-aware reply,
526
546
  * `POST /v1/inboxes/{addr}/reply`. Exactly one of `thread_id` / `message_id`
527
547
  * selects the parent; the server derives `to` (original participants), the
528
- * `Re:`-prefixed subject, and the `In-Reply-To` / `References` headers you do
548
+ * `Re:`-prefixed subject, and the `In-Reply-To` / `References` headers: you do
529
549
  * NOT pass `to`. Set `reply_all` to reply to every thread recipient.
530
550
  */
531
551
  interface ReplyRequest {
@@ -533,6 +553,12 @@ interface ReplyRequest {
533
553
  thread_id?: string;
534
554
  /** Reply to this specific message. One of thread_id / message_id. */
535
555
  message_id?: string;
556
+ /**
557
+ * Optional optimistic stale-context guard for a thread reply. Use the
558
+ * `last_message_id` from the thread you read; a 409 means the thread advanced.
559
+ * This detects stale context at submission, but is not an atomic send lock.
560
+ */
561
+ expected_last_message_id?: string;
536
562
  /** At least one of `text` / `html` is required. */
537
563
  text?: string;
538
564
  html?: string;
@@ -542,7 +568,7 @@ interface ReplyRequest {
542
568
  reply_to?: string;
543
569
  /** Reply to all thread recipients, not just the original sender. */
544
570
  reply_all?: boolean;
545
- /** See {@link SendRequest.idempotency_key} sent as a header, never in the body. */
571
+ /** See {@link SendRequest.idempotency_key}: sent as a header, never in the body. */
546
572
  idempotency_key?: string;
547
573
  headers?: Record<string, string>;
548
574
  /** Files to attach (base64). Emitted as a multipart/mixed message. */
@@ -555,6 +581,7 @@ interface ReplyRequest {
555
581
  category_id?: string;
556
582
  /** Agent-supplied confidence (0..1); see {@link SendRequest.category_confidence}. */
557
583
  category_confidence?: number;
584
+ composition_token?: string;
558
585
  }
559
586
  /**
560
587
  * Request body for `POST /v1/inboxes/{addr}/messages/{id}/forward`. Re-sends the
@@ -563,7 +590,7 @@ interface ReplyRequest {
563
590
  * A forward is governed by the SAME review policy as a send, and for a stronger
564
591
  * reason: it is an outbound message to arbitrary NEW recipients that quotes an
565
592
  * entire inbound thread. Leaving it outside the policy would have made forward
566
- * the documented bypass and a worse one than a bare send, because it
593
+ * the documented bypass: and a worse one than a bare send, because it
567
594
  * exfiltrates a received conversation.
568
595
  */
569
596
  interface ForwardRequest {
@@ -589,7 +616,8 @@ interface ForwardRequest {
589
616
  category_id?: string;
590
617
  /** Agent-supplied confidence (0..1); see {@link SendRequest.category_confidence}. */
591
618
  category_confidence?: number;
592
- /** See {@link SendRequest.idempotency_key} — sent as a header, never in the body. */
619
+ composition_token?: string;
620
+ /** See {@link SendRequest.idempotency_key}: sent as a header, never in the body. */
593
621
  idempotency_key?: string;
594
622
  }
595
623
  /**
@@ -599,8 +627,8 @@ interface ForwardRequest {
599
627
  * Its shape differs per verb, which is why almost every field is optional and
600
628
  * this type is NOT the whole story (see {@link SendOutcome}):
601
629
  *
602
- * - `send` → `{status:"sent", message_id, review_id}` **no `thread_id`**.
603
- * - `reply`/`forward` → `{message_id, thread_id, review_id}` no `status`.
630
+ * - `send` → `{status:"sent", message_id, review_id}`: **no `thread_id`**.
631
+ * - `reply`/`forward` → `{message_id, thread_id, review_id}`: no `status`.
604
632
  *
605
633
  * `thread_id` was declared REQUIRED here for a long time while the send path
606
634
  * never returned one, so `res.thread_id` typechecked and was `undefined` at
@@ -615,7 +643,7 @@ interface SendResult {
615
643
  kind?: undefined;
616
644
  /** Extrovert message id of the sent outbound message. */
617
645
  message_id: string;
618
- /** Thread id present on reply/forward; ABSENT on the direct-send response. */
646
+ /** Thread id: present on reply/forward; ABSENT on the direct-send response. */
619
647
  thread_id?: string;
620
648
  /**
621
649
  * Opaque review id (rr_…) of the review row that governed this send. Every
@@ -633,16 +661,16 @@ interface SendResult {
633
661
  * Every shape `inbox.send()` / `.reply()` / `.forward()` / `.submitForReview()`
634
662
  * can return, discriminated by `kind`.
635
663
  *
636
- * There are three, because the resolved review policy not the caller decides
664
+ * There are three, because the resolved review policy: not the caller: decides
637
665
  * what happens to an outbound message:
638
666
  *
639
- * - {@link QueuedForReviewResult} (`kind:"queued_for_review"`, 202) parked for
667
+ * - {@link QueuedForReviewResult} (`kind:"queued_for_review"`, 202): parked for
640
668
  * a human. **Nothing has been delivered yet.** Monitor
641
669
  * `reviewEvents.wait({review_id})` until a `sent` or `send_failed` event
642
670
  * arrives.
643
- * - {@link SentResult} (`kind:"sent"`, 200) delivered immediately, returned to
671
+ * - {@link SentResult} (`kind:"sent"`, 200): delivered immediately, returned to
644
672
  * callers that opted into the review loop by passing mode/intent/category_id.
645
- * - {@link SendResult} (no `kind`, 202) the legacy immediate-send body for a
673
+ * - {@link SendResult} (no `kind`, 202): the legacy immediate-send body for a
646
674
  * caller that mentioned none of those fields.
647
675
  *
648
676
  * Under the default `require_review` policy a send WITHOUT an `intent` does not
@@ -654,15 +682,15 @@ type SendOutcome = SendResult | SentResult | QueuedForReviewResult;
654
682
  /** Per-send agent assertion (D3/D6). The resolved policy may downgrade `direct`. */
655
683
  type ReviewMode = "review" | "direct";
656
684
  /**
657
- * The account/inbox review policy the AUTHORITY on what happens to an outbound
685
+ * The account/inbox review policy: the AUTHORITY on what happens to an outbound
658
686
  * message. There is no way for a caller to opt out of it.
659
687
  *
660
- * - `require_review` the default for every account. A send WITHOUT an `intent`
688
+ * - `require_review`: the default for every account. A send WITHOUT an `intent`
661
689
  * is rejected 422 `intent_required` (nothing sent, nothing queued); a send
662
690
  * WITH one is queued for a human (202 `queued_for_review`).
663
- * - `allow_direct` a bare send (no mode/intent/category_id) is delivered
691
+ * - `allow_direct`: a bare send (no mode/intent/category_id) is delivered
664
692
  * immediately. Supplying an intent, or `mode: "review"`, still queues it.
665
- * - `auto_send_graduated` a categorized message that clears the graduation
693
+ * - `auto_send_graduated`: a categorized message that clears the graduation
666
694
  * gates auto-sends; everything else is queued.
667
695
  *
668
696
  * Read {@link Inbox.effective_review_policy} once before your first send rather
@@ -681,7 +709,7 @@ interface ReviewIntent {
681
709
  urgency?: string;
682
710
  };
683
711
  }
684
- /** A review request (rr_…) the pre-send record under the Review Loop. */
712
+ /** A review request (rr_…): the pre-send record under the Review Loop. */
685
713
  interface Review {
686
714
  id: string;
687
715
  state: ReviewState;
@@ -714,8 +742,8 @@ interface Review {
714
742
  * `failed`**.
715
743
  *
716
744
  * `failed` is included deliberately even though it is not in the formal
717
- * terminal set: nothing in the product can move a failed review the console
718
- * cannot re-approve it so a flag that said `false` there would invite an
745
+ * terminal set: nothing in the product can move a failed review: the console
746
+ * cannot re-approve it: so a flag that said `false` there would invite an
719
747
  * agent to wait forever on a row nobody will ever touch.
720
748
  *
721
749
  * An agent that lost its event cursor (a crash, a fresh process) reads this
@@ -729,7 +757,7 @@ interface Review {
729
757
  send_error?: string;
730
758
  /**
731
759
  * How the message was released, once sent: `human_reviewed`,
732
- * `reviewer_approved`, `graduated_auto` or `agent_direct` without a turns
760
+ * `reviewer_approved`, `graduated_auto` or `agent_direct`: without a turns
733
761
  * fetch.
734
762
  */
735
763
  send_path?: string;
@@ -771,7 +799,7 @@ interface ReviewFeedbackComment {
771
799
  * The human's assembled feedback for a review (spec §11), returned by
772
800
  * `reviews.feedback(id)`: the unified + structured diff of the human edit, the human
773
801
  * comments / rejection feedback, the decision, and the rules born from this review
774
- * (rule_ ids whose source_review_id is this review). $0 LLM pure assembly.
802
+ * (rule_ ids whose source_review_id is this review). $0 LLM: pure assembly.
775
803
  */
776
804
  interface ReviewFeedback {
777
805
  review_id: string;
@@ -788,7 +816,7 @@ interface PostReviewChatRequest {
788
816
  }
789
817
  /**
790
818
  * Body for posting a new agent draft under a parent_revision CAS (spec §5.2; M5,
791
- * D17). parent_revision is the PRIMARY CAS it must equal the draft's current
819
+ * D17). parent_revision is the PRIMARY CAS: it must equal the draft's current
792
820
  * revision, else 409 STALE with NO mutation. version is OPTIONAL belt-and-suspenders.
793
821
  */
794
822
  interface SubmitRevisionRequest {
@@ -797,7 +825,7 @@ interface SubmitRevisionRequest {
797
825
  subject?: string;
798
826
  /**
799
827
  * The redrafted plain-text body. Canonical, matching `text` on send / reply /
800
- * forward the same concept should not have two names in the one flow an
828
+ * forward: the same concept should not have two names in the one flow an
801
829
  * agent runs most.
802
830
  */
803
831
  text?: string;
@@ -811,6 +839,8 @@ interface SubmitRevisionRequest {
811
839
  html?: string;
812
840
  built_at?: IsoTimestamp;
813
841
  rules_version_seen?: number;
842
+ /** Opaque token from the fresh getRules call used for this redraft. */
843
+ composition_token?: string;
814
844
  /**
815
845
  * REPLACES the draft's attachments. Omit the field to leave them untouched;
816
846
  * send an empty array to clear them.
@@ -848,7 +878,7 @@ type ReviewEventReason =
848
878
  * cancel, so compose and submit a NEW message rather than retrying this one.
849
879
  */
850
880
  | "send_failed"
851
- /** Withdrawn by you, by a human, or as the close-out of a failed send. */
881
+ /** Withdrawn: by you, by a human, or as the close-out of a failed send. */
852
882
  | "cancelled"
853
883
  /**
854
884
  * You were front-run: the review reached a terminal state while you were
@@ -856,9 +886,9 @@ type ReviewEventReason =
856
886
  * `cancel_review` answered 409 `terminal`. STOP retrying that review.
857
887
  */
858
888
  | "front_run_next"
859
- /** RESERVED never emitted. Terminal success is `sent`. */
889
+ /** RESERVED: never emitted. Terminal success is `sent`. */
860
890
  | "approved"
861
- /** RESERVED no production producer (the D13 staleness detector is unbuilt). */
891
+ /** RESERVED: no production producer (the D13 staleness detector is unbuilt). */
862
892
  | "staleness";
863
893
  /**
864
894
  * One durable review nudge (ndg_…) drained from the AUTHORITATIVE liveness queue
@@ -874,12 +904,12 @@ interface ReviewEvent {
874
904
  payload?: Record<string, unknown>;
875
905
  created_at: IsoTimestamp;
876
906
  }
877
- /** The agent's per-(agent, review) ack frontier its strict-FIFO position. */
907
+ /** The agent's per-(agent, review) ack frontier: its strict-FIFO position. */
878
908
  interface ReviewEventCursor {
879
909
  review_id: string;
880
910
  last_acked_seq: number;
881
911
  }
882
- /** Drain result for list/wait un-acked events in FIFO seq order + cursors. */
912
+ /** Drain result for list/wait: un-acked events in FIFO seq order + cursors. */
883
913
  interface ReviewEventsResult {
884
914
  events: ReviewEvent[];
885
915
  cursors?: ReviewEventCursor[];
@@ -895,7 +925,7 @@ interface ListReviewEventsParams {
895
925
  * A category (cat_…) in the Review Loop registry (D9/D10). `name` + `description`
896
926
  * are skill-style metadata the agent fuzzy-matches against; nothing keys on the
897
927
  * name (renames never break a reference). Categories are CUSTOMER-scoped and
898
- * agent-attributed the deliberate cross-agent-404 exception. Opaque ids only.
928
+ * agent-attributed: the deliberate cross-agent-404 exception. Opaque ids only.
899
929
  */
900
930
  interface Category {
901
931
  id: string;
@@ -924,13 +954,13 @@ interface ProposeCategoryRequest {
924
954
  /** Defaults to org_shared server-side. */
925
955
  scope?: "org_shared" | "agent_private";
926
956
  }
927
- /** Rename / re-describe a category metadata only (spec §5.5; D10). */
957
+ /** Rename / re-describe a category: metadata only (spec §5.5; D10). */
928
958
  interface UpdateCategoryRequest {
929
959
  name?: string;
930
960
  description?: string;
931
961
  }
932
962
  /**
933
- * The account-wide default risk dial (Review Loop, D4/D12) the values a per-
963
+ * The account-wide default risk dial (Review Loop, D4/D12): the values a per-
934
964
  * category null override inherits. The single user-configurable brand-risk lever.
935
965
  */
936
966
  interface AccountRiskDial {
@@ -968,7 +998,7 @@ interface CategoryRiskDial {
968
998
  }
969
999
  /**
970
1000
  * The effective risk dial (Review Loop, agent plane; D4/D12): the account default
971
- * plus every category's overrides. Read-only for agents flipping the dial is a
1001
+ * plus every category's overrides. Read-only for agents: flipping the dial is a
972
1002
  * console (human) action (D16).
973
1003
  */
974
1004
  interface RiskDial {
@@ -1021,7 +1051,7 @@ type ReviewerAction = "approve" | "edit" | "reject" | "escalate";
1021
1051
  * The REVIEWER's read-only decision surface for a review (BYO review-agent plane;
1022
1052
  * D5/§9), returned by `reviews.decisionContext(id)`: the intent + current draft + the
1023
1053
  * append-only thread + the two-circuit-breaker budget. `force_to_human` is true when
1024
- * EITHER breaker has tripped the reviewer's next reject would be FORCED to the human
1054
+ * EITHER breaker has tripped: the reviewer's next reject would be FORCED to the human
1025
1055
  * regardless of intent (the human is the only terminal authority, D17).
1026
1056
  */
1027
1057
  interface ReviewDecisionContext {
@@ -1045,7 +1075,7 @@ interface ReviewDecisionContext {
1045
1075
  /**
1046
1076
  * Body for a reviewer decision (`reviews.decide(id, req)`; reviewer_decide, D5/§9).
1047
1077
  * `action` is approve|edit|reject|escalate. `revision`/`version` are the optimistic CAS
1048
- * a mismatch is a 409 STALE with NO mutation (the human always wins, D17). subject/
1078
+ *: a mismatch is a 409 STALE with NO mutation (the human always wins, D17). subject/
1049
1079
  * body carry the edited content for the edit action; feedback is the reviewer's note.
1050
1080
  */
1051
1081
  interface ReviewerDecisionRequest {
@@ -1062,8 +1092,8 @@ interface ReviewerDecisionRequest {
1062
1092
  feedback?: string;
1063
1093
  }
1064
1094
  /**
1065
- * The outcome of a reviewer decision (D5/§9). `kind=sent` when the platform ACS-sent
1066
- * with the COMPOSER's creds (approve/edit the reviewer NEVER holds mailbox:send);
1095
+ * The outcome of a reviewer decision (D5/§9). `kind=sent` when the platform sent
1096
+ * with the COMPOSER's creds (approve/edit: the reviewer NEVER holds mailbox:send);
1067
1097
  * `kind=sent_to_human` when the draft returned to the human queue (reject/escalate, or
1068
1098
  * a reject FORCED to the human by a circuit breaker, with `forced_by_breaker` naming it).
1069
1099
  */
@@ -1079,7 +1109,7 @@ interface ReviewerDecisionResult {
1079
1109
  /**
1080
1110
  * The D19/§8 backlog-reconciliation snapshot for a category (agent-readable, $0-LLM).
1081
1111
  * Counts the QUEUED drafts that are stale vs current-enough against the current
1082
- * category rules-version + house-style version (a pure integer compare). Read-only
1112
+ * category rules-version + house-style version (a pure integer compare). Read-only :
1083
1113
  * the agent READS the picture; the human / hooks TRIGGER the actual sweep.
1084
1114
  */
1085
1115
  interface ScanBacklogStatus {
@@ -1102,7 +1132,7 @@ interface PacingItem {
1102
1132
  state: "behind_cursor" | "in_window_fresh" | "in_window_redrafting" | "ahead";
1103
1133
  }
1104
1134
  /**
1105
- * The demand-driven pacing snapshot for a category (agent-readable, $0-LLM M7 Slice
1135
+ * The demand-driven pacing snapshot for a category (agent-readable, $0-LLM: M7 Slice
1106
1136
  * B/§8): the human review cursor, the effective window/ceiling/interval, the queued
1107
1137
  * count, and each queued draft's in-window/redrafting/behind-cursor classification.
1108
1138
  * Read-only; the cursor advances from the human's console approve/reject/edit actions.
@@ -1115,7 +1145,7 @@ interface CategoryPacingState {
1115
1145
  cursor_advanced_count: number;
1116
1146
  /** Effective freshness window (default org_settings.lookahead_window=3). */
1117
1147
  lookahead_window: number;
1118
- /** HARD per-nudge fan-out ceiling (default 10) one nudge can never fan to 500. */
1148
+ /** HARD per-nudge fan-out ceiling (default 10): one nudge can never fan to 500. */
1119
1149
  rework_batch_max: number;
1120
1150
  /** Per-agent token-bucket interval that coalesces feedback storms (default 5000). */
1121
1151
  nudge_min_interval_ms: number;
@@ -1185,17 +1215,27 @@ interface GetRulesParams {
1185
1215
  /** Narrow to one layer (general | category). Default returns both. */
1186
1216
  scope?: "general" | "category";
1187
1217
  }
1218
+ /** Stable effective rule stack plus an opaque proof for the next composition. */
1219
+ interface RuleSnapshot extends Page<Rule> {
1220
+ house_style_version: number;
1221
+ category_rules_version: number;
1222
+ rule_high_water: number;
1223
+ composition_token?: string;
1224
+ composition_token_expires_at?: IsoTimestamp;
1225
+ }
1188
1226
  /**
1189
1227
  * Save / edit a writing rule (append-only by supersession; spec §5.4; D11).
1190
1228
  *
1191
- * Layering (org/project): an agent-plane save is ALWAYS project-layer the saved
1229
+ * Layering (org/project): an agent-plane save is ALWAYS project-layer: the saved
1192
1230
  * rule's `rule_layer` is `project`, bound to the calling key's project. There is no
1193
1231
  * settable `rule_layer` here: an agent cannot create org-layer / house-style
1194
1232
  * (`rule_layer="org"`) rules in v1; authoring org rules is a console/admin action.
1195
- * (`scope: "general"` still means a house-style rule WITHIN the project layer
1233
+ * (`scope: "general"` still means a house-style rule WITHIN the project layer :
1196
1234
  * `scope` is the category axis, `rule_layer` is the ownership axis.)
1197
1235
  */
1198
1236
  interface SaveRuleRequest {
1237
+ /** Stable retry key, sent as Idempotency-Key and omitted from the JSON body. */
1238
+ idempotency_key?: string;
1199
1239
  /** Defaults from category_id (general iff empty). */
1200
1240
  scope?: "general" | "category";
1201
1241
  /** Category id (cat_…); empty = house-style/general (D2). */
@@ -1213,7 +1253,7 @@ interface SaveRuleRequest {
1213
1253
  /**
1214
1254
  * D8 retro-propagation HUMAN OPT-IN (default false). When true, a NEW category rule
1215
1255
  * that could apply to pending siblings enqueues ONE propagate_general_rule nudge
1216
- * (siblings + suggested_batch) so the agent redrafts a FEW at a time never the
1256
+ * (siblings + suggested_batch) so the agent redrafts a FEW at a time: never the
1217
1257
  * whole queue. Set only after the human said "apply to N pending?".
1218
1258
  */
1219
1259
  propagate_to_pending?: boolean;
@@ -1270,7 +1310,7 @@ interface SentResult {
1270
1310
  };
1271
1311
  /**
1272
1312
  * The review row that governed this send (ADDITIVE). Present on every send the
1273
- * service routed, i.e. all of them it is the handle that makes a post-crash
1313
+ * service routed, i.e. all of them: it is the handle that makes a post-crash
1274
1314
  * `reviews.get(id)` possible on the direct path too.
1275
1315
  */
1276
1316
  review?: {
@@ -1290,14 +1330,20 @@ interface Thread {
1290
1330
  /** Owning inbox address. */
1291
1331
  inbox_id: string;
1292
1332
  subject: string;
1293
- /** Distinct participant address strings across the thread. */
1333
+ /** List/search summaries use the latest envelope; thread detail may include the full conversation set. */
1294
1334
  participants: string[];
1295
1335
  message_count: number;
1296
1336
  last_message_at: IsoTimestamp;
1297
1337
  /** Most-recent-message preview snippet. */
1298
1338
  snippet: string;
1339
+ /** Whether the latest message is unread. */
1340
+ unread?: boolean;
1341
+ /** Whether the newest message has one or more attachments. */
1342
+ last_message_has_attachments?: boolean;
1343
+ /** Opaque message id for optimistic reply freshness checks. */
1344
+ last_message_id?: string;
1299
1345
  }
1300
- /** A thread plus its messages (oldest-first) `GET /v1/inboxes/{addr}/threads/{id}`. */
1346
+ /** A thread plus its messages (oldest-first): `GET /v1/inboxes/{addr}/threads/{id}`. */
1301
1347
  interface ThreadDetail extends Thread {
1302
1348
  messages: Message[];
1303
1349
  }
@@ -1469,7 +1515,7 @@ interface SuppressionEntry {
1469
1515
  /**
1470
1516
  * The result of a pre-check (`GET /v1/suppressions?recipient=…`): whether the
1471
1517
  * caller's OWN org suppresses the recipient, plus the matching org rows. Reflects
1472
- * only the caller's org state never a global/shared/cross-tenant opt-out.
1518
+ * only the caller's org state: never a global/shared/cross-tenant opt-out.
1473
1519
  */
1474
1520
  interface SuppressionPrecheck {
1475
1521
  recipient: string;
@@ -1488,7 +1534,7 @@ interface ListSuppressionsParams {
1488
1534
  /** Opaque cursor from a previous page's `next_cursor`. */
1489
1535
  cursor?: string;
1490
1536
  }
1491
- /** One DNS record the customer must set (manual mode) or that we serve (ns_delegated). */
1537
+ /** One nameserver record the customer must publish for delegated setup. */
1492
1538
  interface DomainRecord {
1493
1539
  name: string;
1494
1540
  type: string;
@@ -1502,40 +1548,43 @@ type DomainScope = "org" | "project";
1502
1548
  /**
1503
1549
  * Request body for `POST /v1/domains`. Onboards/adds a domain for the customer.
1504
1550
  *
1505
- * Permissions: every mode needs the `domain:manage` scope (the route gate); `mode:
1506
- * "purchased"` spends money at the registrar and therefore ADDITIONALLY requires the
1507
- * explicit, default-off `domain:purchase` scope (and is capped by the org/project
1508
- * purchased-domain plan limit, enforced before any registrar spend). `manual` and
1509
- * `ns_delegated` need `domain:manage` only.
1551
+ * Requires the `domain:manage` scope. This request only adds a delegated inbox
1552
+ * domain the customer controls; it cannot register one.
1553
+ * New registrations use the separate commerce quote/request workflow.
1510
1554
  */
1511
1555
  interface OnboardDomainRequest {
1512
1556
  domain: string;
1513
1557
  /**
1514
- * Onboarding path. Defaults to `ns_delegated` server-side when omitted. `purchased`
1515
- * additionally requires the `domain:purchase` scope.
1558
+ * Onboarding path. Defaults to `ns_delegated` server-side when omitted.
1516
1559
  */
1517
- mode?: OnboardingMode;
1518
- /** A-record IP served at a delegated zone's apex (ns_delegated only). */
1519
- mail_host_ip?: string;
1560
+ mode?: "ns_delegated";
1520
1561
  /**
1521
1562
  * Domain visibility. Defaults to `org` (org-shared, usable by every project in the
1522
1563
  * org). `project` binds the domain to the key's OWN bound project (never
1523
- * client-selected) so it is only visible/mintable from that project. A
1564
+ * client-selected) so it is only visible/creatable from that project. A
1524
1565
  * legacy/unscoped key (no bound project) falls back to `org`.
1525
1566
  */
1526
1567
  scope?: DomainScope;
1527
1568
  /**
1528
- * Optional assertion that must match the key's bound project NEVER a selector.
1569
+ * Optional assertion that must match the key's bound project: NEVER a selector.
1529
1570
  * A mismatch is a 403. The binding is always derived from the key.
1530
1571
  */
1531
1572
  project_id?: string;
1532
1573
  }
1533
1574
  /**
1534
1575
  * The agent-facing view of one onboarded domain (mirrors the Go `domainResponse`).
1535
- * `records` (and `delegation_ns` for ns_delegated) are present on get / onboard /
1536
- * verify and empty on list reads and for shared/purchased modes.
1576
+ * `delegation_ns` is present on get / onboard / verify for delegated domains and
1577
+ * empty on list reads. `records` remains for legacy response compatibility.
1537
1578
  */
1538
1579
  interface Domain {
1580
+ /** Authoritative outcome. Absent only when talking to an older server; never infer readiness from DKIM. */
1581
+ readiness?: DomainReadiness;
1582
+ /** Customer DNS health, independent of mail provisioning readiness. */
1583
+ delegation?: {
1584
+ status: "pending" | "confirmed" | "rechecking" | "check_delayed" | "action_required";
1585
+ checked_at?: string;
1586
+ confirmed_at?: string;
1587
+ };
1539
1588
  id: string;
1540
1589
  domain: string;
1541
1590
  mode: OnboardingMode;
@@ -1550,10 +1599,48 @@ interface Domain {
1550
1599
  /** Human-facing copy for what the customer must do next. */
1551
1600
  instruction?: string;
1552
1601
  }
1602
+ interface DomainStatusEvent {
1603
+ id: string;
1604
+ type: string;
1605
+ domain: string;
1606
+ summary: string;
1607
+ data: {
1608
+ domain: string;
1609
+ readiness: DomainReadiness;
1610
+ };
1611
+ created_at: string;
1612
+ }
1613
+ interface DomainStatusEventPage {
1614
+ items: DomainStatusEvent[];
1615
+ next_cursor: string;
1616
+ has_more: boolean;
1617
+ poll_after_seconds: number;
1618
+ }
1619
+ interface DomainReadiness {
1620
+ status: "waiting_for_dns" | "checking" | "setting_up" | "ready" | "action_required" | "needs_attention";
1621
+ label: string;
1622
+ summary: string;
1623
+ reason: string;
1624
+ action_required_by: "customer" | "extrovert" | "none";
1625
+ next_action: "check_dns_entries" | "restore_dns" | "wait" | "create_inbox" | "use_inbox" | "ask_owner_to_create_inbox";
1626
+ /** Domain configuration only; creating an inbox still requires permission and available plan capacity. */
1627
+ ready_for_inboxes: boolean;
1628
+ checked_at?: IsoTimestamp;
1629
+ next_check_at?: IsoTimestamp;
1630
+ poll_after_seconds: number;
1631
+ /** Omitted without inbox-read permission. Counts never imply organization-wide visibility for an agent. */
1632
+ inboxes?: {
1633
+ scope: "agent" | "project" | "organization";
1634
+ total: number;
1635
+ ready: number;
1636
+ setting_up: number;
1637
+ needs_attention: number;
1638
+ };
1639
+ }
1553
1640
  /**
1554
1641
  * Result of an ACCEPTED domain offboard (`DELETE /v1/domains/{domain}` → HTTP 202).
1555
- * Teardown reaping the outbound provider senders + routing rows, then scrubbing
1556
- * the DNS zone/records and the domain row runs as an async job. Poll `status_url`
1642
+ * Teardown: reaping the outbound provider senders + routing rows, then scrubbing
1643
+ * the DNS zone/records and the domain row: runs as an async job. Poll `status_url`
1557
1644
  * (`GET /v1/jobs/{job_id}`, via {@link Job} / `client.getJob(job_id)`) until
1558
1645
  * `status` is terminal (succeeded/failed/cancelled); the domain is ACCEPTED for
1559
1646
  * offboard, not yet fully torn down when this returns.
@@ -1578,6 +1665,95 @@ interface Job {
1578
1665
  updated_at: IsoTimestamp;
1579
1666
  finished_at?: IsoTimestamp;
1580
1667
  }
1668
+ /** One exact reason a commerce request cannot advance automatically. */
1669
+ interface CommerceBlocker {
1670
+ code: string;
1671
+ message: string;
1672
+ scope?: "org" | "project" | "agent" | string;
1673
+ limit_id?: string;
1674
+ used_cents?: number;
1675
+ reserved_cents?: number;
1676
+ limit_cents?: number;
1677
+ requested_cents?: number;
1678
+ used_count?: number;
1679
+ reserved_count?: number;
1680
+ limit_count?: number;
1681
+ reset_at?: IsoTimestamp;
1682
+ manage_url?: string;
1683
+ }
1684
+ /** Request body for the non-spending domain quote endpoint. */
1685
+ interface QuoteDomainRequest {
1686
+ domain: string;
1687
+ }
1688
+ /** Current, expiring domain registration quote. Quoting never purchases. */
1689
+ interface DomainQuote {
1690
+ object: "domain_quote";
1691
+ domain: string;
1692
+ available: boolean;
1693
+ currency: string;
1694
+ quote_cents: number;
1695
+ renewal_cents: number;
1696
+ premium: boolean;
1697
+ quote_expires_at: IsoTimestamp;
1698
+ required_plan?: string;
1699
+ required_plan_price_cents?: number;
1700
+ blockers: CommerceBlocker[];
1701
+ }
1702
+ type CommerceRequestKind = "domain_purchase" | "plan_change";
1703
+ interface RequestDomainPurchaseRequest {
1704
+ domain: string;
1705
+ /** Stable retry identity; sent as the `Idempotency-Key` header, not in the JSON body. */
1706
+ idempotency_key: string;
1707
+ scope?: DomainScope;
1708
+ rationale?: string;
1709
+ auto_renew?: boolean;
1710
+ }
1711
+ interface RequestPlanChangeRequest {
1712
+ target_plan: "free" | "developer" | "startup";
1713
+ /** Stable retry identity; sent as the `Idempotency-Key` header, not in the JSON body. */
1714
+ idempotency_key: string;
1715
+ rationale?: string;
1716
+ }
1717
+ interface ListCommerceRequestsParams {
1718
+ limit?: number;
1719
+ page?: string;
1720
+ }
1721
+ /** Durable poll shape for an agent-initiated financial request. */
1722
+ interface CommerceRequest {
1723
+ object: "commerce_request";
1724
+ id: string;
1725
+ project_id?: string;
1726
+ agent_id?: string;
1727
+ kind: CommerceRequestKind;
1728
+ state: string;
1729
+ domain?: string;
1730
+ domain_scope?: DomainScope;
1731
+ target_plan?: string;
1732
+ current_plan?: string;
1733
+ rationale?: string;
1734
+ currency: string;
1735
+ quote_cents: number;
1736
+ renewal_cents: number;
1737
+ approved_max_cents?: number;
1738
+ quote_expires_at?: IsoTimestamp;
1739
+ auto_renew: boolean;
1740
+ required_plan?: string;
1741
+ required_plan_price_cents?: number;
1742
+ blocker_code?: string;
1743
+ blockers: CommerceBlocker[];
1744
+ approval_url?: string;
1745
+ payment_action_url?: string;
1746
+ external_job_id?: string;
1747
+ effective_at?: IsoTimestamp;
1748
+ notification_state?: string;
1749
+ notification_last_error?: string;
1750
+ agent_next_action: string;
1751
+ retry_safe: boolean;
1752
+ poll_after_seconds: number;
1753
+ version: number;
1754
+ created_at: IsoTimestamp;
1755
+ updated_at: IsoTimestamp;
1756
+ }
1581
1757
  /**
1582
1758
  * One event from the SSE stream (`GET /v1/inboxes/{addr}/stream` or `GET
1583
1759
  * /v1/events`). It is the SAME envelope a webhook delivers, so a stream consumer
@@ -1614,12 +1790,12 @@ interface StreamOptions {
1614
1790
  interface SignUpRequest {
1615
1791
  /** Human email that receives the one-time verification code. */
1616
1792
  human_email: string;
1617
- /** Desired local-part for the first inbox (optional; auto-generated when omitted). */
1793
+ /** Desired local part on `free.extrovertmail.com`. It must normalize to at least 5 characters and cannot use a reserved name. */
1618
1794
  username?: string;
1619
1795
  }
1620
1796
  /**
1621
1797
  * Response from `POST /v1/agent/sign-up`. The `agent_key` is a LIMITED-scope key
1622
- * (read-only) that expires with the emailed code. Successful verification revokes
1798
+ * (verification-only, with no inbox read or send permission) that expires with the emailed code. Successful verification revokes
1623
1799
  * it and returns a replacement full-scope key. The OTP itself is never returned.
1624
1800
  */
1625
1801
  interface SignUpResponse {
@@ -1629,7 +1805,7 @@ interface SignUpResponse {
1629
1805
  agent_key: string;
1630
1806
  key_prefix: string;
1631
1807
  scopes: Scope[];
1632
- /** The first inbox minted for the agent. */
1808
+ /** The first inbox created for the agent. */
1633
1809
  address: string;
1634
1810
  verified: boolean;
1635
1811
  /** Where the verification code was sent. */
@@ -1678,14 +1854,28 @@ interface VerifyResponse {
1678
1854
  org_claim_token?: string;
1679
1855
  }
1680
1856
  /**
1681
- * Response from `GET /v1/auth/me` the verified principal behind the key.
1857
+ * Response from `GET /v1/auth/me`: the verified principal behind the key.
1682
1858
  *
1683
1859
  * `org_id`/`project_id` are the FIXED org/project the key is bound to (resolved from
1684
1860
  * the stored key, never client input). There is NO mutable project selector for a
1685
- * scoped key `whoami` is the canonical project-visibility surface; project
1861
+ * scoped key: `whoami` is the canonical project-visibility surface; project
1686
1862
  * selection happens when the human/admin issues the enrollment token or agent key.
1687
1863
  */
1688
1864
  interface WhoAmI {
1865
+ connection_status?: "connected";
1866
+ summary?: string;
1867
+ agent_name?: string;
1868
+ organization_name?: string;
1869
+ project_name?: string;
1870
+ /** Granted permissions, not a guarantee of plan capacity or review approval. */
1871
+ capabilities?: {
1872
+ read_domain_status: boolean;
1873
+ connect_owned_domains: boolean;
1874
+ create_inboxes: boolean;
1875
+ read_inboxes: boolean;
1876
+ submit_mail_for_review: boolean;
1877
+ request_purchases: boolean;
1878
+ };
1689
1879
  customer_id: string;
1690
1880
  /**
1691
1881
  * The fixed org the key is bound to. Optional to match the OpenAPI contract: a
@@ -1707,7 +1897,7 @@ interface WhoAmI {
1707
1897
  *
1708
1898
  * Every redesign collection endpoint (the canonical `x.projects.inboxes.*` chain
1709
1899
  * and beyond) returns {@link List}: `{ object: "list", data, has_more, next_cursor }`.
1710
- * `next_cursor` is OPAQUE treat it as a token and pass it back verbatim as
1900
+ * `next_cursor` is OPAQUE - treat it as a token and pass it back verbatim as
1711
1901
  * `?cursor` to fetch the next page. {@link ListPage} wraps a raw {@link List} with
1712
1902
  * ergonomic iteration (`for await … of`) and a `nextPage()` cursor walker so callers
1713
1903
  * never thread cursors by hand.
@@ -1757,7 +1947,7 @@ declare class ListPage<T> implements AsyncIterable<T> {
1757
1947
  readonly object: "list";
1758
1948
  constructor(raw: List<T>, fetcher: PageFetcher<T>);
1759
1949
  /**
1760
- * Fetch the next page. Throws if there is none guard with {@link hasMore}.
1950
+ * Fetch the next page. Throws if there is none - guard with {@link hasMore}.
1761
1951
  */
1762
1952
  nextPage(signal?: AbortSignal): Promise<ListPage<T>>;
1763
1953
  /**
@@ -1833,12 +2023,25 @@ interface Transport {
1833
2023
  precheckSuppression(recipient: string, signal?: AbortSignal): Promise<SuppressionPrecheck>;
1834
2024
  listSuppressions(params: ListSuppressionsParams, signal?: AbortSignal): Promise<Page<SuppressionEntry>>;
1835
2025
  revokeSuppression(id: string, reason: string, signal?: AbortSignal): Promise<SuppressionEntry>;
1836
- listDomains(signal?: AbortSignal): Promise<Page<Domain>>;
2026
+ listDomains(signal?: AbortSignal, params?: {
2027
+ page?: string;
2028
+ limit?: number;
2029
+ }): Promise<Page<Domain>>;
2030
+ listDomainEvents(domain: string, params: {
2031
+ after?: string;
2032
+ limit?: number;
2033
+ }, signal?: AbortSignal): Promise<DomainStatusEventPage>;
1837
2034
  getDomain(domain: string, signal?: AbortSignal): Promise<Domain>;
1838
2035
  onboardDomain(req: OnboardDomainRequest, signal?: AbortSignal): Promise<Domain>;
1839
2036
  verifyDomain(domain: string, signal?: AbortSignal): Promise<Domain>;
1840
2037
  offboardDomain(domain: string, signal?: AbortSignal): Promise<DomainOffboard>;
1841
2038
  getJob(jobId: string, signal?: AbortSignal): Promise<Job>;
2039
+ quoteDomain(req: QuoteDomainRequest, signal?: AbortSignal): Promise<DomainQuote>;
2040
+ requestDomainPurchase(req: RequestDomainPurchaseRequest, signal?: AbortSignal): Promise<CommerceRequest>;
2041
+ requestPlanChange(req: RequestPlanChangeRequest, signal?: AbortSignal): Promise<CommerceRequest>;
2042
+ getCommerceRequest(requestId: string, signal?: AbortSignal): Promise<CommerceRequest>;
2043
+ cancelCommerceRequest(requestId: string, signal?: AbortSignal): Promise<CommerceRequest>;
2044
+ listCommerceRequests(params: ListCommerceRequestsParams, signal?: AbortSignal): Promise<Page<CommerceRequest>>;
1842
2045
  submitForReview(address: string, req: SendRequest, signal?: AbortSignal): Promise<SendOutcome>;
1843
2046
  submitReplyForReview(address: string, req: ReplyRequest, signal?: AbortSignal): Promise<SendOutcome>;
1844
2047
  listReviews(params: ListReviewsParams, signal?: AbortSignal): Promise<Page<Review>>;
@@ -1863,7 +2066,7 @@ interface Transport {
1863
2066
  proposeGraduation(categoryId: string, req: ProposeGraduationRequest, signal?: AbortSignal): Promise<GraduationStatus>;
1864
2067
  getScanBacklogStatus(categoryId: string, signal?: AbortSignal): Promise<ScanBacklogStatus>;
1865
2068
  getCategoryPacingState(categoryId: string, signal?: AbortSignal): Promise<CategoryPacingState>;
1866
- getRules(params: GetRulesParams, signal?: AbortSignal): Promise<Page<Rule>>;
2069
+ getRules(params: GetRulesParams, signal?: AbortSignal): Promise<RuleSnapshot>;
1867
2070
  saveRule(req: SaveRuleRequest, signal?: AbortSignal): Promise<Rule>;
1868
2071
  promoteRule(ruleId: string, toScope: "general" | "category", signal?: AbortSignal): Promise<Rule>;
1869
2072
  retireRule(ruleId: string, signal?: AbortSignal): Promise<Rule>;
@@ -1887,7 +2090,7 @@ interface Transport {
1887
2090
  *
1888
2091
  * The mock honors the same request/response models as the real API and reproduces the few behaviors
1889
2092
  * the SDK ergonomics depend on (enrollment cap, idempotency on `client_id`, wait_for_email returning
1890
- * an OTP). It is intentionally simple not a full server and never reaches the network.
2093
+ * an OTP). It is intentionally simple - not a full server - and never reaches the network.
1891
2094
  */
1892
2095
 
1893
2096
  /**
@@ -1915,7 +2118,7 @@ declare class MockBackend {
1915
2118
  * Normalize an inbox ref (opaque id OR address alias) to the canonical address the
1916
2119
  * mock keys its message/thread/contact maps on. The SDK now routes inbox ops by the
1917
2120
  * canonical opaque `id` when it holds a full record (matching the contract's
1918
- * canonical-key semantics), so the mock must resolve an id back to its address
2121
+ * canonical-key semantics), so the mock must resolve an id back to its address -
1919
2122
  * both key `state.inboxes` (same object), `state.messages` keys by address only.
1920
2123
  * Unknown refs pass through unchanged so the existing not-found paths still fire.
1921
2124
  */
@@ -1945,8 +2148,8 @@ declare class MockBackend {
1945
2148
  forward(address: string, messageId: string, req: ForwardRequest): SendOutcome;
1946
2149
  /**
1947
2150
  * Submit a new message for review (mock). Rides the SAME endpoint as `send` on
1948
- * the real server, so it is literally the same call here: the resolved policy
1949
- * not which SDK method you picked decides whether the message is queued
2151
+ * the real server, so it is literally the same call here: the resolved policy -
2152
+ * not which SDK method you picked - decides whether the message is queued
1950
2153
  * (`kind:"queued_for_review"`) or delivered.
1951
2154
  */
1952
2155
  submitForReview(address: string, req: SendRequest): SendOutcome;
@@ -1967,9 +2170,9 @@ declare class MockBackend {
1967
2170
  private setReviewState;
1968
2171
  /** Mark a review delivered on an auto-send path and emit its terminal `sent` nudge. */
1969
2172
  private markReviewAutoSent;
1970
- /** Raw delivery for a send no policy, only reachable from submitOutbound. */
2173
+ /** Raw delivery for a send - no policy, only reachable from submitOutbound. */
1971
2174
  private deliverSend;
1972
- /** Raw delivery for a reply no policy, only reachable from submitOutbound. */
2175
+ /** Raw delivery for a reply - no policy, only reachable from submitOutbound. */
1973
2176
  private deliverReply;
1974
2177
  /** Append the outbound message and shape the legacy send result. */
1975
2178
  private deliverRaw;
@@ -2033,7 +2236,7 @@ declare class MockBackend {
2033
2236
  reviewerDecide(reviewId: string, req: ReviewerDecisionRequest): ReviewerDecisionResult | undefined;
2034
2237
  /**
2035
2238
  * Browse the registry (mock), newest-first, excluding merged/soft-deleted. `match`
2036
- * is a pure lexical filter (every token must appear in name+description) NO LLM,
2239
+ * is a pure lexical filter (every token must appear in name+description) - NO LLM,
2037
2240
  * mirroring the server.
2038
2241
  */
2039
2242
  listCategories(params?: ListCategoriesParams): Page<Category>;
@@ -2041,14 +2244,14 @@ declare class MockBackend {
2041
2244
  getCategory(categoryId: string): Category | undefined;
2042
2245
  /** Propose a category (mock): stands immediately, author_kind=agent (D9). */
2043
2246
  proposeCategory(req: ProposeCategoryRequest): Category;
2044
- /** Rename / re-describe a category (mock) metadata only (D10). */
2247
+ /** Rename / re-describe a category (mock) - metadata only (D10). */
2045
2248
  updateCategory(categoryId: string, req: UpdateCategoryRequest): Category | undefined;
2046
2249
  /** The mock account-default risk dial (mirrors the server defaults). */
2047
2250
  private accountDial;
2048
2251
  /**
2049
2252
  * Read the effective risk dial (mock): the account default + every category with an
2050
2253
  * inherited (null override) effective dial. The mock category carries no overrides,
2051
- * so every category inherits effective == account.
2254
+ * so every category inherits - effective == account.
2052
2255
  */
2053
2256
  getRiskDial(): RiskDial;
2054
2257
  private nextGraduationState;
@@ -2060,19 +2263,19 @@ declare class MockBackend {
2060
2263
  getGraduationStatus(categoryId: string): GraduationStatus | undefined;
2061
2264
  /**
2062
2265
  * Propose graduating a category (mock): returns the current gate status without
2063
- * changing the category state (D16 an agent can never flip the bit).
2266
+ * changing the category state (D16 - an agent can never flip the bit).
2064
2267
  */
2065
2268
  proposeGraduation(categoryId: string, _req: ProposeGraduationRequest): GraduationStatus | undefined;
2066
2269
  /**
2067
2270
  * Read the D19/§8 backlog-reconciliation status (mock): counts the QUEUED drafts in a
2068
2271
  * category that are stale vs current-enough against the current rules-version. The
2069
2272
  * mock has no per-draft composed_* stamps on its Review fixtures, so every queued
2070
- * draft reads as current-enough (composed 0 vs current 0) the contract shape is
2273
+ * draft reads as current-enough (composed 0 vs current 0) - the contract shape is
2071
2274
  * exercised; the integer-compare logic is covered by the Go tests.
2072
2275
  */
2073
2276
  getScanBacklogStatus(categoryId: string): ScanBacklogStatus | undefined;
2074
2277
  /**
2075
- * Read the demand-driven pacing state (mock M7 Slice B/§8): the cursor + effective
2278
+ * Read the demand-driven pacing state (mock - M7 Slice B/§8): the cursor + effective
2076
2279
  * window/ceiling/interval + each queued draft's classification. The mock has no cursor
2077
2280
  * (nothing reviewed) and no composed_* stamps, so every queued draft reads in-window-
2078
2281
  * fresh until the window fills, then ahead; the contract shape is exercised (the
@@ -2081,17 +2284,17 @@ declare class MockBackend {
2081
2284
  getCategoryPacingState(categoryId: string): CategoryPacingState | undefined;
2082
2285
  /** rank a rule for the §7 ladder (mock mirror of the server's deterministic order). */
2083
2286
  private ruleRank;
2084
- /** Get the ORDERED active rule set (mock) §7 ladder + category-before-general. */
2085
- getRules(params?: GetRulesParams): Page<Rule>;
2086
- /** Save / edit a rule (mock) append-only by supersession (D11). */
2287
+ /** Get the ORDERED active rule set (mock) - §7 ladder + category-before-general. */
2288
+ getRules(params?: GetRulesParams): RuleSnapshot;
2289
+ /** Save / edit a rule (mock) - append-only by supersession (D11). */
2087
2290
  saveRule(req: SaveRuleRequest): Rule;
2088
2291
  /** Promote a rule between layers (mock, via supersession), or undefined when unknown. */
2089
2292
  promoteRule(ruleId: string, toScope: "general" | "category"): Rule | undefined;
2090
- /** Retire a rule (mock) soft delete, or undefined when unknown. */
2293
+ /** Retire a rule (mock) - soft delete, or undefined when unknown. */
2091
2294
  retireRule(ruleId: string): Rule | undefined;
2092
2295
  /** Read the rule/category change audit log (mock). */
2093
2296
  getRuleAudit(params?: GetRuleAuditParams): Page<RuleAuditEntry>;
2094
- /** Undo a rule change (mock) restore the prior version; idempotent (re-undo 409). */
2297
+ /** Undo a rule change (mock) - restore the prior version; idempotent (re-undo 409). */
2095
2298
  undoRuleChange(udoId: string): Rule;
2096
2299
  /** recordRuleAudit appends one change/undo audit row (mock). */
2097
2300
  private recordRuleAudit;
@@ -2108,7 +2311,7 @@ declare class MockBackend {
2108
2311
  */
2109
2312
  private enqueueTerminalNudge;
2110
2313
  /**
2111
- * Enqueue `front_run_next` the signal that the review reached a terminal state
2314
+ * Enqueue `front_run_next` - the signal that the review reached a terminal state
2112
2315
  * while the agent was still trying to act on it.
2113
2316
  *
2114
2317
  * Deduped on (review, terminal state, parent revision) so a retry loop hitting
@@ -2126,8 +2329,8 @@ declare class MockBackend {
2126
2329
  }): Review | undefined;
2127
2330
  /**
2128
2331
  * Mock-only: mirror an approved draft whose delivery then FAILED at the provider.
2129
- * This is the case the composing agent was previously never told about the
2130
- * console showed the error and the agent's queue stayed silent so the loop test
2332
+ * This is the case the composing agent was previously never told about - the
2333
+ * console showed the error and the agent's queue stayed silent - so the loop test
2131
2334
  * that matters most drives this path.
2132
2335
  */
2133
2336
  simulateSendFailed(reviewId: string, error?: string): Review | undefined;
@@ -2155,7 +2358,7 @@ declare class MockBackend {
2155
2358
  listReviewEvents(params?: ListReviewEventsParams): ReviewEventsResult;
2156
2359
  /**
2157
2360
  * Long-poll for a review event (mock). Offline there is nothing to wait FOR, so it
2158
- * returns the immediate drain (empty when caught up) the server's "empty on
2361
+ * returns the immediate drain (empty when caught up) - the server's "empty on
2159
2362
  * timeout" contract.
2160
2363
  */
2161
2364
  waitForReviewEvent(params?: WaitForReviewEventParams): ReviewEventsResult;
@@ -2178,9 +2381,10 @@ declare class MockBackend {
2178
2381
  getMessageRaw(messageId: string): string;
2179
2382
  /** Full-text search scoped to one inbox. */
2180
2383
  searchMessages(address: string, params: SearchMessagesParams): Page<Message>;
2181
- listThreads(address: string): Page<Thread>;
2384
+ listThreads(address: string, params?: ListThreadsParams): Page<Thread>;
2182
2385
  /** Thread-level search (subject / snippet / participant substring). */
2183
2386
  searchThreads(address: string, params: SearchMessagesParams): Page<Thread>;
2387
+ private paginateThreads;
2184
2388
  /** Fetch one thread (with messages, oldest-first) by id under an inbox. */
2185
2389
  getThread(address: string, threadId: string): ThreadDetail;
2186
2390
  /**
@@ -2235,7 +2439,7 @@ declare class MockBackend {
2235
2439
  listContactLists(address: string): Page<ContactListEntry> | undefined;
2236
2440
  /** Delete a contact-list entry by id; returns false when it was not found. */
2237
2441
  deleteContactListEntry(_address: string, entryId: string): boolean;
2238
- /** Onboard a domain, mirroring the server's per-mode record set + status. Idempotent on the name. */
2442
+ /** Add a delegated domain and return only the customer-published nameservers. */
2239
2443
  onboardDomain(req: OnboardDomainRequest): Domain;
2240
2444
  /** List onboarded domains (records omitted on the summary, mirroring the server). */
2241
2445
  listDomains(): Page<Domain>;
@@ -2252,6 +2456,12 @@ declare class MockBackend {
2252
2456
  offboardDomain(domain: string): boolean;
2253
2457
  /** Get one async job's poll status; undefined when the id is unknown. */
2254
2458
  getJob(jobId: string): Job | undefined;
2459
+ quoteDomain(req: QuoteDomainRequest): DomainQuote;
2460
+ requestDomainPurchase(req: RequestDomainPurchaseRequest): CommerceRequest;
2461
+ requestPlanChange(req: RequestPlanChangeRequest): CommerceRequest;
2462
+ getCommerceRequest(requestId: string): CommerceRequest | undefined;
2463
+ cancelCommerceRequest(requestId: string): CommerceRequest | undefined;
2464
+ listCommerceRequests(params?: ListCommerceRequestsParams): Page<CommerceRequest>;
2255
2465
  /**
2256
2466
  * Pre-check whether the caller's org suppresses a recipient (mirrors
2257
2467
  * `GET /v1/suppressions?recipient=…`). Returns `{recipient, suppressed, rows}`
@@ -2269,7 +2479,7 @@ declare class MockBackend {
2269
2479
  /**
2270
2480
  * Reject the WHOLE send if ANY recipient has an active org-scope suppression,
2271
2481
  * naming exactly the suppressed addresses (never the scope/origin) so the caller
2272
- * can drop them and retry mirroring the live `recipient_suppressed` (422) path.
2482
+ * can drop them and retry - mirroring the live `recipient_suppressed` (422) path.
2273
2483
  */
2274
2484
  private enforceSuppression;
2275
2485
  /**
@@ -2280,19 +2490,25 @@ declare class MockBackend {
2280
2490
  private enforceSendPolicy;
2281
2491
  }
2282
2492
 
2493
+ interface DomainWaitResult {
2494
+ domain: Domain;
2495
+ outcome: "ready" | "action_required" | "needs_attention" | "timed_out" | "status_unavailable";
2496
+ resume_after_seconds: number;
2497
+ }
2498
+
2283
2499
  /**
2284
2500
  * Key-tier awareness (redesign §3.1).
2285
2501
  *
2286
2502
  * An agent key encodes its CEILING tier in its raw prefix. The SDK never trusts
2287
- * client input for scope the tier is derived from the key the caller already
2503
+ * client input for scope - the tier is derived from the key the caller already
2288
2504
  * holds, purely as a client-side hint so an app can branch (e.g. an org-tier key
2289
2505
  * MUST pick a project breadth on a list; a project/inbox key may use the bare
2290
2506
  * sugar). The server remains the source of truth; this is advisory only.
2291
2507
  *
2292
2508
  * Prefix scheme (the secret tail is unchanged across tiers):
2293
- * - `pk_agent_org_…` → {@link KeyTier.Org} (admin/console mint only)
2509
+ * - `pk_agent_org_…` → {@link KeyTier.Org} (admin/console issuance only)
2294
2510
  * - `pk_agent_proj_…` → {@link KeyTier.Project} (enrollment redeem + console)
2295
- * - `pk_agent_inbox_…` → {@link KeyTier.Inbox} (admin/console mint only)
2511
+ * - `pk_agent_inbox_…` → {@link KeyTier.Inbox} (admin/console issuance only)
2296
2512
  * - legacy `pk_agent_…` (no tier segment) → {@link KeyTier.Project}
2297
2513
  */
2298
2514
  /** The ceiling tier encoded in an agent key's prefix. */
@@ -2300,7 +2516,7 @@ type KeyTier = "org" | "project" | "inbox" | "unknown";
2300
2516
  /**
2301
2517
  * Derive the {@link KeyTier} from a raw agent key by peeking the segment after the
2302
2518
  * `pk_agent_` head. A legacy bare `pk_agent_…` key (no tier segment) maps to
2303
- * `"project"` exactly today's behavior. A non-agent credential (enrollment
2519
+ * `"project"` - exactly today's behavior. A non-agent credential (enrollment
2304
2520
  * token, Clerk session, empty) returns `"unknown"`.
2305
2521
  */
2306
2522
  declare function parseKeyTier(apiKey: string | undefined): KeyTier;
@@ -2318,7 +2534,7 @@ declare function tierAllowsOrgWildcard(tier: KeyTier): boolean;
2318
2534
  declare function tierNeedsExplicitBreadth(tier: KeyTier): boolean;
2319
2535
 
2320
2536
  /**
2321
- * InboxHandle an ergonomic, bound handle to a single inbox.
2537
+ * InboxHandle: an ergonomic, bound handle to a single inbox.
2322
2538
  *
2323
2539
  * Returned by `extrovert.inboxes.create(...)` and `extrovert.inbox(address)`, it scopes every operation
2324
2540
  * to one address so agent code reads naturally: `inbox.send(...)`, `inbox.waitForEmail(...)`. This
@@ -2332,7 +2548,7 @@ interface InboxHandleOptions {
2332
2548
  declare class InboxHandle {
2333
2549
  private readonly transport;
2334
2550
  private readonly options;
2335
- /** The canonical address, e.g. `agent7@smtp.extrovert.dev`. */
2551
+ /** The canonical address, e.g. `agent7@extrovertmail.com`. */
2336
2552
  readonly address: string;
2337
2553
  /** The full inbox record this handle was created from (absent when constructed by address). */
2338
2554
  readonly record: Inbox | undefined;
@@ -2378,8 +2594,8 @@ declare class InboxHandle {
2378
2594
  * Returns a three-way {@link SendOutcome}: `kind:"queued_for_review"` means a
2379
2595
  * human has to approve it and NOTHING has been delivered yet; anything else was
2380
2596
  * delivered. Under the default `require_review` policy a call WITHOUT an
2381
- * `intent` raises `IntentRequiredError` (422) instead nothing sent, nothing
2382
- * queued so pass one, or read `inbox.record.effective_review_policy` first.
2597
+ * `intent` raises `IntentRequiredError` (422) instead: nothing sent, nothing
2598
+ * queued: so pass one, or read `inbox.record.effective_review_policy` first.
2383
2599
  */
2384
2600
  send(req: SendRequest, signal?: AbortSignal): Promise<SendOutcome>;
2385
2601
  /**
@@ -2387,14 +2603,14 @@ declare class InboxHandle {
2387
2603
  * the latest message) or `message_id` (reply to that message); the server
2388
2604
  * derives To / Subject / In-Reply-To / References. Set `reply_all` to reply to
2389
2605
  * every thread recipient. Returns the same three-way {@link SendOutcome} as
2390
- * {@link send} a reply is governed by the review policy too.
2606
+ * {@link send}: a reply is governed by the review policy too.
2391
2607
  */
2392
2608
  reply(req: ReplyRequest, signal?: AbortSignal): Promise<SendOutcome>;
2393
2609
  /**
2394
2610
  * Forward a message in this inbox to new recipients, preserving the original.
2395
2611
  *
2396
2612
  * A forward is an outbound message to arbitrary NEW recipients that quotes an
2397
- * inbound thread, so it is governed by the review policy exactly like a send
2613
+ * inbound thread, so it is governed by the review policy exactly like a send :
2398
2614
  * same {@link SendOutcome} union, same `intent` requirement.
2399
2615
  */
2400
2616
  forward(messageId: string, req: ForwardRequest, signal?: AbortSignal): Promise<SendOutcome>;
@@ -2495,7 +2711,7 @@ declare class InboxHandle {
2495
2711
  }
2496
2712
 
2497
2713
  /**
2498
- * `extrovert.projects` the CANONICAL project-scoped resource chain (redesign §4).
2714
+ * `extrovert.projects`: the CANONICAL project-scoped resource chain (redesign §4).
2499
2715
  *
2500
2716
  * Scope lives in the KEY; a broad (org-tier) key narrows to one project by PATH.
2501
2717
  * The headline chain is `x.projects.inboxes.*`, mirroring
@@ -2510,7 +2726,7 @@ declare class InboxHandle {
2510
2726
  *
2511
2727
  * Operations are keyed by the OPAQUE `inbox_id` (the inbox's email address is also
2512
2728
  * accepted as a within-project alias). `projectId` may be `"-"` for the org-wide
2513
- * wildcard only an org-tier key may use it (others get 403 `forbidden_scope`).
2729
+ * wildcard: only an org-tier key may use it (others get 403 `forbidden_scope`).
2514
2730
  *
2515
2731
  * The bare `x.inboxes.*` / `x.inbox(address)` surface is curl-style sugar that
2516
2732
  * resolves to the key's default project; this chain is the contract-canonical one.
@@ -2522,7 +2738,7 @@ interface ProjectsContext {
2522
2738
  handleOptions: InboxHandleOptions;
2523
2739
  }
2524
2740
  /**
2525
- * `x.projects.inboxes` create / list / get / update / delete inboxes, plus the
2741
+ * `x.projects.inboxes`: create / list / get / update / delete inboxes, plus the
2526
2742
  * send / reply / message / thread / wait operations, all scoped to one project (or
2527
2743
  * the `-` org wildcard for an org-tier key). List returns a {@link ListPage} that
2528
2744
  * auto-paginates over the opaque-cursor {@link import("../pagination.js").List} envelope.
@@ -2558,8 +2774,8 @@ declare class ProjectInboxes {
2558
2774
  * Returns a three-way {@link SendOutcome}: `kind:"queued_for_review"` means a
2559
2775
  * human has to approve it and NOTHING has been delivered yet; anything else was
2560
2776
  * delivered. Under the default `require_review` policy a call WITHOUT an
2561
- * `intent` raises `IntentRequiredError` (422) instead nothing sent, nothing
2562
- * queued so pass one, or read `inbox.record.effective_review_policy` first.
2777
+ * `intent` raises `IntentRequiredError` (422) instead: nothing sent, nothing
2778
+ * queued: so pass one, or read `inbox.record.effective_review_policy` first.
2563
2779
  */
2564
2780
  send(projectId: string, inboxId: string, req: SendRequest, signal?: AbortSignal): Promise<SendOutcome>;
2565
2781
  /** Reply within a thread from an inbox in `projectId`. See {@link send} on the return union. */
@@ -2594,14 +2810,14 @@ declare class ProjectInboxes {
2594
2810
  *
2595
2811
  * The frozen contract project-prefixes ONLY the inbox collection/item/credentials
2596
2812
  * routes (`/v1/projects/{project_id}/inboxes[/{inbox_id}][/credentials]`); the
2597
- * send/reply/forward/message/thread/wait sub-ops have NO project-prefixed path
2813
+ * send/reply/forward/message/thread/wait sub-ops have NO project-prefixed path :
2598
2814
  * they address the inbox by its opaque id directly (`/v1/inboxes/{inbox_id}/…`),
2599
2815
  * where the project is implicit in (and enforced by) the inbox id server-side.
2600
2816
  *
2601
2817
  * So for these sub-ops `projectId` cannot be carried on the URL and is NOT a URL
2602
2818
  * selector. The adversarial review flagged that silently discarding it makes the
2603
2819
  * signature misleading. CHOICE: keep the arg (dropping it would break the chain's
2604
- * symmetry with create/list/get/update/delete the more disruptive option) but
2820
+ * symmetry with create/list/get/update/delete: the more disruptive option) but
2605
2821
  * VALIDATE it rather than ignore it. We reject the two client mistakes we can catch
2606
2822
  * without a round-trip:
2607
2823
  * - a blank / whitespace-only `projectId` (a required selector everywhere else in
@@ -2613,12 +2829,12 @@ declare class ProjectInboxes {
2613
2829
  private ref;
2614
2830
  }
2615
2831
  /**
2616
- * `extrovert.projects` the canonical project-scoped resource namespace. Today it
2832
+ * `extrovert.projects`: the canonical project-scoped resource namespace. Today it
2617
2833
  * exposes the `inboxes` chain (`x.projects.inboxes.*`); future project-scoped
2618
2834
  * resources (domains, agents) hang off the same namespace.
2619
2835
  */
2620
2836
  declare class Projects {
2621
- /** `x.projects.inboxes.*` the canonical inbox chain. */
2837
+ /** `x.projects.inboxes.*`: the canonical inbox chain. */
2622
2838
  readonly inboxes: ProjectInboxes;
2623
2839
  constructor(ctx: ProjectsContext);
2624
2840
  }
@@ -2639,25 +2855,26 @@ interface ResourceContext {
2639
2855
  */
2640
2856
  keyTier: KeyTier;
2641
2857
  }
2642
- /** `extrovert.inboxes` create, list, get, update, delete inboxes. */
2858
+ /** `extrovert.inboxes`: create, list, get, update, delete inboxes. */
2643
2859
  declare class Inboxes {
2644
2860
  private readonly ctx;
2645
2861
  constructor(ctx: ResourceContext);
2646
2862
  /**
2647
- * Create an inbox. The default path mints an address on a pre-verified shared subdomain of
2648
- * `smtp.extrovert.dev`, so it returns a live, send-and-receive-capable inbox in one call.
2863
+ * Create an inbox. The default path creates an address on `extrovertmail.com`
2864
+ * for paid accounts or `free.extrovertmail.com` for free signups, so it returns
2865
+ * a live inbox in one call.
2649
2866
  *
2650
2867
  * Pass `metadata` to attach arbitrary key-value data, and `client_id` for idempotent creation
2651
2868
  * (re-calling with the same id returns the same inbox, with its metadata replayed verbatim).
2652
2869
  */
2653
2870
  create(req?: CreateInboxRequest, signal?: AbortSignal): Promise<InboxHandle>;
2654
2871
  /**
2655
- * List inboxes visible to the calling key (the bare curl-sugar surface resolves
2872
+ * List inboxes visible to the calling key (the bare curl-sugar surface: resolves
2656
2873
  * to the key's default project). An org-tier key has no single default project, so
2657
2874
  * the bare list is ambiguous: fail fast client-side with a BreadthRequiredError that
2658
2875
  * names the next call, matching the MCP surface, instead of round-tripping to a 400.
2659
2876
  * Use `extrovert.projects.inboxes.list("<project_id>")` or `"-"` (org subtree) for
2660
- * an org key. The check is advisory the server stays authoritative.
2877
+ * an org key. The check is advisory: the server stays authoritative.
2661
2878
  */
2662
2879
  list(params?: ListInboxesParams, signal?: AbortSignal): Promise<Page<Inbox>>;
2663
2880
  /** Fetch a single inbox and return an ergonomic handle bound to it. */
@@ -2678,7 +2895,7 @@ declare class Inboxes {
2678
2895
  delete(address: string, signal?: AbortSignal): Promise<void>;
2679
2896
  }
2680
2897
  /**
2681
- * `extrovert.messages` read a message, fetch its raw bytes, mark it read.
2898
+ * `extrovert.messages`: read a message, fetch its raw bytes, mark it read.
2682
2899
  *
2683
2900
  * Reply and forward are inbox-scoped (the server resolves the parent and derives
2684
2901
  * recipients), so they live on the {@link InboxHandle} (`inbox.reply(...)`,
@@ -2723,21 +2940,27 @@ declare class Messages {
2723
2940
  getAttachment(inbox: string, messageId: string, attachmentId: string, signal?: AbortSignal): Promise<AttachmentDownload>;
2724
2941
  }
2725
2942
  /**
2726
- * `extrovert.threads` fetch a conversation thread (with its messages) by id,
2727
- * scoped to its owning inbox.
2943
+ * `extrovert.threads`: list, search, read, reply to, and delete conversations,
2944
+ * scoped to their owning inbox.
2728
2945
  */
2729
2946
  declare class Threads {
2730
2947
  private readonly ctx;
2731
2948
  constructor(ctx: ResourceContext);
2949
+ /** List conversations newest-active first. Pass `next_cursor` back as `cursor` for the next page. */
2950
+ list(inbox: string, params?: ListThreadsParams, signal?: AbortSignal): Promise<Page<Thread>>;
2951
+ /** Search thread subjects, snippets, and participants. Cursor pagination matches {@link list}. */
2952
+ search(inbox: string, params: SearchMessagesParams, signal?: AbortSignal): Promise<Page<Thread>>;
2732
2953
  /** Fetch one thread (+ its messages, oldest-first) by id under its owning inbox address. */
2733
2954
  get(inbox: string, threadId: string, signal?: AbortSignal): Promise<ThreadDetail>;
2955
+ /** Reply in a thread; recipients and RFC reply headers are derived server-side. */
2956
+ reply(inbox: string, req: ReplyRequest, signal?: AbortSignal): Promise<SendOutcome>;
2734
2957
  /**
2735
2958
  * Delete an entire thread (every message): move to Trash (default) or
2736
2959
  * permanently remove when `expunge` is true. `inbox` is the owning address.
2737
2960
  */
2738
2961
  delete(inbox: string, threadId: string, expunge?: boolean, signal?: AbortSignal): Promise<DeleteResult>;
2739
2962
  }
2740
- /** `extrovert.webhooks` register / list / get / update / delete HMAC-signed inbound webhooks. */
2963
+ /** `extrovert.webhooks`: register / list / get / update / delete HMAC-signed inbound webhooks. */
2741
2964
  declare class Webhooks {
2742
2965
  private readonly ctx;
2743
2966
  constructor(ctx: ResourceContext);
@@ -2758,7 +2981,7 @@ declare class Webhooks {
2758
2981
  delete(webhookId: string, signal?: AbortSignal): Promise<void>;
2759
2982
  }
2760
2983
  /**
2761
- * `extrovert.contactLists` per-inbox allow/block lists of addresses/domains.
2984
+ * `extrovert.contactLists`: per-inbox allow/block lists of addresses/domains.
2762
2985
  * A `block` entry rejects a send to a matching recipient; once an `allow` entry
2763
2986
  * exists for an inbox, sends from it are restricted to matching recipients
2764
2987
  * (allowlist mode). Entries are addressable by their opaque id (`lst_…`).
@@ -2774,12 +2997,12 @@ declare class ContactLists {
2774
2997
  delete(inbox: string, entryId: string, signal?: AbortSignal): Promise<void>;
2775
2998
  }
2776
2999
  /**
2777
- * `extrovert.suppressions` recipient opt-outs (list-unsubscribe). A recipient
3000
+ * `extrovert.suppressions`: recipient opt-outs (list-unsubscribe). A recipient
2778
3001
  * that has unsubscribed cannot be mailed by this org: a send to them is rejected
2779
3002
  * with `recipient_suppressed` ({@link RecipientSuppressedError}). Use `precheck`
2780
3003
  * before composing to skip a would-be-rejected recipient, `list` to browse the
2781
3004
  * org's opt-outs, and `revoke` (reason required, audit-logged) to re-enable a
2782
- * recipient. All reads/writes are scoped to the caller's OWN org a
3005
+ * recipient. All reads/writes are scoped to the caller's OWN org: a
2783
3006
  * platform-global or shared-domain opt-out is never surfaced here.
2784
3007
  */
2785
3008
  declare class Suppressions {
@@ -2787,7 +3010,7 @@ declare class Suppressions {
2787
3010
  constructor(ctx: ResourceContext);
2788
3011
  /**
2789
3012
  * Pre-check whether the caller's org already suppresses a recipient, BEFORE
2790
- * composing. `suppressed: true` means a send to them would be rejected skip
3013
+ * composing. `suppressed: true` means a send to them would be rejected: skip
2791
3014
  * that recipient. Returns the matching org rows too (never a global/shared row).
2792
3015
  */
2793
3016
  precheck(recipient: string, signal?: AbortSignal): Promise<SuppressionPrecheck>;
@@ -2801,25 +3024,36 @@ declare class Suppressions {
2801
3024
  revoke(id: string, reason: string, signal?: AbortSignal): Promise<SuppressionEntry>;
2802
3025
  }
2803
3026
  /**
2804
- * `extrovert.domains` the customer's domains (privileged; the agent key must
2805
- * carry the `domain:manage` scope). Onboard (shared | ns_delegated | manual |
2806
- * purchased), read status + the DNS records to set inline, trigger/refresh
2807
- * verification, and offboard. `mode: "purchased"` spends money at the registrar and
2808
- * ADDITIONALLY requires the explicit, default-off `domain:purchase` scope (and is
2809
- * capped by the org/project purchased-domain plan limit). Set `scope: "project"` to
2810
- * bind the domain to the key's project; it defaults to `org` (org-shared).
3027
+ * `extrovert.domains`: read with domain:read or domain:manage; changes require
3028
+ * domain:manage. Add delegated inbox domains the customer
3029
+ * controls, read status + nameserver records inline, trigger/refresh
3030
+ * verification, and offboard. New registrations use `extrovert.commerce`: quote
3031
+ * first, create a request, then poll its status. Set `scope: "project"` to bind a
3032
+ * customer-controlled domain to the key's project; it defaults to `org`.
2811
3033
  */
2812
3034
  declare class Domains {
2813
3035
  private readonly ctx;
2814
3036
  constructor(ctx: ResourceContext);
2815
3037
  /** List the customer's onboarded domains and their status. */
2816
- list(signal?: AbortSignal): Promise<Page<Domain>>;
2817
- /** Get one domain's detail + verification status + the DNS records to set, inline. */
3038
+ list(paramsOrSignal?: {
3039
+ page?: string;
3040
+ limit?: number;
3041
+ } | AbortSignal, signal?: AbortSignal): Promise<Page<Domain>>;
3042
+ /** Get one domain's detail, verification status, and nameserver records. */
2818
3043
  get(domain: string, signal?: AbortSignal): Promise<Domain>;
2819
- /**
2820
- * Onboard (add) a domain. `mode` defaults to ns_delegated. `mode: "purchased"`
2821
- * requires the `domain:purchase` scope (in addition to `domain:manage`). Returns
2822
- * the record set / NS instruction.
3044
+ /** Wait up to 50 seconds, then return an explicit resumable outcome. No DNS writes. */
3045
+ wait(domain: string, options?: {
3046
+ timeout_seconds?: number;
3047
+ signal?: AbortSignal;
3048
+ }): Promise<DomainWaitResult>;
3049
+ /** Resume durable updates for this domain using the previous next_cursor as after. */
3050
+ events(domain: string, params?: {
3051
+ after?: string;
3052
+ limit?: number;
3053
+ }, signal?: AbortSignal): Promise<DomainStatusEventPage>;
3054
+ /**
3055
+ * Add a delegated inbox domain the customer controls. Returns the nameserver
3056
+ * records to publish and never spends money.
2823
3057
  */
2824
3058
  onboard(req: OnboardDomainRequest, signal?: AbortSignal): Promise<Domain>;
2825
3059
  /** Trigger or refresh verification for a domain; returns its (possibly advanced) status. */
@@ -2833,7 +3067,29 @@ declare class Domains {
2833
3067
  offboard(domain: string, signal?: AbortSignal): Promise<DomainOffboard>;
2834
3068
  }
2835
3069
  /**
2836
- * `extrovert.reviews` the Review Loop (HITL) agent-plane reads. A sending agent
3070
+ * `extrovert.commerce`: quote, request, cancel, and poll financial operations. Agents
3071
+ * can never approve a request through this resource; approval is a human console
3072
+ * action. Every create requires a stable idempotency key.
3073
+ */
3074
+ declare class Commerce {
3075
+ private readonly ctx;
3076
+ constructor(ctx: ResourceContext);
3077
+ private requireIdempotencyKey;
3078
+ /** Quote a domain without purchasing, reserving, or approving it. */
3079
+ quoteDomain(req: QuoteDomainRequest, signal?: AbortSignal): Promise<DomainQuote>;
3080
+ /** Create a durable domain-purchase request for human approval. */
3081
+ requestDomainPurchase(req: RequestDomainPurchaseRequest, signal?: AbortSignal): Promise<CommerceRequest>;
3082
+ /** Create a durable plan-upgrade or downgrade request for human approval. */
3083
+ requestPlanChange(req: RequestPlanChangeRequest, signal?: AbortSignal): Promise<CommerceRequest>;
3084
+ /** Poll one request's exact blockers, approval URL, and next-action guidance. */
3085
+ get(requestId: string, signal?: AbortSignal): Promise<CommerceRequest>;
3086
+ /** Withdraw this agent's request while its durable state still permits cancellation. */
3087
+ cancel(requestId: string, signal?: AbortSignal): Promise<CommerceRequest>;
3088
+ /** List visible commerce requests using the API's opaque page token. */
3089
+ list(params?: ListCommerceRequestsParams, signal?: AbortSignal): Promise<Page<CommerceRequest>>;
3090
+ }
3091
+ /**
3092
+ * `extrovert.reviews`: the Review Loop (HITL) agent-plane reads. A sending agent
2837
3093
  * monitors its submissions in the human-review queue: list/get a review request and
2838
3094
  * read its append-only thread of turns (intent, drafts, human comments/edits/
2839
3095
  * decisions, captured diffs). Submitting FOR review rides `inbox.send` /
@@ -2843,7 +3099,7 @@ declare class Domains {
2843
3099
  declare class Reviews {
2844
3100
  private readonly ctx;
2845
3101
  /**
2846
- * `extrovert.reviews.events` the Review Loop (HITL) realtime plane: drain,
3102
+ * `extrovert.reviews.events`: the Review Loop (HITL) realtime plane: drain,
2847
3103
  * long-poll, and ack the durable nudge queue (the AUTHORITATIVE liveness source;
2848
3104
  * SSE/webhook are best-effort fast paths on top of it).
2849
3105
  */
@@ -2858,20 +3114,20 @@ declare class Reviews {
2858
3114
  /**
2859
3115
  * Get the human's assembled feedback (M5): the diff + comments + decision + the
2860
3116
  * rules born from this review. Read it after a rejected/edited nudge to learn what
2861
- * the human wanted. $0 LLM pure assembly on our side.
3117
+ * the human wanted. $0 LLM: pure assembly on our side.
2862
3118
  */
2863
3119
  feedback(reviewId: string, signal?: AbortSignal): Promise<ReviewFeedback>;
2864
3120
  /**
2865
3121
  * Post a chat turn on a review's thread (M5): an agent question to the human
2866
3122
  * reviewer; flips in_review -> chatting on the first turn. Idempotent on the
2867
- * optional `idempotencyKey` (the `Idempotency-Key` header). $0 LLM you compose it.
3123
+ * optional `idempotencyKey` (the `Idempotency-Key` header). $0 LLM: you compose it.
2868
3124
  */
2869
3125
  chat(reviewId: string, req: PostReviewChatRequest, idempotencyKey?: string, signal?: AbortSignal): Promise<Review>;
2870
3126
  /**
2871
3127
  * Post a new agent draft under a parent_revision CAS (M5; D17). parent_revision
2872
3128
  * must equal the draft's current revision, else a 409 STALE with NO mutation (the
2873
- * human always wins re-read, re-apply, retry). On success the draft is re-rendered
2874
- * in place (revision++) and returns to needs_review. $0 LLM you compose the redraft.
3129
+ * human always wins: re-read, re-apply, retry). On success the draft is re-rendered
3130
+ * in place (revision++) and returns to needs_review. $0 LLM: you compose the redraft.
2875
3131
  */
2876
3132
  revise(reviewId: string, req: SubmitRevisionRequest, signal?: AbortSignal): Promise<Review>;
2877
3133
  /**
@@ -2884,9 +3140,9 @@ declare class Reviews {
2884
3140
  * assert "I reviewed this against rules vX and no change is needed", advancing the
2885
3141
  * draft's composed_* versions with no new draft, no revision bump, no nudge. A
2886
3142
  * born-stale draft re-stamped to the current version becomes current-enough and
2887
- * releasable on the next reconciliation sweep the cheap counterpart to revise().
3143
+ * releasable on the next reconciliation sweep: the cheap counterpart to revise().
2888
3144
  * against_version above the category's current rules-version is 400; a terminal draft
2889
- * 409s. $0 LLM you judged.
3145
+ * 409s. $0 LLM: you judged.
2890
3146
  */
2891
3147
  restamp(reviewId: string, req: RestampReviewRequest, signal?: AbortSignal): Promise<Review>;
2892
3148
  /**
@@ -2901,22 +3157,22 @@ declare class Reviews {
2901
3157
  decisionContext(reviewId: string, signal?: AbortSignal): Promise<ReviewDecisionContext>;
2902
3158
  /**
2903
3159
  * Submit a reviewer decision (M8 Slice B; reviewer_decide, D5/§9). approve/edit → the
2904
- * PLATFORM ACS-sends with the COMPOSER's credentials (the reviewer NEVER holds
2905
- * mailbox:send on an inbox it doesn't own the credential boundary); reject → back to
3160
+ * PLATFORM sends with the COMPOSER's credentials (the reviewer NEVER holds
3161
+ * mailbox:send on an inbox it doesn't own: the credential boundary); reject → back to
2906
3162
  * the composer (needs_review, hop_count++); escalate → the human queue. revision/
2907
- * version are the CAS (409 STALE on mismatch, NO mutation the human always wins,
3163
+ * version are the CAS (409 STALE on mismatch, NO mutation: the human always wins,
2908
3164
  * D17). The two circuit breakers (hop_count ≥ max_hops, or the hard review_deadline)
2909
- * FORCE a reject to the human regardless of intent `forced_by_breaker` names it. $0
2910
- * LLM you judged; we route, send, and enforce the breakers.
3165
+ * FORCE a reject to the human regardless of intent: `forced_by_breaker` names it. $0
3166
+ * LLM: you judged; we route, send, and enforce the breakers.
2911
3167
  */
2912
3168
  decide(reviewId: string, req: ReviewerDecisionRequest, signal?: AbortSignal): Promise<ReviewerDecisionResult>;
2913
3169
  }
2914
3170
  /**
2915
- * `extrovert.reviews.events` drain / long-poll / ack the durable review nudge
3171
+ * `extrovert.reviews.events`: drain / long-poll / ack the durable review nudge
2916
3172
  * queue (spec §5.9). `list` is a non-blocking, side-effect-free drain of the next
2917
3173
  * un-acked nudges in FIFO seq order (strict per review); `wait` long-polls
2918
3174
  * (~25–55s) for the next one; `ack` advances the per-(agent, review) cursor
2919
- * monotonically (idempotent re-acking an older seq is a no-op).
3175
+ * monotonically (idempotent: re-acking an older seq is a no-op).
2920
3176
  */
2921
3177
  declare class ReviewEvents {
2922
3178
  private readonly ctx;
@@ -2929,10 +3185,10 @@ declare class ReviewEvents {
2929
3185
  ack(req: AckReviewEventRequest, signal?: AbortSignal): Promise<AckReviewEventResult>;
2930
3186
  }
2931
3187
  /**
2932
- * `extrovert.categories` the Review Loop category registry (D9/D10). Browse and
3188
+ * `extrovert.categories`: the Review Loop category registry (D9/D10). Browse and
2933
3189
  * MATCH an existing category before composing (like a skills registry), or propose
2934
3190
  * a new one. Categories are CUSTOMER-scoped and agent-attributed (the deliberate
2935
- * cross-agent-404 exception); identity is opaque cat_ ids nothing keys on the
3191
+ * cross-agent-404 exception); identity is opaque cat_ ids: nothing keys on the
2936
3192
  * name, so renames never break a reference. `match` is a pure lexical filter (NO
2937
3193
  * LLM on our side); the agent does the semantic matching. Merging / deleting a
2938
3194
  * category is a human (console) action, not exposed here (D17).
@@ -2946,12 +3202,12 @@ declare class Categories {
2946
3202
  get(categoryId: string, signal?: AbortSignal): Promise<Category>;
2947
3203
  /** Propose a new category; it stands immediately and writes a create audit row. */
2948
3204
  propose(req: ProposeCategoryRequest, signal?: AbortSignal): Promise<Category>;
2949
- /** Rename / re-describe a category metadata only (D10). */
3205
+ /** Rename / re-describe a category: metadata only (D10). */
2950
3206
  update(categoryId: string, req: UpdateCategoryRequest, signal?: AbortSignal): Promise<Category>;
2951
3207
  /**
2952
3208
  * Read the effective risk dial (D4/D12): the account default + every category's
2953
3209
  * overrides (each with its resolved effective value; null override = inherit).
2954
- * Read-only agents read but NEVER flip the dial; setting it is a human (console)
3210
+ * Read-only: agents read but NEVER flip the dial; setting it is a human (console)
2955
3211
  * action (D16).
2956
3212
  */
2957
3213
  riskDial(signal?: AbortSignal): Promise<RiskDial>;
@@ -2963,14 +3219,14 @@ declare class Categories {
2963
3219
  graduationStatus(categoryId: string, signal?: AbortSignal): Promise<GraduationStatus>;
2964
3220
  /**
2965
3221
  * Propose graduating a category (D16/D6): RECORDS the request (durable evidence) and
2966
- * returns the current gate status. It does NOT change the category state flipping
3222
+ * returns the current gate status. It does NOT change the category state: flipping
2967
3223
  * the bit is a human (console) action; an agent only proposes.
2968
3224
  */
2969
3225
  proposeGraduation(categoryId: string, req?: ProposeGraduationRequest, signal?: AbortSignal): Promise<GraduationStatus>;
2970
3226
  /**
2971
3227
  * Read the D19/§8 backlog-reconciliation status: how many of the category's QUEUED
2972
3228
  * drafts are stale vs current-enough against the current rules-version (a pure
2973
- * integer compare, $0 LLM). Read-only you READ the picture; the human (console
3229
+ * integer compare, $0 LLM). Read-only: you READ the picture; the human (console
2974
3230
  * scan-backlog) or the graduate/rule-change hooks TRIGGER the actual reconciliation
2975
3231
  * sweep that releases current-enough drafts and nudges stale ones to redraft.
2976
3232
  */
@@ -2986,39 +3242,39 @@ declare class Categories {
2986
3242
  pacingState(categoryId: string, signal?: AbortSignal): Promise<CategoryPacingState>;
2987
3243
  }
2988
3244
  /**
2989
- * `extrovert.rules` the Review Loop writing-rule store + house-style + the §7
3245
+ * `extrovert.rules`: the Review Loop writing-rule store + house-style + the §7
2990
3246
  * precedence ladder + audit/undo (D2/D11). ANY agent in the customer may write,
2991
- * edit, promote, retire, and undo rules (the deliberate cross-agent exception the
3247
+ * edit, promote, retire, and undo rules (the deliberate cross-agent exception: the
2992
3248
  * shared house-style is the whole pitch). `get()` returns the ORDERED active rule
2993
3249
  * set with the precedence ladder applied SERVER-SIDE (NO LLM on our side); the agent
2994
3250
  * reconciles the list semantically. Rules are append-only by supersession; undo
2995
3251
  * restores the prior version as a forward 'restore' supersession. Identity is opaque
2996
- * rule_/rln_/udo_ ids nothing keys on a name.
3252
+ * rule_/rln_/udo_ ids: nothing keys on a name.
2997
3253
  */
2998
3254
  declare class Rules {
2999
3255
  private readonly ctx;
3000
3256
  constructor(ctx: ResourceContext);
3001
3257
  /** Get the ORDERED active rule set (precedence ladder applied; NO LLM). */
3002
- get(params?: GetRulesParams, signal?: AbortSignal): Promise<Page<Rule>>;
3258
+ get(params?: GetRulesParams, signal?: AbortSignal): Promise<RuleSnapshot>;
3003
3259
  /**
3004
3260
  * Save / edit a rule (append-only by supersession; D11). An agent-plane save is
3005
3261
  * ALWAYS project-layer: the saved rule's `rule_layer` is `project`, bound to the
3006
3262
  * key's project. Agents cannot author org-layer / house-style (`rule_layer:"org"`)
3007
- * rules in v1 that is a console/admin action.
3263
+ * rules in v1: that is a console/admin action.
3008
3264
  */
3009
3265
  save(req: SaveRuleRequest, signal?: AbortSignal): Promise<Rule>;
3010
3266
  /** Promote a rule between the category and general/house-style layers. */
3011
3267
  promote(ruleId: string, toScope: "general" | "category", signal?: AbortSignal): Promise<Rule>;
3012
- /** Retire a rule soft delete; the history survives as training data. */
3268
+ /** Retire a rule: soft delete; the history survives as training data. */
3013
3269
  retire(ruleId: string, signal?: AbortSignal): Promise<Rule>;
3014
3270
  /** Read the rule/category change audit log (the safety net, D11). */
3015
3271
  audit(params?: GetRuleAuditParams, signal?: AbortSignal): Promise<Page<RuleAuditEntry>>;
3016
- /** Undo a rule change by its audit-row id (udo_…) restore the prior version. */
3272
+ /** Undo a rule change by its audit-row id (udo_…): restore the prior version. */
3017
3273
  undo(udoId: string, signal?: AbortSignal): Promise<Rule>;
3018
3274
  }
3019
3275
 
3020
3276
  /**
3021
- * ExtrovertClient the entry point.
3277
+ * ExtrovertClient - the entry point.
3022
3278
  *
3023
3279
  * ```ts
3024
3280
  * import { Extrovert } from "@extrovert.dev/sdk";
@@ -3069,28 +3325,30 @@ interface ExtrovertClientOptions {
3069
3325
  mockBackend?: MockBackend;
3070
3326
  }
3071
3327
  declare class ExtrovertClient {
3072
- /** `extrovert.inboxes` create / list / get / update / delete inboxes. */
3328
+ /** `extrovert.inboxes` - create / list / get / update / delete inboxes. */
3073
3329
  readonly inboxes: Inboxes;
3074
- /** `extrovert.messages` read a message, reply to it (threaded). */
3330
+ /** `extrovert.messages` - read a message, reply to it (threaded). */
3075
3331
  readonly messages: Messages;
3076
- /** `extrovert.threads` fetch a conversation thread. */
3332
+ /** `extrovert.threads` - fetch a conversation thread. */
3077
3333
  readonly threads: Threads;
3078
- /** `extrovert.webhooks` register HMAC-signed inbound webhooks. */
3334
+ /** `extrovert.webhooks` - register HMAC-signed inbound webhooks. */
3079
3335
  readonly webhooks: Webhooks;
3080
- /** `extrovert.contactLists` per-inbox allow/block lists of addresses/domains. */
3336
+ /** `extrovert.contactLists` - per-inbox allow/block lists of addresses/domains. */
3081
3337
  readonly contactLists: ContactLists;
3082
- /** `extrovert.suppressions` recipient opt-outs (list-unsubscribe); precheck/list/revoke. */
3338
+ /** `extrovert.suppressions` - recipient opt-outs (list-unsubscribe); precheck/list/revoke. */
3083
3339
  readonly suppressions: Suppressions;
3084
- /** `extrovert.domains` the customer's domains (privileged; domain:manage scope). */
3340
+ /** `extrovert.domains` - domain readiness and setup (domain:read or domain:manage to read; domain:manage to change). */
3085
3341
  readonly domains: Domains;
3086
- /** `extrovert.reviews` the Review Loop (HITL) agent-plane reads. */
3342
+ /** `extrovert.commerce` - quote/request/cancel/poll financial actions; no agent approval methods. */
3343
+ readonly commerce: Commerce;
3344
+ /** `extrovert.reviews` - the Review Loop (HITL) agent-plane reads. */
3087
3345
  readonly reviews: Reviews;
3088
- /** `extrovert.categories` the Review Loop category registry (browse/propose/curate). */
3346
+ /** `extrovert.categories` - the Review Loop category registry (browse/propose/curate). */
3089
3347
  readonly categories: Categories;
3090
- /** `extrovert.rules` the Review Loop writing-rule store + house-style + audit/undo. */
3348
+ /** `extrovert.rules` - the Review Loop writing-rule store + house-style + audit/undo. */
3091
3349
  readonly rules: Rules;
3092
3350
  /**
3093
- * `extrovert.projects` the CANONICAL project-scoped chain. The headline is
3351
+ * `extrovert.projects` - the CANONICAL project-scoped chain. The headline is
3094
3352
  * `extrovert.projects.inboxes.*` (create/list/get/update/delete/send/...), keyed by
3095
3353
  * the opaque `inbox_id` and scoped to a `{project_id}` path (or `-` for the org
3096
3354
  * wildcard on an org-tier key). The bare `extrovert.inboxes` surface is curl sugar
@@ -3106,7 +3364,7 @@ declare class ExtrovertClient {
3106
3364
  readonly apiVersion: string;
3107
3365
  /**
3108
3366
  * The CEILING tier derived from the configured agent key prefix (`org` | `project`
3109
- * | `inbox` | `unknown`). Advisory client-side hint only the server is the source
3367
+ * | `inbox` | `unknown`). Advisory client-side hint only - the server is the source
3110
3368
  * of truth. Lets an app branch (e.g. require a project pick for an org-tier key).
3111
3369
  */
3112
3370
  readonly keyTier: KeyTier;
@@ -3114,18 +3372,22 @@ declare class ExtrovertClient {
3114
3372
  private readonly handleOptions;
3115
3373
  constructor(options?: ExtrovertClientOptions);
3116
3374
  /**
3117
- * Redeem an enrollment token (`pk_enroll_...`) and mint a scoped agent key.
3375
+ * Redeem an enrollment token (`pk_enroll_...`) and issue a scoped agent key.
3118
3376
  *
3119
3377
  * Idempotent on `agent_handle`: redeeming twice with the same handle returns the same agent.
3120
- * Returns the raw `EnrollResponse` to immediately use the minted key, prefer
3378
+ * Returns the raw `EnrollResponse` - to immediately use the issued key, prefer
3121
3379
  * {@link ExtrovertClient.enrolled}.
3122
3380
  */
3123
3381
  enroll(req: EnrollRequest, signal?: AbortSignal): Promise<EnrollResponse>;
3124
3382
  /**
3125
- * Grab a free account in one unauthenticated call (Slice E). Provisions a tenant
3126
- * + a first inbox and returns a LIMITED-scope (read-only) agent key; a one-time
3127
- * code is emailed to `human_email`. Call {@link verify} with the code to unlock
3128
- * full scopes. Idempotent on `human_email`: re-calling rotates the key + resends.
3383
+ * Request a free account in one unauthenticated call. When free signup is
3384
+ * enabled, this provisions a tenant plus a first inbox and returns a
3385
+ * verification-only agent key. That key can only call {@link verify}; it cannot
3386
+ * read or send mail. A one-time code is emailed to `human_email`. Call
3387
+ * {@link verify} with the code to activate the account and receive full scopes.
3388
+ * Idempotent on `human_email`: re-calling rotates the key and resends the code.
3389
+ * When free signup is paused, this throws an `ApiError` with status 403 and
3390
+ * code `signup_disabled` without creating account state.
3129
3391
  */
3130
3392
  signUp(req: SignUpRequest, signal?: AbortSignal): Promise<SignUpResponse>;
3131
3393
  /**
@@ -3133,20 +3395,22 @@ declare class ExtrovertClient {
3133
3395
  * once). Must be called with the limited key from {@link signUp} as the bearer.
3134
3396
  * The result repeats the ready inbox address and includes MCP-first list/read/wait
3135
3397
  * calls; SDK callers can pass `address` directly to `inboxes` and `messages`.
3398
+ * Pending verification is also fail-closed with 403 `signup_disabled` while
3399
+ * free signup is paused.
3136
3400
  */
3137
3401
  verify(req: VerifyRequest, signal?: AbortSignal): Promise<VerifyResponse>;
3138
3402
  /** Introspect the principal behind the current key (`GET /v1/auth/me`). */
3139
3403
  whoami(signal?: AbortSignal): Promise<WhoAmI>;
3140
3404
  /**
3141
- * Poll the status of an async job (`GET /v1/jobs/{job_id}`) currently only
3405
+ * Poll the status of an async job (`GET /v1/jobs/{job_id}`) - currently only
3142
3406
  * the domain-offboard teardown started by {@link Domains.offboard} enqueues
3143
3407
  * one. `status` is terminal on succeeded/failed/cancelled; keep polling
3144
3408
  * otherwise. An unknown or foreign job id is a {@link NotFoundError}.
3145
3409
  */
3146
3410
  getJob(jobId: string, signal?: AbortSignal): Promise<Job>;
3147
3411
  /**
3148
- * Redeem an enrollment token and return a *new* client already authenticated with the minted
3149
- * agent key the natural "redeem then act" flow for an agent.
3412
+ * Redeem an enrollment token and return a *new* client already authenticated with the issued
3413
+ * agent key - the natural "redeem then act" flow for an agent.
3150
3414
  *
3151
3415
  * ```ts
3152
3416
  * const bootstrap = new Extrovert({ apiKey: enrollmentToken });
@@ -3162,7 +3426,7 @@ declare class ExtrovertClient {
3162
3426
  enrollment: EnrollResponse;
3163
3427
  }>;
3164
3428
  /**
3165
- * Get an ergonomic handle to an existing inbox by address without an extra round-trip. Use this
3429
+ * Get an ergonomic handle to an existing inbox by address - without an extra round-trip. Use this
3166
3430
  * when you already know the address (e.g. from a previous create) and want to send/wait/reply.
3167
3431
  * Call {@link InboxHandle.refresh} to load the full record.
3168
3432
  */
@@ -3205,7 +3469,7 @@ declare class ExtrovertClient {
3205
3469
  */
3206
3470
  /**
3207
3471
  * The CLOSED problem code enum (mirrors `components.schemas.Problem.code` in the
3208
- * frozen OpenAPI). Adding a member is a contract change keep it in lockstep with
3472
+ * frozen OpenAPI). Adding a member is a contract change - keep it in lockstep with
3209
3473
  * the Go `ProblemCode` enum.
3210
3474
  */
3211
3475
  type ProblemCode = "bad_request" | "unauthorized" | "forbidden_scope" | "not_found" | "conflict" | "idempotency_conflict" | "breadth_required" | "quota_exceeded" | "rate_limited" | "domain_not_allowed" | "recipient_blocked" | "recipient_suppressed" | "not_configured" | "domain_unavailable" | "internal" | "intent_required" | "wrong_state" | "terminal" | "stale" | "born_stale" | "send_needs_reconciliation" | "graduation_locked" | "maturity_gate_unmet" | "scope_taken" | "unavailable";
@@ -3218,11 +3482,11 @@ declare const PROBLEM_CODES: readonly ProblemCode[];
3218
3482
  * compare-and-set (`stale`) and a redraft built against an older rule high-water
3219
3483
  * (`born_stale`) describe a situation a retry can fix, and each only a bounded
3220
3484
  * number of times (re-read, re-apply on top of the other party's change,
3221
- * resubmit). `wrong_state` means the verb is wrong, not the timing read the
3485
+ * resubmit). `wrong_state` means the verb is wrong, not the timing - read the
3222
3486
  * `allowed_action` hints and pick another one. `terminal` means the review is
3223
3487
  * finished forever; a `front_run_next` nudge is already waiting on the queue
3224
3488
  * with the outcome. `send_needs_reconciliation` means a delivery attempt is
3225
- * unconfirmed resending is precisely how a message goes out twice.
3489
+ * unconfirmed - resending is precisely how a message goes out twice.
3226
3490
  *
3227
3491
  * `intent_required` is listed false because retrying the SAME bytes fails
3228
3492
  * identically: the fix is to ADD an `intent` and send a different request. The
@@ -3327,38 +3591,38 @@ declare class ApiError extends Error {
3327
3591
  /** True for 5xx responses (server errors that may succeed on retry). */
3328
3592
  get isServerError(): boolean;
3329
3593
  }
3330
- /** 401 the agent key / enrollment token was missing, malformed, expired, or revoked. */
3594
+ /** 401 - the agent key / enrollment token was missing, malformed, expired, or revoked. */
3331
3595
  declare class AuthenticationError extends ApiError {
3332
3596
  }
3333
- /** 403 authenticated, but the key's scopes don't permit this action (capability denied). */
3597
+ /** 403 - authenticated, but the key's scopes don't permit this action (capability denied). */
3334
3598
  declare class PermissionError extends ApiError {
3335
3599
  }
3336
3600
  /**
3337
- * 403 `forbidden_scope` the call is outside the key's CEILING (e.g. a non-org key
3338
- * on the org-wide wildcard, or a mint that would escalate). A redesign-specific
3601
+ * 403 `forbidden_scope` - the call is outside the key's CEILING (e.g. a non-org key
3602
+ * on the org-wide wildcard, or an issuance that would escalate). A redesign-specific
3339
3603
  * subclass of {@link PermissionError} so existing `instanceof PermissionError`
3340
3604
  * branches keep working.
3341
3605
  */
3342
3606
  declare class ForbiddenScopeError extends PermissionError {
3343
3607
  }
3344
3608
  /**
3345
- * 400 `breadth_required` an org-tier key/operator issued a bare list that needs a
3609
+ * 400 `breadth_required` - an org-tier key/operator issued a bare list that needs a
3346
3610
  * breadth pick; the problem `errors`/`detail` name the next call
3347
3611
  * (`/v1/projects/{id}/inboxes` or `/v1/projects/-/inboxes`).
3348
3612
  */
3349
3613
  declare class BreadthRequiredError extends ApiError {
3350
3614
  }
3351
- /** 404 the inbox, message, thread, or webhook does not exist (or isn't visible to this tenant). */
3615
+ /** 404 - the inbox, message, thread, or webhook does not exist (or isn't visible to this tenant). */
3352
3616
  declare class NotFoundError extends ApiError {
3353
3617
  }
3354
- /** 409 a conflicting state, e.g. an enrollment token that already minted its max of N inboxes. */
3618
+ /** 409 - a conflicting state, e.g. an enrollment token that already created its maximum number of inboxes. */
3355
3619
  declare class ConflictError extends ApiError {
3356
3620
  }
3357
- /** 422 the request body failed validation; see `body.error.details`. */
3621
+ /** 422 - the request body failed validation; see `body.error.details`. */
3358
3622
  declare class ValidationError extends ApiError {
3359
3623
  }
3360
3624
  /**
3361
- * 422 `recipient_suppressed` a send/reply/forward was rejected because one or
3625
+ * 422 `recipient_suppressed` - a send/reply/forward was rejected because one or
3362
3626
  * more recipients have opted out (list-unsubscribe / suppression). The whole send
3363
3627
  * is rejected (never a silent partial drop). {@link suppressedRecipients} lists the
3364
3628
  * exact addresses to drop; retry the send without them. The scope/origin of the
@@ -3366,12 +3630,12 @@ declare class ValidationError extends ApiError {
3366
3630
  * existing `instanceof ValidationError` branches keep working.
3367
3631
  */
3368
3632
  declare class RecipientSuppressedError extends ValidationError {
3369
- /** The recipient addresses that are suppressed drop these and retry. */
3633
+ /** The recipient addresses that are suppressed - drop these and retry. */
3370
3634
  readonly suppressedRecipients: string[];
3371
3635
  constructor(args: ConstructorParameters<typeof ApiError>[0]);
3372
3636
  }
3373
3637
  /**
3374
- * 422 `intent_required` the inbox's resolved review policy requires a human to
3638
+ * 422 `intent_required` - the inbox's resolved review policy requires a human to
3375
3639
  * see this message before it goes out, and the request carried no `intent`.
3376
3640
  *
3377
3641
  * **Nothing was sent and nothing was queued.** The server checks this before it
@@ -3380,7 +3644,7 @@ declare class RecipientSuppressedError extends ValidationError {
3380
3644
  * splice in, and the human-readable remediation (the full recipe, including how
3381
3645
  * to monitor the resulting review) is on `.message` / `.problem.detail`.
3382
3646
  *
3383
- * Under `require_review` the default for every account this is the FIRST
3647
+ * Under `require_review` - the default for every account - this is the FIRST
3384
3648
  * thing most agents hit. Read `effective_review_policy` on
3385
3649
  * `GET /v1/inboxes/{id}` once at start-up and compose an intent up front instead
3386
3650
  * of learning the policy by being refused. A subclass of {@link ValidationError}
@@ -3389,7 +3653,7 @@ declare class RecipientSuppressedError extends ValidationError {
3389
3653
  declare class IntentRequiredError extends ValidationError {
3390
3654
  /** The resolved review policy, e.g. `require_review`. */
3391
3655
  readonly policy: string | undefined;
3392
- /** Where the policy came from a per-inbox override or the account default. */
3656
+ /** Where the policy came from - a per-inbox override or the account default. */
3393
3657
  readonly policySource: string | undefined;
3394
3658
  /** Literal JSON to merge into the original request body, then retry once. */
3395
3659
  readonly retryWith: string | undefined;
@@ -3407,7 +3671,7 @@ declare class IntentRequiredError extends ValidationError {
3407
3671
  declare class ReviewConflictError extends ConflictError {
3408
3672
  /** The review's CURRENT state (`needs_review`, `approved`, `sent`, …). */
3409
3673
  readonly currentState: string | undefined;
3410
- /** The current revision pass it as `parent_revision` on a legal retry. */
3674
+ /** The current revision - pass it as `parent_revision` on a legal retry. */
3411
3675
  readonly currentRevision: number | undefined;
3412
3676
  /** The current row version (the optional belt-and-braces CAS). */
3413
3677
  readonly currentVersion: number | undefined;
@@ -3416,13 +3680,13 @@ declare class ReviewConflictError extends ConflictError {
3416
3680
  constructor(args: ConstructorParameters<typeof ApiError>[0]);
3417
3681
  /**
3418
3682
  * Whether retrying the same call could ever succeed. False for every subclass
3419
- * except {@link StaleError} and {@link BornStaleError} and true there only
3683
+ * except {@link StaleError} and {@link BornStaleError} - and true there only
3420
3684
  * after re-reading and re-applying on top of the other party's change.
3421
3685
  */
3422
3686
  get isRetryable(): boolean;
3423
3687
  }
3424
3688
  /**
3425
- * 409 `stale` the `(revision[, version])` you named is no longer current
3689
+ * 409 `stale` - the `(revision[, version])` you named is no longer current
3426
3690
  * because a human or reviewer moved the draft. **Nothing was mutated.**
3427
3691
  *
3428
3692
  * The one genuinely retryable conflict, and bounded (≤3): re-read the draft and
@@ -3435,7 +3699,7 @@ declare class StaleError extends ReviewConflictError {
3435
3699
  get isRetryable(): boolean;
3436
3700
  }
3437
3701
  /**
3438
- * 409 `wrong_state` this VERB is illegal from the review's current state, but
3702
+ * 409 `wrong_state` - this VERB is illegal from the review's current state, but
3439
3703
  * the draft is still live.
3440
3704
  *
3441
3705
  * **Never retry the same verb**; the timing is not the problem, the choice of
@@ -3444,7 +3708,7 @@ declare class StaleError extends ReviewConflictError {
3444
3708
  declare class WrongStateError extends ReviewConflictError {
3445
3709
  }
3446
3710
  /**
3447
- * 409 `terminal` the review has already finished (sent / auto_sent /
3711
+ * 409 `terminal` - the review has already finished (sent / auto_sent /
3448
3712
  * cancelled). Nothing will EVER succeed on it.
3449
3713
  *
3450
3714
  * **Stop.** A `front_run_next` review event is waiting on the durable queue with
@@ -3458,12 +3722,12 @@ declare class TerminalError extends ReviewConflictError {
3458
3722
  constructor(args: ConstructorParameters<typeof ApiError>[0]);
3459
3723
  }
3460
3724
  /**
3461
- * 409 `born_stale` the redraft was composed against an OLDER writing-rule
3725
+ * 409 `born_stale` - the redraft was composed against an OLDER writing-rule
3462
3726
  * high-water than the one now in force. **Nothing was mutated** and the composer
3463
3727
  * has been re-nudged.
3464
3728
  *
3465
3729
  * Retryable at most once per rule high-water: re-read the rules, re-apply them,
3466
- * resubmit or `restamp_review` when re-reading shows nothing genuinely needed
3730
+ * resubmit - or `restamp_review` when re-reading shows nothing genuinely needed
3467
3731
  * to change. Restamping when the body DID need to change makes the draft lie to
3468
3732
  * the born-stale accounting, so do it only for a true no-op.
3469
3733
  */
@@ -3471,7 +3735,7 @@ declare class BornStaleError extends ReviewConflictError {
3471
3735
  get isRetryable(): boolean;
3472
3736
  }
3473
3737
  /**
3474
- * 409 `send_needs_reconciliation` a delivery attempt reached (or may have
3738
+ * 409 `send_needs_reconciliation` - a delivery attempt reached (or may have
3475
3739
  * reached) the mail provider and the process died before recording the outcome,
3476
3740
  * so the review is parked for recover-by-Message-ID.
3477
3741
  *
@@ -3482,17 +3746,17 @@ declare class BornStaleError extends ReviewConflictError {
3482
3746
  declare class SendNeedsReconciliationError extends ReviewConflictError {
3483
3747
  }
3484
3748
  /**
3485
- * 409 `idempotency_conflict` the same `Idempotency-Key` was replayed with a
3749
+ * 409 `idempotency_conflict` - the same `Idempotency-Key` was replayed with a
3486
3750
  * DIFFERENT request body within the same scope. The replay key is a hash of the
3487
3751
  * raw bytes, so "same message, different spelling" counts as different.
3488
3752
  *
3489
3753
  * A caller bug, not a race: do not retry under that key. Either send the byte-
3490
- * identical body, or mint a new key for the genuinely new message.
3754
+ * identical body, or use a new key for the genuinely new message.
3491
3755
  */
3492
3756
  declare class IdempotencyConflictError extends ConflictError {
3493
3757
  }
3494
3758
  /**
3495
- * 503 `unavailable` a dependency could not be read, so the request was failed
3759
+ * 503 `unavailable` - a dependency could not be read, so the request was failed
3496
3760
  * CLOSED rather than served on a guess. On the send path this specifically means
3497
3761
  * the account's review policy was unreadable: relaying unsupervised mail for a
3498
3762
  * customer whose stated policy we could not see is the failure that would be
@@ -3508,7 +3772,7 @@ declare class UnavailableError extends ApiError {
3508
3772
  retryAfter?: number;
3509
3773
  });
3510
3774
  }
3511
- /** 402 payment required (x402 test-mode). `paymentRequired` holds the raw challenge header. */
3775
+ /** 402 - payment required (x402 test-mode). `paymentRequired` holds the raw challenge header. */
3512
3776
  declare class PaymentRequiredError extends ApiError {
3513
3777
  /** The raw `PAYMENT-REQUIRED` header challenge to sign + retry (EIP-3009, Base Sepolia). */
3514
3778
  readonly paymentRequired: string | undefined;
@@ -3516,7 +3780,7 @@ declare class PaymentRequiredError extends ApiError {
3516
3780
  paymentRequired?: string;
3517
3781
  });
3518
3782
  }
3519
- /** 429 rate limited. `retryAfter` is the server's hint in seconds, when provided. */
3783
+ /** 429 - rate limited. `retryAfter` is the server's hint in seconds, when provided. */
3520
3784
  declare class RateLimitError extends ApiError {
3521
3785
  /** Seconds to wait before retrying, parsed from the `Retry-After` header. */
3522
3786
  readonly retryAfter: number | undefined;
@@ -3534,7 +3798,7 @@ declare class TimeoutError extends ApiError {
3534
3798
  }
3535
3799
 
3536
3800
  /**
3537
- * Narrowing helpers for {@link SendOutcome} the three shapes a send can answer.
3801
+ * Narrowing helpers for {@link SendOutcome} - the three shapes a send can answer.
3538
3802
  *
3539
3803
  * `inbox.send()` used to be typed as one struct with a REQUIRED `thread_id`, which
3540
3804
  * the direct-send response has never carried. The type checked; the value was
@@ -3545,7 +3809,7 @@ declare class TimeoutError extends ApiError {
3545
3809
  * has been delivered**. A human has to approve it first, and the delivery outcome
3546
3810
  * arrives later as a `sent` / `send_failed` review event. Code that treats every
3547
3811
  * 2xx from `send()` as "the mail went out" is wrong under the default
3548
- * `require_review` policy which is every account that has not changed it.
3812
+ * `require_review` policy - which is every account that has not changed it.
3549
3813
  */
3550
3814
 
3551
3815
  /**
@@ -3555,14 +3819,14 @@ declare class TimeoutError extends ApiError {
3555
3819
  */
3556
3820
  declare function isQueuedForReview(res: SendOutcome): res is QueuedForReviewResult;
3557
3821
  /**
3558
- * True when the message was delivered immediately either the review-loop
3822
+ * True when the message was delivered immediately - either the review-loop
3559
3823
  * `{kind:"sent"}` body or the legacy body a bare send gets under `allow_direct`.
3560
3824
  */
3561
3825
  declare function isSentImmediately(res: SendOutcome): res is SendResult | SentResult;
3562
3826
  /**
3563
3827
  * The delivered message id, or `undefined` when the message was queued instead.
3564
3828
  *
3565
- * `undefined` here is NOT an error it is the normal answer under
3829
+ * `undefined` here is NOT an error - it is the normal answer under
3566
3830
  * `require_review`. Pair it with {@link reviewIdOf} to follow the message to its
3567
3831
  * outcome.
3568
3832
  */
@@ -3670,7 +3934,7 @@ declare function verifyWebhookSignature(options: VerifyWebhookOptions): Promise<
3670
3934
  */
3671
3935
  declare function parseWebhook(options: VerifyWebhookOptions): Promise<WebhookPayload | null>;
3672
3936
  /**
3673
- * Produce the canonical `X-Extrovert-Signature` header value for a body the exact format the Go
3937
+ * Produce the canonical `X-Extrovert-Signature` header value for a body - the exact format the Go
3674
3938
  * delivery engine emits: `t=<unix>,v1=<hex hmac-sha256("<t>.<rawbody>")>`. Mainly useful for tests
3675
3939
  * and self-hosted senders; the platform signs deliveries server-side. The Go `SignWebhook` and this
3676
3940
  * helper are pinned to the same fixed conformance vector across languages.
@@ -3681,7 +3945,7 @@ declare function signWebhook(secret: string, body: string, timestampSeconds: num
3681
3945
  * The Extrovert Review-Loop **open contract** (HITL D14, spec §11).
3682
3946
  *
3683
3947
  * This module is the single, documented, *versioned* publication of the stable
3684
- * agent-facing JSON shapes that the Review Loop exposes the shapes agents and
3948
+ * agent-facing JSON shapes that the Review Loop exposes - the shapes agents and
3685
3949
  * third-party harnesses code against. It does **not** redesign any types: it
3686
3950
  * re-exports the canonical models built across M1–M8 (see `./models`) under one
3687
3951
  * named contract surface, stamps a {@link CONTRACT_VERSION}, and publishes a
@@ -3691,7 +3955,7 @@ declare function signWebhook(secret: string, body: string, timestampSeconds: num
3691
3955
  * ## This is a contract, NOT a protocol (D14)
3692
3956
  *
3693
3957
  * Per resolved decision **D14**, the open surface is published **now** as an open,
3694
- * documented **skill + SDK contract** explicitly **not** a wire protocol and
3958
+ * documented **skill + SDK contract** - explicitly **not** a wire protocol and
3695
3959
  * **not** a standalone `/v1/contract` endpoint. The contract is exactly: these SDK
3696
3960
  * types + the agent skills (`extrovert-send-email`, `extrovert-writing-rules`) + the
3697
3961
  * docs, **versioned with the SDK** (this package). Formal protocol
@@ -3699,7 +3963,7 @@ declare function signWebhook(secret: string, body: string, timestampSeconds: num
3699
3963
  *
3700
3964
  * ## Provisional, pre-1.0 (0.x)
3701
3965
  *
3702
- * {@link CONTRACT_VERSION} is **`0.1.0-pre.5`** a deliberately **provisional**, pre-1.0
3966
+ * {@link CONTRACT_VERSION} is **`0.1.0-pre.7`** - a deliberately **provisional**, pre-1.0
3703
3967
  * contract. It is open and documented, but it MAY still evolve before 1.0: there
3704
3968
  * are no external users yet, and the **D20 shared-pool auto-send governor** is a
3705
3969
  * hard prerequisite before onboarding external users. Pin the version; expect
@@ -3709,11 +3973,11 @@ declare function signWebhook(secret: string, body: string, timestampSeconds: num
3709
3973
  *
3710
3974
  * Every shape keys on **opaque, typed ids** (`rr_`, `turn_`, `cat_`, `rule_`,
3711
3975
  * `rln_`, `ndg_`, …) and never on names. Names/descriptions are mutable display
3712
- * metadata; renaming never breaks a reference. $0-LLM on our side the contract
3976
+ * metadata; renaming never breaks a reference. $0-LLM on our side - the contract
3713
3977
  * is pure deterministic JSON; all judgment lives in the agent skills.
3714
3978
  *
3715
3979
  * The canonical example payloads for the §11 core shapes (Intent, ReviewFeedback,
3716
- * DiffJson, Rule, Nudge) are the conformance golden fixtures see
3980
+ * DiffJson, Rule, Nudge) are the conformance golden fixtures - see
3717
3981
  * `golang/internal/extrovertapi/testdata/contract/` and the SDK
3718
3982
  * `contract.test.ts` (both assert these examples parse/validate without loss).
3719
3983
  *
@@ -3756,24 +4020,24 @@ interface DiffJson {
3756
4020
  /**
3757
4021
  * The published version of the Extrovert Review-Loop open contract (D14).
3758
4022
  *
3759
- * **`0.1.0-pre.5` PROVISIONAL, pre-1.0.** Versioned *with the SDK* (this package's
4023
+ * **`0.1.0-pre.7` - PROVISIONAL, pre-1.0.** Versioned *with the SDK* (this package's
3760
4024
  * `package.json` version) and aligned to the openapi `info.version`. Open and
3761
4025
  * documented, but MAY still evolve before 1.0 (no external users yet; the D20
3762
4026
  * shared-pool governor is required before external users). Pin it.
3763
4027
  */
3764
- declare const CONTRACT_VERSION: "0.1.0-pre.5";
4028
+ declare const CONTRACT_VERSION: "0.1.0-pre.7";
3765
4029
  /** The stability posture of a published contract version. */
3766
4030
  type ContractStability = "provisional" | "stable";
3767
4031
  /**
3768
- * The machine-readable manifest of the open contract (D14) what a harness pins.
4032
+ * The machine-readable manifest of the open contract (D14) - what a harness pins.
3769
4033
  *
3770
4034
  * It enumerates the canonical §11 **core** shapes and the **full** M1–M8 surface
3771
4035
  * by name, stamps {@link CONTRACT_VERSION}, and marks the {@link ContractStability}
3772
4036
  * posture so a consumer can reason about evolution risk. It carries no runtime
3773
- * behavior (M9 adds none types + a version + a test + docs) and no LLM.
4037
+ * behavior (M9 adds none - types + a version + a test + docs) and no LLM.
3774
4038
  */
3775
4039
  interface ContractManifest {
3776
- /** Stable contract name (NOT a protocol name D14). */
4040
+ /** Stable contract name (NOT a protocol name - D14). */
3777
4041
  readonly name: "extrovert.review-loop";
3778
4042
  /** The published contract version (== {@link CONTRACT_VERSION}). */
3779
4043
  readonly version: string;
@@ -3783,7 +4047,7 @@ interface ContractManifest {
3783
4047
  */
3784
4048
  readonly stability: ContractStability;
3785
4049
  /**
3786
- * D14: this is an SDK + skill contract, versioned WITH the SDK never a wire
4050
+ * D14: this is an SDK + skill contract, versioned WITH the SDK - never a wire
3787
4051
  * protocol or a standalone protocol endpoint.
3788
4052
  */
3789
4053
  readonly kind: "sdk+skill-contract";
@@ -3793,15 +4057,15 @@ interface ContractManifest {
3793
4057
  readonly core_shapes: readonly string[];
3794
4058
  /** The full published M1–M8 agent-facing contract surface (one 0.x contract; no tiering). */
3795
4059
  readonly shapes: readonly string[];
3796
- /** The agent skills that are part of the contract (D14 "skill + SDK"). */
4060
+ /** The agent skills that are part of the contract (D14 - "skill + SDK"). */
3797
4061
  readonly skills: readonly string[];
3798
4062
  }
3799
4063
  /**
3800
4064
  * The published manifest instance. Frozen so a harness can compare it
3801
4065
  * structurally. The `core_shapes` are the five §11 canonical shapes; `shapes` is
3802
4066
  * the full provisional-0.x surface. Keep this list in sync with the re-exports
3803
- * above the `contract.test.ts` drift test asserts every named shape resolves.
4067
+ * above - the `contract.test.ts` drift test asserts every named shape resolves.
3804
4068
  */
3805
4069
  declare const CONTRACT_MANIFEST: ContractManifest;
3806
4070
 
3807
- export { API_VERSION_HEADER, type AccountRiskDial, type AckReviewEventEntry, type AckReviewEventRequest, type AckReviewEventResult, type AddContactListRequest, type Agent, type AgentStatus, ApiError, type ApiErrorBody, type Attachment, type AttachmentDownload, type AttachmentInput, AuthenticationError, type BatchUpdateMessagesRequest, type BatchUpdateResult, BornStaleError, BreadthRequiredError, CONTRACT_MANIFEST, CONTRACT_VERSION, CURRENT_API_VERSION, Categories, type Category, type CategoryPacingState, type CategoryRiskDial, ConflictError, ConnectionError, type ContactListDirection, type ContactListEntry, type ContactListKind, ContactLists, type ContractManifest, type ContractStability, type CreateInboxRequest, type Cursor, DEFAULT_BASE_URL, type DeleteResult, type DiffHunk, type DiffJson, type Domain, type DomainOffboard, type DomainRecord, type DomainScope, Domains, type EffectiveRiskDial, type EmailAddress, type EnrollRequest, type EnrollResponse, type ExtractedCredentials, ExtrovertClient as Extrovert, ExtrovertClient, type ExtrovertClientOptions, ForbiddenScopeError, type ForwardRequest, type GetInboxParams, type GetRuleAuditParams, type GetRulesParams, type GraduationStatus, IdempotencyConflictError, type Inbox, type InboxCredentials, InboxHandle, type InboxInclude, type InboxMetadata, type InboxMetadataPatch, type InboxMetadataValue, type InboxStatus, Inboxes, IntentRequiredError, type IsoTimestamp, type Job, type KeyTier, type List, type ListCategoriesParams, type ListInboxesParams, type ListMessagesParams, ListPage, type ListParams, type ListReviewEventsParams, type ListReviewsParams, type ListSuppressionsParams, type ListThreadsParams, MOCK_BASE_URL, type MailFolder, type MailboxQuickstart, type MailboxQuickstartCall, type MarkReadRequest, type Message, type MessageDirection, Messages, MockBackend, NotFoundError, type OnboardDomainRequest, type OnboardingMode, PROBLEM_CODES, type PacingItem, type Page, type PageFetcher, PaymentRequiredError, PermissionError, type PostReviewChatRequest, type Problem, type ProblemCode, type ProblemField, type ProjectInboxListParams, ProjectInboxes, Projects, type ProposeCategoryRequest, type ProposeGraduationRequest, type QueuedForReviewResult, REVIEW_PROBLEM_RETRYABLE, RateLimitError, RecipientSuppressedError, type RegisterWebhookRequest, type ReplyRequest, type RestampReviewRequest, type Review, ReviewConflictError, type ReviewDecisionContext, type ReviewEvent, type ReviewEventCursor, type ReviewEventReason, ReviewEvents, type ReviewEventsResult, type ReviewFeedback, type ReviewFeedbackComment, type ReviewInclude, type ReviewIntent, type ReviewMode, type ReviewPolicy, type ReviewState, type ReviewTurn, type ReviewerAction, type ReviewerDecisionRequest, type ReviewerDecisionResult, Reviews, type RiskDial, type Rule, type RuleAuditEntry, type RuleLayer, Rules, SDK_VERSION, type SaveRuleRequest, type ScanBacklogStatus, type Scope, type SearchMessagesParams, SendNeedsReconciliationError, type SendOutcome, type SendRequest, type SendResult, type SentResult, type SignUpRequest, type SignUpResponse, StaleError, type StreamEvent, type StreamOptions, type SubmitForReviewResult, type SubmitRevisionRequest, type SuppressionEntry, type SuppressionPrecheck, type SuppressionScope, type SuppressionSource, Suppressions, TerminalError, type Thread, type ThreadDetail, Threads, TimeoutError, UnavailableError, type UpdateCategoryRequest, type UpdateInboxRequest, type UpdateWebhookRequest, ValidationError, type VerifyRequest, type VerifyResponse, type VerifyWebhookOptions, type WaitForEmailRequest, type WaitForEmailResult, type WaitForReviewEventParams, type Webhook, type WebhookEvent, type WebhookPayload, Webhooks, type WhoAmI, WrongStateError, extractCredentials, extractLink, extractOtp, isProblemCode, isQueuedForReview, isSentImmediately, listPage, parseKeyTier, parseProblem, parseWebhook, reviewIdOf, sentMessageIdOf, serializeInclude, signWebhook, threadIdOf, tierAllowsOrgWildcard, tierNeedsExplicitBreadth, verifyWebhookSignature };
4071
+ export { API_VERSION_HEADER, type AccountRiskDial, type AckReviewEventEntry, type AckReviewEventRequest, type AckReviewEventResult, type AddContactListRequest, type Agent, type AgentStatus, ApiError, type ApiErrorBody, type Attachment, type AttachmentDownload, type AttachmentInput, AuthenticationError, type BatchUpdateMessagesRequest, type BatchUpdateResult, BornStaleError, BreadthRequiredError, CONTRACT_MANIFEST, CONTRACT_VERSION, CURRENT_API_VERSION, Categories, type Category, type CategoryPacingState, type CategoryRiskDial, Commerce, type CommerceBlocker, type CommerceRequest, type CommerceRequestKind, ConflictError, ConnectionError, type ContactListDirection, type ContactListEntry, type ContactListKind, ContactLists, type ContractManifest, type ContractStability, type CreateInboxRequest, type Cursor, DEFAULT_BASE_URL, type DeleteResult, type DiffHunk, type DiffJson, type Domain, type DomainOffboard, type DomainQuote, type DomainReadiness, type DomainRecord, type DomainScope, type DomainStatusEvent, type DomainStatusEventPage, type DomainWaitResult, Domains, type EffectiveRiskDial, type EmailAddress, type EnrollRequest, type EnrollResponse, type ExtractedCredentials, ExtrovertClient as Extrovert, ExtrovertClient, type ExtrovertClientOptions, ForbiddenScopeError, type ForwardRequest, type GetInboxParams, type GetRuleAuditParams, type GetRulesParams, type GraduationStatus, IdempotencyConflictError, type Inbox, type InboxCredentials, InboxHandle, type InboxInclude, type InboxMetadata, type InboxMetadataPatch, type InboxMetadataValue, type InboxStatus, Inboxes, IntentRequiredError, type IsoTimestamp, type Job, type KeyTier, type List, type ListCategoriesParams, type ListCommerceRequestsParams, type ListInboxesParams, type ListMessagesParams, ListPage, type ListParams, type ListReviewEventsParams, type ListReviewsParams, type ListSuppressionsParams, type ListThreadsParams, MOCK_BASE_URL, type MailFolder, type MailboxQuickstart, type MailboxQuickstartCall, type MarkReadRequest, type Message, type MessageDirection, Messages, MockBackend, NotFoundError, type OnboardDomainRequest, type OnboardingMode, PROBLEM_CODES, type PacingItem, type Page, type PageFetcher, PaymentRequiredError, PermissionError, type PostReviewChatRequest, type Problem, type ProblemCode, type ProblemField, type ProjectInboxListParams, ProjectInboxes, Projects, type ProposeCategoryRequest, type ProposeGraduationRequest, type QueuedForReviewResult, type QuoteDomainRequest, REVIEW_PROBLEM_RETRYABLE, RateLimitError, RecipientSuppressedError, type RegisterWebhookRequest, type ReplyRequest, type RequestDomainPurchaseRequest, type RequestPlanChangeRequest, type RestampReviewRequest, type Review, ReviewConflictError, type ReviewDecisionContext, type ReviewEvent, type ReviewEventCursor, type ReviewEventReason, ReviewEvents, type ReviewEventsResult, type ReviewFeedback, type ReviewFeedbackComment, type ReviewInclude, type ReviewIntent, type ReviewMode, type ReviewPolicy, type ReviewState, type ReviewTurn, type ReviewerAction, type ReviewerDecisionRequest, type ReviewerDecisionResult, Reviews, type RiskDial, type Rule, type RuleAuditEntry, type RuleLayer, type RuleSnapshot, Rules, SDK_VERSION, type SaveRuleRequest, type ScanBacklogStatus, type Scope, type SearchMessagesParams, SendNeedsReconciliationError, type SendOutcome, type SendRequest, type SendResult, type SentResult, type SignUpRequest, type SignUpResponse, StaleError, type StreamEvent, type StreamOptions, type SubmitForReviewResult, type SubmitRevisionRequest, type SuppressionEntry, type SuppressionPrecheck, type SuppressionScope, type SuppressionSource, Suppressions, TerminalError, type Thread, type ThreadDetail, Threads, TimeoutError, UnavailableError, type UpdateCategoryRequest, type UpdateInboxRequest, type UpdateWebhookRequest, ValidationError, type VerifyRequest, type VerifyResponse, type VerifyWebhookOptions, type WaitForEmailRequest, type WaitForEmailResult, type WaitForReviewEventParams, type Webhook, type WebhookEvent, type WebhookPayload, Webhooks, type WhoAmI, WrongStateError, extractCredentials, extractLink, extractOtp, isProblemCode, isQueuedForReview, isSentImmediately, listPage, parseKeyTier, parseProblem, parseWebhook, reviewIdOf, sentMessageIdOf, serializeInclude, signWebhook, threadIdOf, tierAllowsOrgWildcard, tierNeedsExplicitBreadth, verifyWebhookSignature };