@extrovert.dev/sdk 0.1.0-pre.6 → 0.1.0-pre.8

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.6";
9
+ declare const SDK_VERSION = "0.1.0-pre.8";
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:credentials" | "mailbox:delete" | "webhook:write" | "domain:manage" | "domain:purchase" | "review:act" | "signup:verify";
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
@@ -527,7 +545,7 @@ interface SendRequest {
527
545
  * Request body for the canonical thread-aware reply,
528
546
  * `POST /v1/inboxes/{addr}/reply`. Exactly one of `thread_id` / `message_id`
529
547
  * selects the parent; the server derives `to` (original participants), the
530
- * `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
531
549
  * NOT pass `to`. Set `reply_all` to reply to every thread recipient.
532
550
  */
533
551
  interface ReplyRequest {
@@ -535,6 +553,12 @@ interface ReplyRequest {
535
553
  thread_id?: string;
536
554
  /** Reply to this specific message. One of thread_id / message_id. */
537
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;
538
562
  /** At least one of `text` / `html` is required. */
539
563
  text?: string;
540
564
  html?: string;
@@ -544,7 +568,7 @@ interface ReplyRequest {
544
568
  reply_to?: string;
545
569
  /** Reply to all thread recipients, not just the original sender. */
546
570
  reply_all?: boolean;
547
- /** 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. */
548
572
  idempotency_key?: string;
549
573
  headers?: Record<string, string>;
550
574
  /** Files to attach (base64). Emitted as a multipart/mixed message. */
@@ -566,7 +590,7 @@ interface ReplyRequest {
566
590
  * A forward is governed by the SAME review policy as a send, and for a stronger
567
591
  * reason: it is an outbound message to arbitrary NEW recipients that quotes an
568
592
  * entire inbound thread. Leaving it outside the policy would have made forward
569
- * 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
570
594
  * exfiltrates a received conversation.
571
595
  */
572
596
  interface ForwardRequest {
@@ -593,7 +617,7 @@ interface ForwardRequest {
593
617
  /** Agent-supplied confidence (0..1); see {@link SendRequest.category_confidence}. */
594
618
  category_confidence?: number;
595
619
  composition_token?: string;
596
- /** See {@link SendRequest.idempotency_key} sent as a header, never in the body. */
620
+ /** See {@link SendRequest.idempotency_key}: sent as a header, never in the body. */
597
621
  idempotency_key?: string;
598
622
  }
599
623
  /**
@@ -603,8 +627,8 @@ interface ForwardRequest {
603
627
  * Its shape differs per verb, which is why almost every field is optional and
604
628
  * this type is NOT the whole story (see {@link SendOutcome}):
605
629
  *
606
- * - `send` → `{status:"sent", message_id, review_id}` **no `thread_id`**.
607
- * - `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`.
608
632
  *
609
633
  * `thread_id` was declared REQUIRED here for a long time while the send path
610
634
  * never returned one, so `res.thread_id` typechecked and was `undefined` at
@@ -619,7 +643,7 @@ interface SendResult {
619
643
  kind?: undefined;
620
644
  /** Extrovert message id of the sent outbound message. */
621
645
  message_id: string;
622
- /** 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. */
623
647
  thread_id?: string;
624
648
  /**
625
649
  * Opaque review id (rr_…) of the review row that governed this send. Every
@@ -637,16 +661,16 @@ interface SendResult {
637
661
  * Every shape `inbox.send()` / `.reply()` / `.forward()` / `.submitForReview()`
638
662
  * can return, discriminated by `kind`.
639
663
  *
640
- * 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
641
665
  * what happens to an outbound message:
642
666
  *
643
- * - {@link QueuedForReviewResult} (`kind:"queued_for_review"`, 202) parked for
667
+ * - {@link QueuedForReviewResult} (`kind:"queued_for_review"`, 202): parked for
644
668
  * a human. **Nothing has been delivered yet.** Monitor
645
669
  * `reviewEvents.wait({review_id})` until a `sent` or `send_failed` event
646
670
  * arrives.
647
- * - {@link SentResult} (`kind:"sent"`, 200) delivered immediately, returned to
671
+ * - {@link SentResult} (`kind:"sent"`, 200): delivered immediately, returned to
648
672
  * callers that opted into the review loop by passing mode/intent/category_id.
649
- * - {@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
650
674
  * caller that mentioned none of those fields.
651
675
  *
652
676
  * Under the default `require_review` policy a send WITHOUT an `intent` does not
@@ -658,15 +682,15 @@ type SendOutcome = SendResult | SentResult | QueuedForReviewResult;
658
682
  /** Per-send agent assertion (D3/D6). The resolved policy may downgrade `direct`. */
659
683
  type ReviewMode = "review" | "direct";
660
684
  /**
661
- * 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
662
686
  * message. There is no way for a caller to opt out of it.
663
687
  *
664
- * - `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`
665
689
  * is rejected 422 `intent_required` (nothing sent, nothing queued); a send
666
690
  * WITH one is queued for a human (202 `queued_for_review`).
667
- * - `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
668
692
  * immediately. Supplying an intent, or `mode: "review"`, still queues it.
669
- * - `auto_send_graduated` a categorized message that clears the graduation
693
+ * - `auto_send_graduated`: a categorized message that clears the graduation
670
694
  * gates auto-sends; everything else is queued.
671
695
  *
672
696
  * Read {@link Inbox.effective_review_policy} once before your first send rather
@@ -685,7 +709,7 @@ interface ReviewIntent {
685
709
  urgency?: string;
686
710
  };
687
711
  }
688
- /** 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. */
689
713
  interface Review {
690
714
  id: string;
691
715
  state: ReviewState;
@@ -718,8 +742,8 @@ interface Review {
718
742
  * `failed`**.
719
743
  *
720
744
  * `failed` is included deliberately even though it is not in the formal
721
- * terminal set: nothing in the product can move a failed review the console
722
- * 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
723
747
  * agent to wait forever on a row nobody will ever touch.
724
748
  *
725
749
  * An agent that lost its event cursor (a crash, a fresh process) reads this
@@ -733,7 +757,7 @@ interface Review {
733
757
  send_error?: string;
734
758
  /**
735
759
  * How the message was released, once sent: `human_reviewed`,
736
- * `reviewer_approved`, `graduated_auto` or `agent_direct` without a turns
760
+ * `reviewer_approved`, `graduated_auto` or `agent_direct`: without a turns
737
761
  * fetch.
738
762
  */
739
763
  send_path?: string;
@@ -757,6 +781,7 @@ interface ReviewTurn {
757
781
  }
758
782
  /** Filters for listing review requests (spec §5.2). */
759
783
  interface ListReviewsParams {
784
+ composer?: "me";
760
785
  state?: ReviewState | ReviewState[];
761
786
  category_id?: string;
762
787
  inbox?: string;
@@ -775,7 +800,7 @@ interface ReviewFeedbackComment {
775
800
  * The human's assembled feedback for a review (spec §11), returned by
776
801
  * `reviews.feedback(id)`: the unified + structured diff of the human edit, the human
777
802
  * comments / rejection feedback, the decision, and the rules born from this review
778
- * (rule_ ids whose source_review_id is this review). $0 LLM pure assembly.
803
+ * (rule_ ids whose source_review_id is this review). $0 LLM: pure assembly.
779
804
  */
780
805
  interface ReviewFeedback {
781
806
  review_id: string;
@@ -792,7 +817,7 @@ interface PostReviewChatRequest {
792
817
  }
793
818
  /**
794
819
  * Body for posting a new agent draft under a parent_revision CAS (spec §5.2; M5,
795
- * D17). parent_revision is the PRIMARY CAS it must equal the draft's current
820
+ * D17). parent_revision is the PRIMARY CAS: it must equal the draft's current
796
821
  * revision, else 409 STALE with NO mutation. version is OPTIONAL belt-and-suspenders.
797
822
  */
798
823
  interface SubmitRevisionRequest {
@@ -801,7 +826,7 @@ interface SubmitRevisionRequest {
801
826
  subject?: string;
802
827
  /**
803
828
  * The redrafted plain-text body. Canonical, matching `text` on send / reply /
804
- * forward the same concept should not have two names in the one flow an
829
+ * forward: the same concept should not have two names in the one flow an
805
830
  * agent runs most.
806
831
  */
807
832
  text?: string;
@@ -854,7 +879,7 @@ type ReviewEventReason =
854
879
  * cancel, so compose and submit a NEW message rather than retrying this one.
855
880
  */
856
881
  | "send_failed"
857
- /** Withdrawn by you, by a human, or as the close-out of a failed send. */
882
+ /** Withdrawn: by you, by a human, or as the close-out of a failed send. */
858
883
  | "cancelled"
859
884
  /**
860
885
  * You were front-run: the review reached a terminal state while you were
@@ -862,9 +887,9 @@ type ReviewEventReason =
862
887
  * `cancel_review` answered 409 `terminal`. STOP retrying that review.
863
888
  */
864
889
  | "front_run_next"
865
- /** RESERVED never emitted. Terminal success is `sent`. */
890
+ /** RESERVED: never emitted. Terminal success is `sent`. */
866
891
  | "approved"
867
- /** RESERVED no production producer (the D13 staleness detector is unbuilt). */
892
+ /** RESERVED: no production producer (the D13 staleness detector is unbuilt). */
868
893
  | "staleness";
869
894
  /**
870
895
  * One durable review nudge (ndg_…) drained from the AUTHORITATIVE liveness queue
@@ -880,13 +905,14 @@ interface ReviewEvent {
880
905
  payload?: Record<string, unknown>;
881
906
  created_at: IsoTimestamp;
882
907
  }
883
- /** The agent's per-(agent, review) ack frontier its strict-FIFO position. */
908
+ /** The agent's per-(agent, review) ack frontier: its strict-FIFO position. */
884
909
  interface ReviewEventCursor {
885
910
  review_id: string;
886
911
  last_acked_seq: number;
887
912
  }
888
- /** Drain result for list/wait un-acked events in FIFO seq order + cursors. */
913
+ /** Drain result for list/wait: un-acked events in FIFO seq order + cursors. */
889
914
  interface ReviewEventsResult {
915
+ pending_reviews?: number;
890
916
  events: ReviewEvent[];
891
917
  cursors?: ReviewEventCursor[];
892
918
  }
@@ -901,7 +927,7 @@ interface ListReviewEventsParams {
901
927
  * A category (cat_…) in the Review Loop registry (D9/D10). `name` + `description`
902
928
  * are skill-style metadata the agent fuzzy-matches against; nothing keys on the
903
929
  * name (renames never break a reference). Categories are CUSTOMER-scoped and
904
- * agent-attributed the deliberate cross-agent-404 exception. Opaque ids only.
930
+ * agent-attributed: the deliberate cross-agent-404 exception. Opaque ids only.
905
931
  */
906
932
  interface Category {
907
933
  id: string;
@@ -930,13 +956,13 @@ interface ProposeCategoryRequest {
930
956
  /** Defaults to org_shared server-side. */
931
957
  scope?: "org_shared" | "agent_private";
932
958
  }
933
- /** Rename / re-describe a category metadata only (spec §5.5; D10). */
959
+ /** Rename / re-describe a category: metadata only (spec §5.5; D10). */
934
960
  interface UpdateCategoryRequest {
935
961
  name?: string;
936
962
  description?: string;
937
963
  }
938
964
  /**
939
- * The account-wide default risk dial (Review Loop, D4/D12) the values a per-
965
+ * The account-wide default risk dial (Review Loop, D4/D12): the values a per-
940
966
  * category null override inherits. The single user-configurable brand-risk lever.
941
967
  */
942
968
  interface AccountRiskDial {
@@ -974,7 +1000,7 @@ interface CategoryRiskDial {
974
1000
  }
975
1001
  /**
976
1002
  * The effective risk dial (Review Loop, agent plane; D4/D12): the account default
977
- * plus every category's overrides. Read-only for agents flipping the dial is a
1003
+ * plus every category's overrides. Read-only for agents: flipping the dial is a
978
1004
  * console (human) action (D16).
979
1005
  */
980
1006
  interface RiskDial {
@@ -1027,7 +1053,7 @@ type ReviewerAction = "approve" | "edit" | "reject" | "escalate";
1027
1053
  * The REVIEWER's read-only decision surface for a review (BYO review-agent plane;
1028
1054
  * D5/§9), returned by `reviews.decisionContext(id)`: the intent + current draft + the
1029
1055
  * append-only thread + the two-circuit-breaker budget. `force_to_human` is true when
1030
- * EITHER breaker has tripped the reviewer's next reject would be FORCED to the human
1056
+ * EITHER breaker has tripped: the reviewer's next reject would be FORCED to the human
1031
1057
  * regardless of intent (the human is the only terminal authority, D17).
1032
1058
  */
1033
1059
  interface ReviewDecisionContext {
@@ -1051,7 +1077,7 @@ interface ReviewDecisionContext {
1051
1077
  /**
1052
1078
  * Body for a reviewer decision (`reviews.decide(id, req)`; reviewer_decide, D5/§9).
1053
1079
  * `action` is approve|edit|reject|escalate. `revision`/`version` are the optimistic CAS
1054
- * a mismatch is a 409 STALE with NO mutation (the human always wins, D17). subject/
1080
+ *: a mismatch is a 409 STALE with NO mutation (the human always wins, D17). subject/
1055
1081
  * body carry the edited content for the edit action; feedback is the reviewer's note.
1056
1082
  */
1057
1083
  interface ReviewerDecisionRequest {
@@ -1068,8 +1094,8 @@ interface ReviewerDecisionRequest {
1068
1094
  feedback?: string;
1069
1095
  }
1070
1096
  /**
1071
- * The outcome of a reviewer decision (D5/§9). `kind=sent` when the platform ACS-sent
1072
- * with the COMPOSER's creds (approve/edit the reviewer NEVER holds mailbox:send);
1097
+ * The outcome of a reviewer decision (D5/§9). `kind=sent` when the platform sent
1098
+ * with the COMPOSER's creds (approve/edit: the reviewer NEVER holds mailbox:send);
1073
1099
  * `kind=sent_to_human` when the draft returned to the human queue (reject/escalate, or
1074
1100
  * a reject FORCED to the human by a circuit breaker, with `forced_by_breaker` naming it).
1075
1101
  */
@@ -1085,7 +1111,7 @@ interface ReviewerDecisionResult {
1085
1111
  /**
1086
1112
  * The D19/§8 backlog-reconciliation snapshot for a category (agent-readable, $0-LLM).
1087
1113
  * Counts the QUEUED drafts that are stale vs current-enough against the current
1088
- * category rules-version + house-style version (a pure integer compare). Read-only
1114
+ * category rules-version + house-style version (a pure integer compare). Read-only :
1089
1115
  * the agent READS the picture; the human / hooks TRIGGER the actual sweep.
1090
1116
  */
1091
1117
  interface ScanBacklogStatus {
@@ -1108,7 +1134,7 @@ interface PacingItem {
1108
1134
  state: "behind_cursor" | "in_window_fresh" | "in_window_redrafting" | "ahead";
1109
1135
  }
1110
1136
  /**
1111
- * The demand-driven pacing snapshot for a category (agent-readable, $0-LLM M7 Slice
1137
+ * The demand-driven pacing snapshot for a category (agent-readable, $0-LLM: M7 Slice
1112
1138
  * B/§8): the human review cursor, the effective window/ceiling/interval, the queued
1113
1139
  * count, and each queued draft's in-window/redrafting/behind-cursor classification.
1114
1140
  * Read-only; the cursor advances from the human's console approve/reject/edit actions.
@@ -1121,7 +1147,7 @@ interface CategoryPacingState {
1121
1147
  cursor_advanced_count: number;
1122
1148
  /** Effective freshness window (default org_settings.lookahead_window=3). */
1123
1149
  lookahead_window: number;
1124
- /** HARD per-nudge fan-out ceiling (default 10) one nudge can never fan to 500. */
1150
+ /** HARD per-nudge fan-out ceiling (default 10): one nudge can never fan to 500. */
1125
1151
  rework_batch_max: number;
1126
1152
  /** Per-agent token-bucket interval that coalesces feedback storms (default 5000). */
1127
1153
  nudge_min_interval_ms: number;
@@ -1183,6 +1209,8 @@ interface Rule {
1183
1209
  author_kind: "agent" | "human";
1184
1210
  created_at: IsoTimestamp;
1185
1211
  updated_at: IsoTimestamp;
1212
+ source_review_id?: string;
1213
+ source_turn_id?: string;
1186
1214
  }
1187
1215
  /** Filter for the ordered get_rules read (spec §5.4; §7). */
1188
1216
  interface GetRulesParams {
@@ -1202,11 +1230,11 @@ interface RuleSnapshot extends Page<Rule> {
1202
1230
  /**
1203
1231
  * Save / edit a writing rule (append-only by supersession; spec §5.4; D11).
1204
1232
  *
1205
- * Layering (org/project): an agent-plane save is ALWAYS project-layer the saved
1233
+ * Layering (org/project): an agent-plane save is ALWAYS project-layer: the saved
1206
1234
  * rule's `rule_layer` is `project`, bound to the calling key's project. There is no
1207
1235
  * settable `rule_layer` here: an agent cannot create org-layer / house-style
1208
1236
  * (`rule_layer="org"`) rules in v1; authoring org rules is a console/admin action.
1209
- * (`scope: "general"` still means a house-style rule WITHIN the project layer
1237
+ * (`scope: "general"` still means a house-style rule WITHIN the project layer :
1210
1238
  * `scope` is the category axis, `rule_layer` is the ownership axis.)
1211
1239
  */
1212
1240
  interface SaveRuleRequest {
@@ -1229,7 +1257,7 @@ interface SaveRuleRequest {
1229
1257
  /**
1230
1258
  * D8 retro-propagation HUMAN OPT-IN (default false). When true, a NEW category rule
1231
1259
  * that could apply to pending siblings enqueues ONE propagate_general_rule nudge
1232
- * (siblings + suggested_batch) so the agent redrafts a FEW at a time never the
1260
+ * (siblings + suggested_batch) so the agent redrafts a FEW at a time: never the
1233
1261
  * whole queue. Set only after the human said "apply to N pending?".
1234
1262
  */
1235
1263
  propagate_to_pending?: boolean;
@@ -1286,7 +1314,7 @@ interface SentResult {
1286
1314
  };
1287
1315
  /**
1288
1316
  * The review row that governed this send (ADDITIVE). Present on every send the
1289
- * service routed, i.e. all of them it is the handle that makes a post-crash
1317
+ * service routed, i.e. all of them: it is the handle that makes a post-crash
1290
1318
  * `reviews.get(id)` possible on the direct path too.
1291
1319
  */
1292
1320
  review?: {
@@ -1306,14 +1334,20 @@ interface Thread {
1306
1334
  /** Owning inbox address. */
1307
1335
  inbox_id: string;
1308
1336
  subject: string;
1309
- /** Distinct participant address strings across the thread. */
1337
+ /** List/search summaries use the latest envelope; thread detail may include the full conversation set. */
1310
1338
  participants: string[];
1311
1339
  message_count: number;
1312
1340
  last_message_at: IsoTimestamp;
1313
1341
  /** Most-recent-message preview snippet. */
1314
1342
  snippet: string;
1343
+ /** Whether the latest message is unread. */
1344
+ unread?: boolean;
1345
+ /** Whether the newest message has one or more attachments. */
1346
+ last_message_has_attachments?: boolean;
1347
+ /** Opaque message id for optimistic reply freshness checks. */
1348
+ last_message_id?: string;
1315
1349
  }
1316
- /** A thread plus its messages (oldest-first) `GET /v1/inboxes/{addr}/threads/{id}`. */
1350
+ /** A thread plus its messages (oldest-first): `GET /v1/inboxes/{addr}/threads/{id}`. */
1317
1351
  interface ThreadDetail extends Thread {
1318
1352
  messages: Message[];
1319
1353
  }
@@ -1485,7 +1519,7 @@ interface SuppressionEntry {
1485
1519
  /**
1486
1520
  * The result of a pre-check (`GET /v1/suppressions?recipient=…`): whether the
1487
1521
  * caller's OWN org suppresses the recipient, plus the matching org rows. Reflects
1488
- * only the caller's org state never a global/shared/cross-tenant opt-out.
1522
+ * only the caller's org state: never a global/shared/cross-tenant opt-out.
1489
1523
  */
1490
1524
  interface SuppressionPrecheck {
1491
1525
  recipient: string;
@@ -1504,7 +1538,7 @@ interface ListSuppressionsParams {
1504
1538
  /** Opaque cursor from a previous page's `next_cursor`. */
1505
1539
  cursor?: string;
1506
1540
  }
1507
- /** One DNS record the customer must set (manual mode) or that we serve (ns_delegated). */
1541
+ /** One nameserver record the customer must publish for delegated setup. */
1508
1542
  interface DomainRecord {
1509
1543
  name: string;
1510
1544
  type: string;
@@ -1518,40 +1552,43 @@ type DomainScope = "org" | "project";
1518
1552
  /**
1519
1553
  * Request body for `POST /v1/domains`. Onboards/adds a domain for the customer.
1520
1554
  *
1521
- * Permissions: every mode needs the `domain:manage` scope (the route gate); `mode:
1522
- * "purchased"` spends money at the registrar and therefore ADDITIONALLY requires the
1523
- * explicit, default-off `domain:purchase` scope (and is capped by the org/project
1524
- * purchased-domain plan limit, enforced before any registrar spend). `manual` and
1525
- * `ns_delegated` need `domain:manage` only.
1555
+ * Requires the `domain:manage` scope. This request only adds a delegated inbox
1556
+ * domain the customer controls; it cannot register one.
1557
+ * New registrations use the separate commerce quote/request workflow.
1526
1558
  */
1527
1559
  interface OnboardDomainRequest {
1528
1560
  domain: string;
1529
1561
  /**
1530
- * Onboarding path. Defaults to `ns_delegated` server-side when omitted. `purchased`
1531
- * additionally requires the `domain:purchase` scope.
1562
+ * Onboarding path. Defaults to `ns_delegated` server-side when omitted.
1532
1563
  */
1533
- mode?: OnboardingMode;
1534
- /** A-record IP served at a delegated zone's apex (ns_delegated only). */
1535
- mail_host_ip?: string;
1564
+ mode?: "ns_delegated";
1536
1565
  /**
1537
1566
  * Domain visibility. Defaults to `org` (org-shared, usable by every project in the
1538
1567
  * org). `project` binds the domain to the key's OWN bound project (never
1539
- * client-selected) so it is only visible/mintable from that project. A
1568
+ * client-selected) so it is only visible/creatable from that project. A
1540
1569
  * legacy/unscoped key (no bound project) falls back to `org`.
1541
1570
  */
1542
1571
  scope?: DomainScope;
1543
1572
  /**
1544
- * Optional assertion that must match the key's bound project NEVER a selector.
1573
+ * Optional assertion that must match the key's bound project: NEVER a selector.
1545
1574
  * A mismatch is a 403. The binding is always derived from the key.
1546
1575
  */
1547
1576
  project_id?: string;
1548
1577
  }
1549
1578
  /**
1550
1579
  * The agent-facing view of one onboarded domain (mirrors the Go `domainResponse`).
1551
- * `records` (and `delegation_ns` for ns_delegated) are present on get / onboard /
1552
- * verify and empty on list reads and for shared/purchased modes.
1580
+ * `delegation_ns` is present on get / onboard / verify for delegated domains and
1581
+ * empty on list reads. `records` remains for legacy response compatibility.
1553
1582
  */
1554
1583
  interface Domain {
1584
+ /** Authoritative outcome. Absent only when talking to an older server; never infer readiness from DKIM. */
1585
+ readiness?: DomainReadiness;
1586
+ /** Customer DNS health, independent of mail provisioning readiness. */
1587
+ delegation?: {
1588
+ status: "pending" | "confirmed" | "rechecking" | "check_delayed" | "action_required";
1589
+ checked_at?: string;
1590
+ confirmed_at?: string;
1591
+ };
1555
1592
  id: string;
1556
1593
  domain: string;
1557
1594
  mode: OnboardingMode;
@@ -1566,10 +1603,48 @@ interface Domain {
1566
1603
  /** Human-facing copy for what the customer must do next. */
1567
1604
  instruction?: string;
1568
1605
  }
1606
+ interface DomainStatusEvent {
1607
+ id: string;
1608
+ type: string;
1609
+ domain: string;
1610
+ summary: string;
1611
+ data: {
1612
+ domain: string;
1613
+ readiness: DomainReadiness;
1614
+ };
1615
+ created_at: string;
1616
+ }
1617
+ interface DomainStatusEventPage {
1618
+ items: DomainStatusEvent[];
1619
+ next_cursor: string;
1620
+ has_more: boolean;
1621
+ poll_after_seconds: number;
1622
+ }
1623
+ interface DomainReadiness {
1624
+ status: "waiting_for_dns" | "checking" | "setting_up" | "ready" | "action_required" | "needs_attention";
1625
+ label: string;
1626
+ summary: string;
1627
+ reason: string;
1628
+ action_required_by: "customer" | "extrovert" | "none";
1629
+ next_action: "check_dns_entries" | "restore_dns" | "wait" | "create_inbox" | "use_inbox" | "ask_owner_to_create_inbox";
1630
+ /** Domain configuration only; creating an inbox still requires permission and available plan capacity. */
1631
+ ready_for_inboxes: boolean;
1632
+ checked_at?: IsoTimestamp;
1633
+ next_check_at?: IsoTimestamp;
1634
+ poll_after_seconds: number;
1635
+ /** Omitted without inbox-read permission. Counts never imply organization-wide visibility for an agent. */
1636
+ inboxes?: {
1637
+ scope: "agent" | "project" | "organization";
1638
+ total: number;
1639
+ ready: number;
1640
+ setting_up: number;
1641
+ needs_attention: number;
1642
+ };
1643
+ }
1569
1644
  /**
1570
1645
  * Result of an ACCEPTED domain offboard (`DELETE /v1/domains/{domain}` → HTTP 202).
1571
- * Teardown reaping the outbound provider senders + routing rows, then scrubbing
1572
- * the DNS zone/records and the domain row runs as an async job. Poll `status_url`
1646
+ * Teardown: reaping the outbound provider senders + routing rows, then scrubbing
1647
+ * the DNS zone/records and the domain row: runs as an async job. Poll `status_url`
1573
1648
  * (`GET /v1/jobs/{job_id}`, via {@link Job} / `client.getJob(job_id)`) until
1574
1649
  * `status` is terminal (succeeded/failed/cancelled); the domain is ACCEPTED for
1575
1650
  * offboard, not yet fully torn down when this returns.
@@ -1594,6 +1669,95 @@ interface Job {
1594
1669
  updated_at: IsoTimestamp;
1595
1670
  finished_at?: IsoTimestamp;
1596
1671
  }
1672
+ /** One exact reason a commerce request cannot advance automatically. */
1673
+ interface CommerceBlocker {
1674
+ code: string;
1675
+ message: string;
1676
+ scope?: "org" | "project" | "agent" | string;
1677
+ limit_id?: string;
1678
+ used_cents?: number;
1679
+ reserved_cents?: number;
1680
+ limit_cents?: number;
1681
+ requested_cents?: number;
1682
+ used_count?: number;
1683
+ reserved_count?: number;
1684
+ limit_count?: number;
1685
+ reset_at?: IsoTimestamp;
1686
+ manage_url?: string;
1687
+ }
1688
+ /** Request body for the non-spending domain quote endpoint. */
1689
+ interface QuoteDomainRequest {
1690
+ domain: string;
1691
+ }
1692
+ /** Current, expiring domain registration quote. Quoting never purchases. */
1693
+ interface DomainQuote {
1694
+ object: "domain_quote";
1695
+ domain: string;
1696
+ available: boolean;
1697
+ currency: string;
1698
+ quote_cents: number;
1699
+ renewal_cents: number;
1700
+ premium: boolean;
1701
+ quote_expires_at: IsoTimestamp;
1702
+ required_plan?: string;
1703
+ required_plan_price_cents?: number;
1704
+ blockers: CommerceBlocker[];
1705
+ }
1706
+ type CommerceRequestKind = "domain_purchase" | "plan_change";
1707
+ interface RequestDomainPurchaseRequest {
1708
+ domain: string;
1709
+ /** Stable retry identity; sent as the `Idempotency-Key` header, not in the JSON body. */
1710
+ idempotency_key: string;
1711
+ scope?: DomainScope;
1712
+ rationale?: string;
1713
+ auto_renew?: boolean;
1714
+ }
1715
+ interface RequestPlanChangeRequest {
1716
+ target_plan: "free" | "developer" | "startup";
1717
+ /** Stable retry identity; sent as the `Idempotency-Key` header, not in the JSON body. */
1718
+ idempotency_key: string;
1719
+ rationale?: string;
1720
+ }
1721
+ interface ListCommerceRequestsParams {
1722
+ limit?: number;
1723
+ page?: string;
1724
+ }
1725
+ /** Durable poll shape for an agent-initiated financial request. */
1726
+ interface CommerceRequest {
1727
+ object: "commerce_request";
1728
+ id: string;
1729
+ project_id?: string;
1730
+ agent_id?: string;
1731
+ kind: CommerceRequestKind;
1732
+ state: string;
1733
+ domain?: string;
1734
+ domain_scope?: DomainScope;
1735
+ target_plan?: string;
1736
+ current_plan?: string;
1737
+ rationale?: string;
1738
+ currency: string;
1739
+ quote_cents: number;
1740
+ renewal_cents: number;
1741
+ approved_max_cents?: number;
1742
+ quote_expires_at?: IsoTimestamp;
1743
+ auto_renew: boolean;
1744
+ required_plan?: string;
1745
+ required_plan_price_cents?: number;
1746
+ blocker_code?: string;
1747
+ blockers: CommerceBlocker[];
1748
+ approval_url?: string;
1749
+ payment_action_url?: string;
1750
+ external_job_id?: string;
1751
+ effective_at?: IsoTimestamp;
1752
+ notification_state?: string;
1753
+ notification_last_error?: string;
1754
+ agent_next_action: string;
1755
+ retry_safe: boolean;
1756
+ poll_after_seconds: number;
1757
+ version: number;
1758
+ created_at: IsoTimestamp;
1759
+ updated_at: IsoTimestamp;
1760
+ }
1597
1761
  /**
1598
1762
  * One event from the SSE stream (`GET /v1/inboxes/{addr}/stream` or `GET
1599
1763
  * /v1/events`). It is the SAME envelope a webhook delivers, so a stream consumer
@@ -1630,12 +1794,12 @@ interface StreamOptions {
1630
1794
  interface SignUpRequest {
1631
1795
  /** Human email that receives the one-time verification code. */
1632
1796
  human_email: string;
1633
- /** Desired local-part for the first inbox (optional; auto-generated when omitted). */
1797
+ /** Desired local part on `free.extrovertmail.com`. It must normalize to at least 5 characters and cannot use a reserved name. */
1634
1798
  username?: string;
1635
1799
  }
1636
1800
  /**
1637
1801
  * Response from `POST /v1/agent/sign-up`. The `agent_key` is a LIMITED-scope key
1638
- * (read-only) that expires with the emailed code. Successful verification revokes
1802
+ * (verification-only, with no inbox read or send permission) that expires with the emailed code. Successful verification revokes
1639
1803
  * it and returns a replacement full-scope key. The OTP itself is never returned.
1640
1804
  */
1641
1805
  interface SignUpResponse {
@@ -1645,7 +1809,7 @@ interface SignUpResponse {
1645
1809
  agent_key: string;
1646
1810
  key_prefix: string;
1647
1811
  scopes: Scope[];
1648
- /** The first inbox minted for the agent. */
1812
+ /** The first inbox created for the agent. */
1649
1813
  address: string;
1650
1814
  verified: boolean;
1651
1815
  /** Where the verification code was sent. */
@@ -1694,14 +1858,28 @@ interface VerifyResponse {
1694
1858
  org_claim_token?: string;
1695
1859
  }
1696
1860
  /**
1697
- * Response from `GET /v1/auth/me` the verified principal behind the key.
1861
+ * Response from `GET /v1/auth/me`: the verified principal behind the key.
1698
1862
  *
1699
1863
  * `org_id`/`project_id` are the FIXED org/project the key is bound to (resolved from
1700
1864
  * the stored key, never client input). There is NO mutable project selector for a
1701
- * scoped key `whoami` is the canonical project-visibility surface; project
1865
+ * scoped key: `whoami` is the canonical project-visibility surface; project
1702
1866
  * selection happens when the human/admin issues the enrollment token or agent key.
1703
1867
  */
1704
1868
  interface WhoAmI {
1869
+ connection_status?: "connected";
1870
+ summary?: string;
1871
+ agent_name?: string;
1872
+ organization_name?: string;
1873
+ project_name?: string;
1874
+ /** Granted permissions, not a guarantee of plan capacity or review approval. */
1875
+ capabilities?: {
1876
+ read_domain_status: boolean;
1877
+ connect_owned_domains: boolean;
1878
+ create_inboxes: boolean;
1879
+ read_inboxes: boolean;
1880
+ submit_mail_for_review: boolean;
1881
+ request_purchases: boolean;
1882
+ };
1705
1883
  customer_id: string;
1706
1884
  /**
1707
1885
  * The fixed org the key is bound to. Optional to match the OpenAPI contract: a
@@ -1717,13 +1895,31 @@ interface WhoAmI {
1717
1895
  key_id: string;
1718
1896
  scopes: Scope[];
1719
1897
  }
1898
+ /** Learn writing guidance from an authenticated human turn on your review. */
1899
+ interface LearnReviewRuleRequest {
1900
+ client_id: string;
1901
+ source_turn_id: string;
1902
+ rule_text: string;
1903
+ target: "org_house" | "project_general" | "category";
1904
+ category_id?: string;
1905
+ kind?: "soft" | "hard";
1906
+ supersedes_id?: string;
1907
+ }
1908
+ interface LearnedReviewRule {
1909
+ rule: Rule;
1910
+ source_review_id: string;
1911
+ source_turn_id: string;
1912
+ human_id: string;
1913
+ audit_id: string;
1914
+ propagation: "queued";
1915
+ }
1720
1916
 
1721
1917
  /**
1722
1918
  * The ONE list envelope + opaque-cursor iteration (redesign §5.2 / §6.2).
1723
1919
  *
1724
1920
  * Every redesign collection endpoint (the canonical `x.projects.inboxes.*` chain
1725
1921
  * and beyond) returns {@link List}: `{ object: "list", data, has_more, next_cursor }`.
1726
- * `next_cursor` is OPAQUE treat it as a token and pass it back verbatim as
1922
+ * `next_cursor` is OPAQUE - treat it as a token and pass it back verbatim as
1727
1923
  * `?cursor` to fetch the next page. {@link ListPage} wraps a raw {@link List} with
1728
1924
  * ergonomic iteration (`for await … of`) and a `nextPage()` cursor walker so callers
1729
1925
  * never thread cursors by hand.
@@ -1773,7 +1969,7 @@ declare class ListPage<T> implements AsyncIterable<T> {
1773
1969
  readonly object: "list";
1774
1970
  constructor(raw: List<T>, fetcher: PageFetcher<T>);
1775
1971
  /**
1776
- * Fetch the next page. Throws if there is none guard with {@link hasMore}.
1972
+ * Fetch the next page. Throws if there is none - guard with {@link hasMore}.
1777
1973
  */
1778
1974
  nextPage(signal?: AbortSignal): Promise<ListPage<T>>;
1779
1975
  /**
@@ -1849,12 +2045,25 @@ interface Transport {
1849
2045
  precheckSuppression(recipient: string, signal?: AbortSignal): Promise<SuppressionPrecheck>;
1850
2046
  listSuppressions(params: ListSuppressionsParams, signal?: AbortSignal): Promise<Page<SuppressionEntry>>;
1851
2047
  revokeSuppression(id: string, reason: string, signal?: AbortSignal): Promise<SuppressionEntry>;
1852
- listDomains(signal?: AbortSignal): Promise<Page<Domain>>;
2048
+ listDomains(signal?: AbortSignal, params?: {
2049
+ page?: string;
2050
+ limit?: number;
2051
+ }): Promise<Page<Domain>>;
2052
+ listDomainEvents(domain: string, params: {
2053
+ after?: string;
2054
+ limit?: number;
2055
+ }, signal?: AbortSignal): Promise<DomainStatusEventPage>;
1853
2056
  getDomain(domain: string, signal?: AbortSignal): Promise<Domain>;
1854
2057
  onboardDomain(req: OnboardDomainRequest, signal?: AbortSignal): Promise<Domain>;
1855
2058
  verifyDomain(domain: string, signal?: AbortSignal): Promise<Domain>;
1856
2059
  offboardDomain(domain: string, signal?: AbortSignal): Promise<DomainOffboard>;
1857
2060
  getJob(jobId: string, signal?: AbortSignal): Promise<Job>;
2061
+ quoteDomain(req: QuoteDomainRequest, signal?: AbortSignal): Promise<DomainQuote>;
2062
+ requestDomainPurchase(req: RequestDomainPurchaseRequest, signal?: AbortSignal): Promise<CommerceRequest>;
2063
+ requestPlanChange(req: RequestPlanChangeRequest, signal?: AbortSignal): Promise<CommerceRequest>;
2064
+ getCommerceRequest(requestId: string, signal?: AbortSignal): Promise<CommerceRequest>;
2065
+ cancelCommerceRequest(requestId: string, signal?: AbortSignal): Promise<CommerceRequest>;
2066
+ listCommerceRequests(params: ListCommerceRequestsParams, signal?: AbortSignal): Promise<Page<CommerceRequest>>;
1858
2067
  submitForReview(address: string, req: SendRequest, signal?: AbortSignal): Promise<SendOutcome>;
1859
2068
  submitReplyForReview(address: string, req: ReplyRequest, signal?: AbortSignal): Promise<SendOutcome>;
1860
2069
  listReviews(params: ListReviewsParams, signal?: AbortSignal): Promise<Page<Review>>;
@@ -1880,6 +2089,7 @@ interface Transport {
1880
2089
  getScanBacklogStatus(categoryId: string, signal?: AbortSignal): Promise<ScanBacklogStatus>;
1881
2090
  getCategoryPacingState(categoryId: string, signal?: AbortSignal): Promise<CategoryPacingState>;
1882
2091
  getRules(params: GetRulesParams, signal?: AbortSignal): Promise<RuleSnapshot>;
2092
+ learnReviewRule(reviewId: string, req: LearnReviewRuleRequest, signal?: AbortSignal): Promise<LearnedReviewRule>;
1883
2093
  saveRule(req: SaveRuleRequest, signal?: AbortSignal): Promise<Rule>;
1884
2094
  promoteRule(ruleId: string, toScope: "general" | "category", signal?: AbortSignal): Promise<Rule>;
1885
2095
  retireRule(ruleId: string, signal?: AbortSignal): Promise<Rule>;
@@ -1903,7 +2113,7 @@ interface Transport {
1903
2113
  *
1904
2114
  * The mock honors the same request/response models as the real API and reproduces the few behaviors
1905
2115
  * the SDK ergonomics depend on (enrollment cap, idempotency on `client_id`, wait_for_email returning
1906
- * an OTP). It is intentionally simple not a full server and never reaches the network.
2116
+ * an OTP). It is intentionally simple - not a full server - and never reaches the network.
1907
2117
  */
1908
2118
 
1909
2119
  /**
@@ -1931,7 +2141,7 @@ declare class MockBackend {
1931
2141
  * Normalize an inbox ref (opaque id OR address alias) to the canonical address the
1932
2142
  * mock keys its message/thread/contact maps on. The SDK now routes inbox ops by the
1933
2143
  * canonical opaque `id` when it holds a full record (matching the contract's
1934
- * canonical-key semantics), so the mock must resolve an id back to its address
2144
+ * canonical-key semantics), so the mock must resolve an id back to its address -
1935
2145
  * both key `state.inboxes` (same object), `state.messages` keys by address only.
1936
2146
  * Unknown refs pass through unchanged so the existing not-found paths still fire.
1937
2147
  */
@@ -1961,8 +2171,8 @@ declare class MockBackend {
1961
2171
  forward(address: string, messageId: string, req: ForwardRequest): SendOutcome;
1962
2172
  /**
1963
2173
  * Submit a new message for review (mock). Rides the SAME endpoint as `send` on
1964
- * the real server, so it is literally the same call here: the resolved policy
1965
- * not which SDK method you picked decides whether the message is queued
2174
+ * the real server, so it is literally the same call here: the resolved policy -
2175
+ * not which SDK method you picked - decides whether the message is queued
1966
2176
  * (`kind:"queued_for_review"`) or delivered.
1967
2177
  */
1968
2178
  submitForReview(address: string, req: SendRequest): SendOutcome;
@@ -1983,9 +2193,9 @@ declare class MockBackend {
1983
2193
  private setReviewState;
1984
2194
  /** Mark a review delivered on an auto-send path and emit its terminal `sent` nudge. */
1985
2195
  private markReviewAutoSent;
1986
- /** Raw delivery for a send no policy, only reachable from submitOutbound. */
2196
+ /** Raw delivery for a send - no policy, only reachable from submitOutbound. */
1987
2197
  private deliverSend;
1988
- /** Raw delivery for a reply no policy, only reachable from submitOutbound. */
2198
+ /** Raw delivery for a reply - no policy, only reachable from submitOutbound. */
1989
2199
  private deliverReply;
1990
2200
  /** Append the outbound message and shape the legacy send result. */
1991
2201
  private deliverRaw;
@@ -2049,7 +2259,7 @@ declare class MockBackend {
2049
2259
  reviewerDecide(reviewId: string, req: ReviewerDecisionRequest): ReviewerDecisionResult | undefined;
2050
2260
  /**
2051
2261
  * Browse the registry (mock), newest-first, excluding merged/soft-deleted. `match`
2052
- * is a pure lexical filter (every token must appear in name+description) NO LLM,
2262
+ * is a pure lexical filter (every token must appear in name+description) - NO LLM,
2053
2263
  * mirroring the server.
2054
2264
  */
2055
2265
  listCategories(params?: ListCategoriesParams): Page<Category>;
@@ -2057,14 +2267,14 @@ declare class MockBackend {
2057
2267
  getCategory(categoryId: string): Category | undefined;
2058
2268
  /** Propose a category (mock): stands immediately, author_kind=agent (D9). */
2059
2269
  proposeCategory(req: ProposeCategoryRequest): Category;
2060
- /** Rename / re-describe a category (mock) metadata only (D10). */
2270
+ /** Rename / re-describe a category (mock) - metadata only (D10). */
2061
2271
  updateCategory(categoryId: string, req: UpdateCategoryRequest): Category | undefined;
2062
2272
  /** The mock account-default risk dial (mirrors the server defaults). */
2063
2273
  private accountDial;
2064
2274
  /**
2065
2275
  * Read the effective risk dial (mock): the account default + every category with an
2066
2276
  * inherited (null override) effective dial. The mock category carries no overrides,
2067
- * so every category inherits effective == account.
2277
+ * so every category inherits - effective == account.
2068
2278
  */
2069
2279
  getRiskDial(): RiskDial;
2070
2280
  private nextGraduationState;
@@ -2076,19 +2286,19 @@ declare class MockBackend {
2076
2286
  getGraduationStatus(categoryId: string): GraduationStatus | undefined;
2077
2287
  /**
2078
2288
  * Propose graduating a category (mock): returns the current gate status without
2079
- * changing the category state (D16 an agent can never flip the bit).
2289
+ * changing the category state (D16 - an agent can never flip the bit).
2080
2290
  */
2081
2291
  proposeGraduation(categoryId: string, _req: ProposeGraduationRequest): GraduationStatus | undefined;
2082
2292
  /**
2083
2293
  * Read the D19/§8 backlog-reconciliation status (mock): counts the QUEUED drafts in a
2084
2294
  * category that are stale vs current-enough against the current rules-version. The
2085
2295
  * mock has no per-draft composed_* stamps on its Review fixtures, so every queued
2086
- * draft reads as current-enough (composed 0 vs current 0) the contract shape is
2296
+ * draft reads as current-enough (composed 0 vs current 0) - the contract shape is
2087
2297
  * exercised; the integer-compare logic is covered by the Go tests.
2088
2298
  */
2089
2299
  getScanBacklogStatus(categoryId: string): ScanBacklogStatus | undefined;
2090
2300
  /**
2091
- * Read the demand-driven pacing state (mock M7 Slice B/§8): the cursor + effective
2301
+ * Read the demand-driven pacing state (mock - M7 Slice B/§8): the cursor + effective
2092
2302
  * window/ceiling/interval + each queued draft's classification. The mock has no cursor
2093
2303
  * (nothing reviewed) and no composed_* stamps, so every queued draft reads in-window-
2094
2304
  * fresh until the window fills, then ahead; the contract shape is exercised (the
@@ -2097,17 +2307,19 @@ declare class MockBackend {
2097
2307
  getCategoryPacingState(categoryId: string): CategoryPacingState | undefined;
2098
2308
  /** rank a rule for the §7 ladder (mock mirror of the server's deterministic order). */
2099
2309
  private ruleRank;
2100
- /** Get the ORDERED active rule set (mock) §7 ladder + category-before-general. */
2310
+ /** Get the ORDERED active rule set (mock) - §7 ladder + category-before-general. */
2101
2311
  getRules(params?: GetRulesParams): RuleSnapshot;
2102
- /** Save / edit a rule (mock) append-only by supersession (D11). */
2312
+ /** Save / edit a rule (mock) - append-only by supersession (D11). */
2313
+ private learnedRules;
2314
+ learnReviewRule(reviewId: string, req: LearnReviewRuleRequest): LearnedReviewRule;
2103
2315
  saveRule(req: SaveRuleRequest): Rule;
2104
2316
  /** Promote a rule between layers (mock, via supersession), or undefined when unknown. */
2105
2317
  promoteRule(ruleId: string, toScope: "general" | "category"): Rule | undefined;
2106
- /** Retire a rule (mock) soft delete, or undefined when unknown. */
2318
+ /** Retire a rule (mock) - soft delete, or undefined when unknown. */
2107
2319
  retireRule(ruleId: string): Rule | undefined;
2108
2320
  /** Read the rule/category change audit log (mock). */
2109
2321
  getRuleAudit(params?: GetRuleAuditParams): Page<RuleAuditEntry>;
2110
- /** Undo a rule change (mock) restore the prior version; idempotent (re-undo 409). */
2322
+ /** Undo a rule change (mock) - restore the prior version; idempotent (re-undo 409). */
2111
2323
  undoRuleChange(udoId: string): Rule;
2112
2324
  /** recordRuleAudit appends one change/undo audit row (mock). */
2113
2325
  private recordRuleAudit;
@@ -2124,7 +2336,7 @@ declare class MockBackend {
2124
2336
  */
2125
2337
  private enqueueTerminalNudge;
2126
2338
  /**
2127
- * Enqueue `front_run_next` the signal that the review reached a terminal state
2339
+ * Enqueue `front_run_next` - the signal that the review reached a terminal state
2128
2340
  * while the agent was still trying to act on it.
2129
2341
  *
2130
2342
  * Deduped on (review, terminal state, parent revision) so a retry loop hitting
@@ -2142,8 +2354,8 @@ declare class MockBackend {
2142
2354
  }): Review | undefined;
2143
2355
  /**
2144
2356
  * Mock-only: mirror an approved draft whose delivery then FAILED at the provider.
2145
- * This is the case the composing agent was previously never told about the
2146
- * console showed the error and the agent's queue stayed silent so the loop test
2357
+ * This is the case the composing agent was previously never told about - the
2358
+ * console showed the error and the agent's queue stayed silent - so the loop test
2147
2359
  * that matters most drives this path.
2148
2360
  */
2149
2361
  simulateSendFailed(reviewId: string, error?: string): Review | undefined;
@@ -2171,7 +2383,7 @@ declare class MockBackend {
2171
2383
  listReviewEvents(params?: ListReviewEventsParams): ReviewEventsResult;
2172
2384
  /**
2173
2385
  * Long-poll for a review event (mock). Offline there is nothing to wait FOR, so it
2174
- * returns the immediate drain (empty when caught up) the server's "empty on
2386
+ * returns the immediate drain (empty when caught up) - the server's "empty on
2175
2387
  * timeout" contract.
2176
2388
  */
2177
2389
  waitForReviewEvent(params?: WaitForReviewEventParams): ReviewEventsResult;
@@ -2194,9 +2406,10 @@ declare class MockBackend {
2194
2406
  getMessageRaw(messageId: string): string;
2195
2407
  /** Full-text search scoped to one inbox. */
2196
2408
  searchMessages(address: string, params: SearchMessagesParams): Page<Message>;
2197
- listThreads(address: string): Page<Thread>;
2409
+ listThreads(address: string, params?: ListThreadsParams): Page<Thread>;
2198
2410
  /** Thread-level search (subject / snippet / participant substring). */
2199
2411
  searchThreads(address: string, params: SearchMessagesParams): Page<Thread>;
2412
+ private paginateThreads;
2200
2413
  /** Fetch one thread (with messages, oldest-first) by id under an inbox. */
2201
2414
  getThread(address: string, threadId: string): ThreadDetail;
2202
2415
  /**
@@ -2251,7 +2464,7 @@ declare class MockBackend {
2251
2464
  listContactLists(address: string): Page<ContactListEntry> | undefined;
2252
2465
  /** Delete a contact-list entry by id; returns false when it was not found. */
2253
2466
  deleteContactListEntry(_address: string, entryId: string): boolean;
2254
- /** Onboard a domain, mirroring the server's per-mode record set + status. Idempotent on the name. */
2467
+ /** Add a delegated domain and return only the customer-published nameservers. */
2255
2468
  onboardDomain(req: OnboardDomainRequest): Domain;
2256
2469
  /** List onboarded domains (records omitted on the summary, mirroring the server). */
2257
2470
  listDomains(): Page<Domain>;
@@ -2268,6 +2481,12 @@ declare class MockBackend {
2268
2481
  offboardDomain(domain: string): boolean;
2269
2482
  /** Get one async job's poll status; undefined when the id is unknown. */
2270
2483
  getJob(jobId: string): Job | undefined;
2484
+ quoteDomain(req: QuoteDomainRequest): DomainQuote;
2485
+ requestDomainPurchase(req: RequestDomainPurchaseRequest): CommerceRequest;
2486
+ requestPlanChange(req: RequestPlanChangeRequest): CommerceRequest;
2487
+ getCommerceRequest(requestId: string): CommerceRequest | undefined;
2488
+ cancelCommerceRequest(requestId: string): CommerceRequest | undefined;
2489
+ listCommerceRequests(params?: ListCommerceRequestsParams): Page<CommerceRequest>;
2271
2490
  /**
2272
2491
  * Pre-check whether the caller's org suppresses a recipient (mirrors
2273
2492
  * `GET /v1/suppressions?recipient=…`). Returns `{recipient, suppressed, rows}`
@@ -2285,7 +2504,7 @@ declare class MockBackend {
2285
2504
  /**
2286
2505
  * Reject the WHOLE send if ANY recipient has an active org-scope suppression,
2287
2506
  * naming exactly the suppressed addresses (never the scope/origin) so the caller
2288
- * can drop them and retry mirroring the live `recipient_suppressed` (422) path.
2507
+ * can drop them and retry - mirroring the live `recipient_suppressed` (422) path.
2289
2508
  */
2290
2509
  private enforceSuppression;
2291
2510
  /**
@@ -2296,19 +2515,25 @@ declare class MockBackend {
2296
2515
  private enforceSendPolicy;
2297
2516
  }
2298
2517
 
2518
+ interface DomainWaitResult {
2519
+ domain: Domain;
2520
+ outcome: "ready" | "action_required" | "needs_attention" | "timed_out" | "status_unavailable";
2521
+ resume_after_seconds: number;
2522
+ }
2523
+
2299
2524
  /**
2300
2525
  * Key-tier awareness (redesign §3.1).
2301
2526
  *
2302
2527
  * An agent key encodes its CEILING tier in its raw prefix. The SDK never trusts
2303
- * client input for scope the tier is derived from the key the caller already
2528
+ * client input for scope - the tier is derived from the key the caller already
2304
2529
  * holds, purely as a client-side hint so an app can branch (e.g. an org-tier key
2305
2530
  * MUST pick a project breadth on a list; a project/inbox key may use the bare
2306
2531
  * sugar). The server remains the source of truth; this is advisory only.
2307
2532
  *
2308
2533
  * Prefix scheme (the secret tail is unchanged across tiers):
2309
- * - `pk_agent_org_…` → {@link KeyTier.Org} (admin/console mint only)
2534
+ * - `pk_agent_org_…` → {@link KeyTier.Org} (admin/console issuance only)
2310
2535
  * - `pk_agent_proj_…` → {@link KeyTier.Project} (enrollment redeem + console)
2311
- * - `pk_agent_inbox_…` → {@link KeyTier.Inbox} (admin/console mint only)
2536
+ * - `pk_agent_inbox_…` → {@link KeyTier.Inbox} (admin/console issuance only)
2312
2537
  * - legacy `pk_agent_…` (no tier segment) → {@link KeyTier.Project}
2313
2538
  */
2314
2539
  /** The ceiling tier encoded in an agent key's prefix. */
@@ -2316,7 +2541,7 @@ type KeyTier = "org" | "project" | "inbox" | "unknown";
2316
2541
  /**
2317
2542
  * Derive the {@link KeyTier} from a raw agent key by peeking the segment after the
2318
2543
  * `pk_agent_` head. A legacy bare `pk_agent_…` key (no tier segment) maps to
2319
- * `"project"` exactly today's behavior. A non-agent credential (enrollment
2544
+ * `"project"` - exactly today's behavior. A non-agent credential (enrollment
2320
2545
  * token, Clerk session, empty) returns `"unknown"`.
2321
2546
  */
2322
2547
  declare function parseKeyTier(apiKey: string | undefined): KeyTier;
@@ -2334,7 +2559,7 @@ declare function tierAllowsOrgWildcard(tier: KeyTier): boolean;
2334
2559
  declare function tierNeedsExplicitBreadth(tier: KeyTier): boolean;
2335
2560
 
2336
2561
  /**
2337
- * InboxHandle an ergonomic, bound handle to a single inbox.
2562
+ * InboxHandle: an ergonomic, bound handle to a single inbox.
2338
2563
  *
2339
2564
  * Returned by `extrovert.inboxes.create(...)` and `extrovert.inbox(address)`, it scopes every operation
2340
2565
  * to one address so agent code reads naturally: `inbox.send(...)`, `inbox.waitForEmail(...)`. This
@@ -2348,7 +2573,7 @@ interface InboxHandleOptions {
2348
2573
  declare class InboxHandle {
2349
2574
  private readonly transport;
2350
2575
  private readonly options;
2351
- /** The canonical address, e.g. `agent7@smtp.extrovert.dev`. */
2576
+ /** The canonical address, e.g. `agent7@extrovertmail.com`. */
2352
2577
  readonly address: string;
2353
2578
  /** The full inbox record this handle was created from (absent when constructed by address). */
2354
2579
  readonly record: Inbox | undefined;
@@ -2394,8 +2619,8 @@ declare class InboxHandle {
2394
2619
  * Returns a three-way {@link SendOutcome}: `kind:"queued_for_review"` means a
2395
2620
  * human has to approve it and NOTHING has been delivered yet; anything else was
2396
2621
  * delivered. Under the default `require_review` policy a call WITHOUT an
2397
- * `intent` raises `IntentRequiredError` (422) instead nothing sent, nothing
2398
- * queued so pass one, or read `inbox.record.effective_review_policy` first.
2622
+ * `intent` raises `IntentRequiredError` (422) instead: nothing sent, nothing
2623
+ * queued: so pass one, or read `inbox.record.effective_review_policy` first.
2399
2624
  */
2400
2625
  send(req: SendRequest, signal?: AbortSignal): Promise<SendOutcome>;
2401
2626
  /**
@@ -2403,14 +2628,14 @@ declare class InboxHandle {
2403
2628
  * the latest message) or `message_id` (reply to that message); the server
2404
2629
  * derives To / Subject / In-Reply-To / References. Set `reply_all` to reply to
2405
2630
  * every thread recipient. Returns the same three-way {@link SendOutcome} as
2406
- * {@link send} a reply is governed by the review policy too.
2631
+ * {@link send}: a reply is governed by the review policy too.
2407
2632
  */
2408
2633
  reply(req: ReplyRequest, signal?: AbortSignal): Promise<SendOutcome>;
2409
2634
  /**
2410
2635
  * Forward a message in this inbox to new recipients, preserving the original.
2411
2636
  *
2412
2637
  * A forward is an outbound message to arbitrary NEW recipients that quotes an
2413
- * inbound thread, so it is governed by the review policy exactly like a send
2638
+ * inbound thread, so it is governed by the review policy exactly like a send :
2414
2639
  * same {@link SendOutcome} union, same `intent` requirement.
2415
2640
  */
2416
2641
  forward(messageId: string, req: ForwardRequest, signal?: AbortSignal): Promise<SendOutcome>;
@@ -2511,7 +2736,7 @@ declare class InboxHandle {
2511
2736
  }
2512
2737
 
2513
2738
  /**
2514
- * `extrovert.projects` the CANONICAL project-scoped resource chain (redesign §4).
2739
+ * `extrovert.projects`: the CANONICAL project-scoped resource chain (redesign §4).
2515
2740
  *
2516
2741
  * Scope lives in the KEY; a broad (org-tier) key narrows to one project by PATH.
2517
2742
  * The headline chain is `x.projects.inboxes.*`, mirroring
@@ -2526,7 +2751,7 @@ declare class InboxHandle {
2526
2751
  *
2527
2752
  * Operations are keyed by the OPAQUE `inbox_id` (the inbox's email address is also
2528
2753
  * accepted as a within-project alias). `projectId` may be `"-"` for the org-wide
2529
- * wildcard only an org-tier key may use it (others get 403 `forbidden_scope`).
2754
+ * wildcard: only an org-tier key may use it (others get 403 `forbidden_scope`).
2530
2755
  *
2531
2756
  * The bare `x.inboxes.*` / `x.inbox(address)` surface is curl-style sugar that
2532
2757
  * resolves to the key's default project; this chain is the contract-canonical one.
@@ -2538,7 +2763,7 @@ interface ProjectsContext {
2538
2763
  handleOptions: InboxHandleOptions;
2539
2764
  }
2540
2765
  /**
2541
- * `x.projects.inboxes` create / list / get / update / delete inboxes, plus the
2766
+ * `x.projects.inboxes`: create / list / get / update / delete inboxes, plus the
2542
2767
  * send / reply / message / thread / wait operations, all scoped to one project (or
2543
2768
  * the `-` org wildcard for an org-tier key). List returns a {@link ListPage} that
2544
2769
  * auto-paginates over the opaque-cursor {@link import("../pagination.js").List} envelope.
@@ -2574,8 +2799,8 @@ declare class ProjectInboxes {
2574
2799
  * Returns a three-way {@link SendOutcome}: `kind:"queued_for_review"` means a
2575
2800
  * human has to approve it and NOTHING has been delivered yet; anything else was
2576
2801
  * delivered. Under the default `require_review` policy a call WITHOUT an
2577
- * `intent` raises `IntentRequiredError` (422) instead nothing sent, nothing
2578
- * queued so pass one, or read `inbox.record.effective_review_policy` first.
2802
+ * `intent` raises `IntentRequiredError` (422) instead: nothing sent, nothing
2803
+ * queued: so pass one, or read `inbox.record.effective_review_policy` first.
2579
2804
  */
2580
2805
  send(projectId: string, inboxId: string, req: SendRequest, signal?: AbortSignal): Promise<SendOutcome>;
2581
2806
  /** Reply within a thread from an inbox in `projectId`. See {@link send} on the return union. */
@@ -2610,14 +2835,14 @@ declare class ProjectInboxes {
2610
2835
  *
2611
2836
  * The frozen contract project-prefixes ONLY the inbox collection/item/credentials
2612
2837
  * routes (`/v1/projects/{project_id}/inboxes[/{inbox_id}][/credentials]`); the
2613
- * send/reply/forward/message/thread/wait sub-ops have NO project-prefixed path
2838
+ * send/reply/forward/message/thread/wait sub-ops have NO project-prefixed path :
2614
2839
  * they address the inbox by its opaque id directly (`/v1/inboxes/{inbox_id}/…`),
2615
2840
  * where the project is implicit in (and enforced by) the inbox id server-side.
2616
2841
  *
2617
2842
  * So for these sub-ops `projectId` cannot be carried on the URL and is NOT a URL
2618
2843
  * selector. The adversarial review flagged that silently discarding it makes the
2619
2844
  * signature misleading. CHOICE: keep the arg (dropping it would break the chain's
2620
- * symmetry with create/list/get/update/delete the more disruptive option) but
2845
+ * symmetry with create/list/get/update/delete: the more disruptive option) but
2621
2846
  * VALIDATE it rather than ignore it. We reject the two client mistakes we can catch
2622
2847
  * without a round-trip:
2623
2848
  * - a blank / whitespace-only `projectId` (a required selector everywhere else in
@@ -2629,12 +2854,12 @@ declare class ProjectInboxes {
2629
2854
  private ref;
2630
2855
  }
2631
2856
  /**
2632
- * `extrovert.projects` the canonical project-scoped resource namespace. Today it
2857
+ * `extrovert.projects`: the canonical project-scoped resource namespace. Today it
2633
2858
  * exposes the `inboxes` chain (`x.projects.inboxes.*`); future project-scoped
2634
2859
  * resources (domains, agents) hang off the same namespace.
2635
2860
  */
2636
2861
  declare class Projects {
2637
- /** `x.projects.inboxes.*` the canonical inbox chain. */
2862
+ /** `x.projects.inboxes.*`: the canonical inbox chain. */
2638
2863
  readonly inboxes: ProjectInboxes;
2639
2864
  constructor(ctx: ProjectsContext);
2640
2865
  }
@@ -2655,25 +2880,26 @@ interface ResourceContext {
2655
2880
  */
2656
2881
  keyTier: KeyTier;
2657
2882
  }
2658
- /** `extrovert.inboxes` create, list, get, update, delete inboxes. */
2883
+ /** `extrovert.inboxes`: create, list, get, update, delete inboxes. */
2659
2884
  declare class Inboxes {
2660
2885
  private readonly ctx;
2661
2886
  constructor(ctx: ResourceContext);
2662
2887
  /**
2663
- * Create an inbox. The default path mints an address on a pre-verified shared subdomain of
2664
- * `smtp.extrovert.dev`, so it returns a live, send-and-receive-capable inbox in one call.
2888
+ * Create an inbox. The default path creates an address on `extrovertmail.com`
2889
+ * for paid accounts or `free.extrovertmail.com` for free signups, so it returns
2890
+ * a live inbox in one call.
2665
2891
  *
2666
2892
  * Pass `metadata` to attach arbitrary key-value data, and `client_id` for idempotent creation
2667
2893
  * (re-calling with the same id returns the same inbox, with its metadata replayed verbatim).
2668
2894
  */
2669
2895
  create(req?: CreateInboxRequest, signal?: AbortSignal): Promise<InboxHandle>;
2670
2896
  /**
2671
- * List inboxes visible to the calling key (the bare curl-sugar surface resolves
2897
+ * List inboxes visible to the calling key (the bare curl-sugar surface: resolves
2672
2898
  * to the key's default project). An org-tier key has no single default project, so
2673
2899
  * the bare list is ambiguous: fail fast client-side with a BreadthRequiredError that
2674
2900
  * names the next call, matching the MCP surface, instead of round-tripping to a 400.
2675
2901
  * Use `extrovert.projects.inboxes.list("<project_id>")` or `"-"` (org subtree) for
2676
- * an org key. The check is advisory the server stays authoritative.
2902
+ * an org key. The check is advisory: the server stays authoritative.
2677
2903
  */
2678
2904
  list(params?: ListInboxesParams, signal?: AbortSignal): Promise<Page<Inbox>>;
2679
2905
  /** Fetch a single inbox and return an ergonomic handle bound to it. */
@@ -2694,7 +2920,7 @@ declare class Inboxes {
2694
2920
  delete(address: string, signal?: AbortSignal): Promise<void>;
2695
2921
  }
2696
2922
  /**
2697
- * `extrovert.messages` read a message, fetch its raw bytes, mark it read.
2923
+ * `extrovert.messages`: read a message, fetch its raw bytes, mark it read.
2698
2924
  *
2699
2925
  * Reply and forward are inbox-scoped (the server resolves the parent and derives
2700
2926
  * recipients), so they live on the {@link InboxHandle} (`inbox.reply(...)`,
@@ -2739,21 +2965,27 @@ declare class Messages {
2739
2965
  getAttachment(inbox: string, messageId: string, attachmentId: string, signal?: AbortSignal): Promise<AttachmentDownload>;
2740
2966
  }
2741
2967
  /**
2742
- * `extrovert.threads` fetch a conversation thread (with its messages) by id,
2743
- * scoped to its owning inbox.
2968
+ * `extrovert.threads`: list, search, read, reply to, and delete conversations,
2969
+ * scoped to their owning inbox.
2744
2970
  */
2745
2971
  declare class Threads {
2746
2972
  private readonly ctx;
2747
2973
  constructor(ctx: ResourceContext);
2974
+ /** List conversations newest-active first. Pass `next_cursor` back as `cursor` for the next page. */
2975
+ list(inbox: string, params?: ListThreadsParams, signal?: AbortSignal): Promise<Page<Thread>>;
2976
+ /** Search thread subjects, snippets, and participants. Cursor pagination matches {@link list}. */
2977
+ search(inbox: string, params: SearchMessagesParams, signal?: AbortSignal): Promise<Page<Thread>>;
2748
2978
  /** Fetch one thread (+ its messages, oldest-first) by id under its owning inbox address. */
2749
2979
  get(inbox: string, threadId: string, signal?: AbortSignal): Promise<ThreadDetail>;
2980
+ /** Reply in a thread; recipients and RFC reply headers are derived server-side. */
2981
+ reply(inbox: string, req: ReplyRequest, signal?: AbortSignal): Promise<SendOutcome>;
2750
2982
  /**
2751
2983
  * Delete an entire thread (every message): move to Trash (default) or
2752
2984
  * permanently remove when `expunge` is true. `inbox` is the owning address.
2753
2985
  */
2754
2986
  delete(inbox: string, threadId: string, expunge?: boolean, signal?: AbortSignal): Promise<DeleteResult>;
2755
2987
  }
2756
- /** `extrovert.webhooks` register / list / get / update / delete HMAC-signed inbound webhooks. */
2988
+ /** `extrovert.webhooks`: register / list / get / update / delete HMAC-signed inbound webhooks. */
2757
2989
  declare class Webhooks {
2758
2990
  private readonly ctx;
2759
2991
  constructor(ctx: ResourceContext);
@@ -2774,7 +3006,7 @@ declare class Webhooks {
2774
3006
  delete(webhookId: string, signal?: AbortSignal): Promise<void>;
2775
3007
  }
2776
3008
  /**
2777
- * `extrovert.contactLists` per-inbox allow/block lists of addresses/domains.
3009
+ * `extrovert.contactLists`: per-inbox allow/block lists of addresses/domains.
2778
3010
  * A `block` entry rejects a send to a matching recipient; once an `allow` entry
2779
3011
  * exists for an inbox, sends from it are restricted to matching recipients
2780
3012
  * (allowlist mode). Entries are addressable by their opaque id (`lst_…`).
@@ -2790,12 +3022,12 @@ declare class ContactLists {
2790
3022
  delete(inbox: string, entryId: string, signal?: AbortSignal): Promise<void>;
2791
3023
  }
2792
3024
  /**
2793
- * `extrovert.suppressions` recipient opt-outs (list-unsubscribe). A recipient
3025
+ * `extrovert.suppressions`: recipient opt-outs (list-unsubscribe). A recipient
2794
3026
  * that has unsubscribed cannot be mailed by this org: a send to them is rejected
2795
3027
  * with `recipient_suppressed` ({@link RecipientSuppressedError}). Use `precheck`
2796
3028
  * before composing to skip a would-be-rejected recipient, `list` to browse the
2797
3029
  * org's opt-outs, and `revoke` (reason required, audit-logged) to re-enable a
2798
- * recipient. All reads/writes are scoped to the caller's OWN org a
3030
+ * recipient. All reads/writes are scoped to the caller's OWN org: a
2799
3031
  * platform-global or shared-domain opt-out is never surfaced here.
2800
3032
  */
2801
3033
  declare class Suppressions {
@@ -2803,7 +3035,7 @@ declare class Suppressions {
2803
3035
  constructor(ctx: ResourceContext);
2804
3036
  /**
2805
3037
  * Pre-check whether the caller's org already suppresses a recipient, BEFORE
2806
- * composing. `suppressed: true` means a send to them would be rejected skip
3038
+ * composing. `suppressed: true` means a send to them would be rejected: skip
2807
3039
  * that recipient. Returns the matching org rows too (never a global/shared row).
2808
3040
  */
2809
3041
  precheck(recipient: string, signal?: AbortSignal): Promise<SuppressionPrecheck>;
@@ -2817,25 +3049,36 @@ declare class Suppressions {
2817
3049
  revoke(id: string, reason: string, signal?: AbortSignal): Promise<SuppressionEntry>;
2818
3050
  }
2819
3051
  /**
2820
- * `extrovert.domains` the customer's domains (privileged; the agent key must
2821
- * carry the `domain:manage` scope). Onboard (shared | ns_delegated | manual |
2822
- * purchased), read status + the DNS records to set inline, trigger/refresh
2823
- * verification, and offboard. `mode: "purchased"` spends money at the registrar and
2824
- * ADDITIONALLY requires the explicit, default-off `domain:purchase` scope (and is
2825
- * capped by the org/project purchased-domain plan limit). Set `scope: "project"` to
2826
- * bind the domain to the key's project; it defaults to `org` (org-shared).
3052
+ * `extrovert.domains`: read with domain:read or domain:manage; changes require
3053
+ * domain:manage. Add delegated inbox domains the customer
3054
+ * controls, read status + nameserver records inline, trigger/refresh
3055
+ * verification, and offboard. New registrations use `extrovert.commerce`: quote
3056
+ * first, create a request, then poll its status. Set `scope: "project"` to bind a
3057
+ * customer-controlled domain to the key's project; it defaults to `org`.
2827
3058
  */
2828
3059
  declare class Domains {
2829
3060
  private readonly ctx;
2830
3061
  constructor(ctx: ResourceContext);
2831
3062
  /** List the customer's onboarded domains and their status. */
2832
- list(signal?: AbortSignal): Promise<Page<Domain>>;
2833
- /** Get one domain's detail + verification status + the DNS records to set, inline. */
3063
+ list(paramsOrSignal?: {
3064
+ page?: string;
3065
+ limit?: number;
3066
+ } | AbortSignal, signal?: AbortSignal): Promise<Page<Domain>>;
3067
+ /** Get one domain's detail, verification status, and nameserver records. */
2834
3068
  get(domain: string, signal?: AbortSignal): Promise<Domain>;
2835
- /**
2836
- * Onboard (add) a domain. `mode` defaults to ns_delegated. `mode: "purchased"`
2837
- * requires the `domain:purchase` scope (in addition to `domain:manage`). Returns
2838
- * the record set / NS instruction.
3069
+ /** Wait up to 50 seconds, then return an explicit resumable outcome. No DNS writes. */
3070
+ wait(domain: string, options?: {
3071
+ timeout_seconds?: number;
3072
+ signal?: AbortSignal;
3073
+ }): Promise<DomainWaitResult>;
3074
+ /** Resume durable updates for this domain using the previous next_cursor as after. */
3075
+ events(domain: string, params?: {
3076
+ after?: string;
3077
+ limit?: number;
3078
+ }, signal?: AbortSignal): Promise<DomainStatusEventPage>;
3079
+ /**
3080
+ * Add a delegated inbox domain the customer controls. Returns the nameserver
3081
+ * records to publish and never spends money.
2839
3082
  */
2840
3083
  onboard(req: OnboardDomainRequest, signal?: AbortSignal): Promise<Domain>;
2841
3084
  /** Trigger or refresh verification for a domain; returns its (possibly advanced) status. */
@@ -2849,7 +3092,29 @@ declare class Domains {
2849
3092
  offboard(domain: string, signal?: AbortSignal): Promise<DomainOffboard>;
2850
3093
  }
2851
3094
  /**
2852
- * `extrovert.reviews` the Review Loop (HITL) agent-plane reads. A sending agent
3095
+ * `extrovert.commerce`: quote, request, cancel, and poll financial operations. Agents
3096
+ * can never approve a request through this resource; approval is a human console
3097
+ * action. Every create requires a stable idempotency key.
3098
+ */
3099
+ declare class Commerce {
3100
+ private readonly ctx;
3101
+ constructor(ctx: ResourceContext);
3102
+ private requireIdempotencyKey;
3103
+ /** Quote a domain without purchasing, reserving, or approving it. */
3104
+ quoteDomain(req: QuoteDomainRequest, signal?: AbortSignal): Promise<DomainQuote>;
3105
+ /** Create a durable domain-purchase request for human approval. */
3106
+ requestDomainPurchase(req: RequestDomainPurchaseRequest, signal?: AbortSignal): Promise<CommerceRequest>;
3107
+ /** Create a durable plan-upgrade or downgrade request for human approval. */
3108
+ requestPlanChange(req: RequestPlanChangeRequest, signal?: AbortSignal): Promise<CommerceRequest>;
3109
+ /** Poll one request's exact blockers, approval URL, and next-action guidance. */
3110
+ get(requestId: string, signal?: AbortSignal): Promise<CommerceRequest>;
3111
+ /** Withdraw this agent's request while its durable state still permits cancellation. */
3112
+ cancel(requestId: string, signal?: AbortSignal): Promise<CommerceRequest>;
3113
+ /** List visible commerce requests using the API's opaque page token. */
3114
+ list(params?: ListCommerceRequestsParams, signal?: AbortSignal): Promise<Page<CommerceRequest>>;
3115
+ }
3116
+ /**
3117
+ * `extrovert.reviews`: the Review Loop (HITL) agent-plane reads. A sending agent
2853
3118
  * monitors its submissions in the human-review queue: list/get a review request and
2854
3119
  * read its append-only thread of turns (intent, drafts, human comments/edits/
2855
3120
  * decisions, captured diffs). Submitting FOR review rides `inbox.send` /
@@ -2859,7 +3124,7 @@ declare class Domains {
2859
3124
  declare class Reviews {
2860
3125
  private readonly ctx;
2861
3126
  /**
2862
- * `extrovert.reviews.events` the Review Loop (HITL) realtime plane: drain,
3127
+ * `extrovert.reviews.events`: the Review Loop (HITL) realtime plane: drain,
2863
3128
  * long-poll, and ack the durable nudge queue (the AUTHORITATIVE liveness source;
2864
3129
  * SSE/webhook are best-effort fast paths on top of it).
2865
3130
  */
@@ -2874,20 +3139,20 @@ declare class Reviews {
2874
3139
  /**
2875
3140
  * Get the human's assembled feedback (M5): the diff + comments + decision + the
2876
3141
  * rules born from this review. Read it after a rejected/edited nudge to learn what
2877
- * the human wanted. $0 LLM pure assembly on our side.
3142
+ * the human wanted. $0 LLM: pure assembly on our side.
2878
3143
  */
2879
3144
  feedback(reviewId: string, signal?: AbortSignal): Promise<ReviewFeedback>;
2880
3145
  /**
2881
3146
  * Post a chat turn on a review's thread (M5): an agent question to the human
2882
3147
  * reviewer; flips in_review -> chatting on the first turn. Idempotent on the
2883
- * optional `idempotencyKey` (the `Idempotency-Key` header). $0 LLM you compose it.
3148
+ * optional `idempotencyKey` (the `Idempotency-Key` header). $0 LLM: you compose it.
2884
3149
  */
2885
3150
  chat(reviewId: string, req: PostReviewChatRequest, idempotencyKey?: string, signal?: AbortSignal): Promise<Review>;
2886
3151
  /**
2887
3152
  * Post a new agent draft under a parent_revision CAS (M5; D17). parent_revision
2888
3153
  * must equal the draft's current revision, else a 409 STALE with NO mutation (the
2889
- * human always wins re-read, re-apply, retry). On success the draft is re-rendered
2890
- * in place (revision++) and returns to needs_review. $0 LLM you compose the redraft.
3154
+ * human always wins: re-read, re-apply, retry). On success the draft is re-rendered
3155
+ * in place (revision++) and returns to needs_review. $0 LLM: you compose the redraft.
2891
3156
  */
2892
3157
  revise(reviewId: string, req: SubmitRevisionRequest, signal?: AbortSignal): Promise<Review>;
2893
3158
  /**
@@ -2900,9 +3165,9 @@ declare class Reviews {
2900
3165
  * assert "I reviewed this against rules vX and no change is needed", advancing the
2901
3166
  * draft's composed_* versions with no new draft, no revision bump, no nudge. A
2902
3167
  * born-stale draft re-stamped to the current version becomes current-enough and
2903
- * releasable on the next reconciliation sweep the cheap counterpart to revise().
3168
+ * releasable on the next reconciliation sweep: the cheap counterpart to revise().
2904
3169
  * against_version above the category's current rules-version is 400; a terminal draft
2905
- * 409s. $0 LLM you judged.
3170
+ * 409s. $0 LLM: you judged.
2906
3171
  */
2907
3172
  restamp(reviewId: string, req: RestampReviewRequest, signal?: AbortSignal): Promise<Review>;
2908
3173
  /**
@@ -2917,22 +3182,22 @@ declare class Reviews {
2917
3182
  decisionContext(reviewId: string, signal?: AbortSignal): Promise<ReviewDecisionContext>;
2918
3183
  /**
2919
3184
  * Submit a reviewer decision (M8 Slice B; reviewer_decide, D5/§9). approve/edit → the
2920
- * PLATFORM ACS-sends with the COMPOSER's credentials (the reviewer NEVER holds
2921
- * mailbox:send on an inbox it doesn't own the credential boundary); reject → back to
3185
+ * PLATFORM sends with the COMPOSER's credentials (the reviewer NEVER holds
3186
+ * mailbox:send on an inbox it doesn't own: the credential boundary); reject → back to
2922
3187
  * the composer (needs_review, hop_count++); escalate → the human queue. revision/
2923
- * version are the CAS (409 STALE on mismatch, NO mutation the human always wins,
3188
+ * version are the CAS (409 STALE on mismatch, NO mutation: the human always wins,
2924
3189
  * D17). The two circuit breakers (hop_count ≥ max_hops, or the hard review_deadline)
2925
- * FORCE a reject to the human regardless of intent `forced_by_breaker` names it. $0
2926
- * LLM you judged; we route, send, and enforce the breakers.
3190
+ * FORCE a reject to the human regardless of intent: `forced_by_breaker` names it. $0
3191
+ * LLM: you judged; we route, send, and enforce the breakers.
2927
3192
  */
2928
3193
  decide(reviewId: string, req: ReviewerDecisionRequest, signal?: AbortSignal): Promise<ReviewerDecisionResult>;
2929
3194
  }
2930
3195
  /**
2931
- * `extrovert.reviews.events` drain / long-poll / ack the durable review nudge
3196
+ * `extrovert.reviews.events`: drain / long-poll / ack the durable review nudge
2932
3197
  * queue (spec §5.9). `list` is a non-blocking, side-effect-free drain of the next
2933
3198
  * un-acked nudges in FIFO seq order (strict per review); `wait` long-polls
2934
3199
  * (~25–55s) for the next one; `ack` advances the per-(agent, review) cursor
2935
- * monotonically (idempotent re-acking an older seq is a no-op).
3200
+ * monotonically (idempotent: re-acking an older seq is a no-op).
2936
3201
  */
2937
3202
  declare class ReviewEvents {
2938
3203
  private readonly ctx;
@@ -2945,10 +3210,10 @@ declare class ReviewEvents {
2945
3210
  ack(req: AckReviewEventRequest, signal?: AbortSignal): Promise<AckReviewEventResult>;
2946
3211
  }
2947
3212
  /**
2948
- * `extrovert.categories` the Review Loop category registry (D9/D10). Browse and
3213
+ * `extrovert.categories`: the Review Loop category registry (D9/D10). Browse and
2949
3214
  * MATCH an existing category before composing (like a skills registry), or propose
2950
3215
  * a new one. Categories are CUSTOMER-scoped and agent-attributed (the deliberate
2951
- * cross-agent-404 exception); identity is opaque cat_ ids nothing keys on the
3216
+ * cross-agent-404 exception); identity is opaque cat_ ids: nothing keys on the
2952
3217
  * name, so renames never break a reference. `match` is a pure lexical filter (NO
2953
3218
  * LLM on our side); the agent does the semantic matching. Merging / deleting a
2954
3219
  * category is a human (console) action, not exposed here (D17).
@@ -2962,12 +3227,12 @@ declare class Categories {
2962
3227
  get(categoryId: string, signal?: AbortSignal): Promise<Category>;
2963
3228
  /** Propose a new category; it stands immediately and writes a create audit row. */
2964
3229
  propose(req: ProposeCategoryRequest, signal?: AbortSignal): Promise<Category>;
2965
- /** Rename / re-describe a category metadata only (D10). */
3230
+ /** Rename / re-describe a category: metadata only (D10). */
2966
3231
  update(categoryId: string, req: UpdateCategoryRequest, signal?: AbortSignal): Promise<Category>;
2967
3232
  /**
2968
3233
  * Read the effective risk dial (D4/D12): the account default + every category's
2969
3234
  * overrides (each with its resolved effective value; null override = inherit).
2970
- * Read-only agents read but NEVER flip the dial; setting it is a human (console)
3235
+ * Read-only: agents read but NEVER flip the dial; setting it is a human (console)
2971
3236
  * action (D16).
2972
3237
  */
2973
3238
  riskDial(signal?: AbortSignal): Promise<RiskDial>;
@@ -2979,14 +3244,14 @@ declare class Categories {
2979
3244
  graduationStatus(categoryId: string, signal?: AbortSignal): Promise<GraduationStatus>;
2980
3245
  /**
2981
3246
  * Propose graduating a category (D16/D6): RECORDS the request (durable evidence) and
2982
- * returns the current gate status. It does NOT change the category state flipping
3247
+ * returns the current gate status. It does NOT change the category state: flipping
2983
3248
  * the bit is a human (console) action; an agent only proposes.
2984
3249
  */
2985
3250
  proposeGraduation(categoryId: string, req?: ProposeGraduationRequest, signal?: AbortSignal): Promise<GraduationStatus>;
2986
3251
  /**
2987
3252
  * Read the D19/§8 backlog-reconciliation status: how many of the category's QUEUED
2988
3253
  * drafts are stale vs current-enough against the current rules-version (a pure
2989
- * integer compare, $0 LLM). Read-only you READ the picture; the human (console
3254
+ * integer compare, $0 LLM). Read-only: you READ the picture; the human (console
2990
3255
  * scan-backlog) or the graduate/rule-change hooks TRIGGER the actual reconciliation
2991
3256
  * sweep that releases current-enough drafts and nudges stale ones to redraft.
2992
3257
  */
@@ -3002,39 +3267,41 @@ declare class Categories {
3002
3267
  pacingState(categoryId: string, signal?: AbortSignal): Promise<CategoryPacingState>;
3003
3268
  }
3004
3269
  /**
3005
- * `extrovert.rules` the Review Loop writing-rule store + house-style + the §7
3270
+ * `extrovert.rules`: the Review Loop writing-rule store + house-style + the §7
3006
3271
  * precedence ladder + audit/undo (D2/D11). ANY agent in the customer may write,
3007
- * edit, promote, retire, and undo rules (the deliberate cross-agent exception the
3272
+ * edit, promote, retire, and undo rules (the deliberate cross-agent exception: the
3008
3273
  * shared house-style is the whole pitch). `get()` returns the ORDERED active rule
3009
3274
  * set with the precedence ladder applied SERVER-SIDE (NO LLM on our side); the agent
3010
3275
  * reconciles the list semantically. Rules are append-only by supersession; undo
3011
3276
  * restores the prior version as a forward 'restore' supersession. Identity is opaque
3012
- * rule_/rln_/udo_ ids nothing keys on a name.
3277
+ * rule_/rln_/udo_ ids: nothing keys on a name.
3013
3278
  */
3014
3279
  declare class Rules {
3015
3280
  private readonly ctx;
3281
+ /** Learn category or organization house rules from verified human review feedback. */
3282
+ learnFromReview(reviewId: string, req: LearnReviewRuleRequest, signal?: AbortSignal): Promise<LearnedReviewRule>;
3016
3283
  constructor(ctx: ResourceContext);
3017
3284
  /** Get the ORDERED active rule set (precedence ladder applied; NO LLM). */
3018
3285
  get(params?: GetRulesParams, signal?: AbortSignal): Promise<RuleSnapshot>;
3019
3286
  /**
3020
3287
  * Save / edit a rule (append-only by supersession; D11). An agent-plane save is
3021
3288
  * ALWAYS project-layer: the saved rule's `rule_layer` is `project`, bound to the
3022
- * key's project. Agents cannot author org-layer / house-style (`rule_layer:"org"`)
3023
- * rules in v1 that is a console/admin action.
3289
+ * key's project. For org-layer house rules use learnFromReview with an authenticated human source; this method cannot author (`rule_layer:"org"`)
3290
+ * rules in v1: that is a console/admin action.
3024
3291
  */
3025
3292
  save(req: SaveRuleRequest, signal?: AbortSignal): Promise<Rule>;
3026
3293
  /** Promote a rule between the category and general/house-style layers. */
3027
3294
  promote(ruleId: string, toScope: "general" | "category", signal?: AbortSignal): Promise<Rule>;
3028
- /** Retire a rule soft delete; the history survives as training data. */
3295
+ /** Retire a rule: soft delete; the history survives as training data. */
3029
3296
  retire(ruleId: string, signal?: AbortSignal): Promise<Rule>;
3030
3297
  /** Read the rule/category change audit log (the safety net, D11). */
3031
3298
  audit(params?: GetRuleAuditParams, signal?: AbortSignal): Promise<Page<RuleAuditEntry>>;
3032
- /** Undo a rule change by its audit-row id (udo_…) restore the prior version. */
3299
+ /** Undo a rule change by its audit-row id (udo_…): restore the prior version. */
3033
3300
  undo(udoId: string, signal?: AbortSignal): Promise<Rule>;
3034
3301
  }
3035
3302
 
3036
3303
  /**
3037
- * ExtrovertClient the entry point.
3304
+ * ExtrovertClient - the entry point.
3038
3305
  *
3039
3306
  * ```ts
3040
3307
  * import { Extrovert } from "@extrovert.dev/sdk";
@@ -3085,28 +3352,30 @@ interface ExtrovertClientOptions {
3085
3352
  mockBackend?: MockBackend;
3086
3353
  }
3087
3354
  declare class ExtrovertClient {
3088
- /** `extrovert.inboxes` create / list / get / update / delete inboxes. */
3355
+ /** `extrovert.inboxes` - create / list / get / update / delete inboxes. */
3089
3356
  readonly inboxes: Inboxes;
3090
- /** `extrovert.messages` read a message, reply to it (threaded). */
3357
+ /** `extrovert.messages` - read a message, reply to it (threaded). */
3091
3358
  readonly messages: Messages;
3092
- /** `extrovert.threads` fetch a conversation thread. */
3359
+ /** `extrovert.threads` - fetch a conversation thread. */
3093
3360
  readonly threads: Threads;
3094
- /** `extrovert.webhooks` register HMAC-signed inbound webhooks. */
3361
+ /** `extrovert.webhooks` - register HMAC-signed inbound webhooks. */
3095
3362
  readonly webhooks: Webhooks;
3096
- /** `extrovert.contactLists` per-inbox allow/block lists of addresses/domains. */
3363
+ /** `extrovert.contactLists` - per-inbox allow/block lists of addresses/domains. */
3097
3364
  readonly contactLists: ContactLists;
3098
- /** `extrovert.suppressions` recipient opt-outs (list-unsubscribe); precheck/list/revoke. */
3365
+ /** `extrovert.suppressions` - recipient opt-outs (list-unsubscribe); precheck/list/revoke. */
3099
3366
  readonly suppressions: Suppressions;
3100
- /** `extrovert.domains` the customer's domains (privileged; domain:manage scope). */
3367
+ /** `extrovert.domains` - domain readiness and setup (domain:read or domain:manage to read; domain:manage to change). */
3101
3368
  readonly domains: Domains;
3102
- /** `extrovert.reviews` the Review Loop (HITL) agent-plane reads. */
3369
+ /** `extrovert.commerce` - quote/request/cancel/poll financial actions; no agent approval methods. */
3370
+ readonly commerce: Commerce;
3371
+ /** `extrovert.reviews` - the Review Loop (HITL) agent-plane reads. */
3103
3372
  readonly reviews: Reviews;
3104
- /** `extrovert.categories` the Review Loop category registry (browse/propose/curate). */
3373
+ /** `extrovert.categories` - the Review Loop category registry (browse/propose/curate). */
3105
3374
  readonly categories: Categories;
3106
- /** `extrovert.rules` the Review Loop writing-rule store + house-style + audit/undo. */
3375
+ /** `extrovert.rules` - the Review Loop writing-rule store + house-style + audit/undo. */
3107
3376
  readonly rules: Rules;
3108
3377
  /**
3109
- * `extrovert.projects` the CANONICAL project-scoped chain. The headline is
3378
+ * `extrovert.projects` - the CANONICAL project-scoped chain. The headline is
3110
3379
  * `extrovert.projects.inboxes.*` (create/list/get/update/delete/send/...), keyed by
3111
3380
  * the opaque `inbox_id` and scoped to a `{project_id}` path (or `-` for the org
3112
3381
  * wildcard on an org-tier key). The bare `extrovert.inboxes` surface is curl sugar
@@ -3122,7 +3391,7 @@ declare class ExtrovertClient {
3122
3391
  readonly apiVersion: string;
3123
3392
  /**
3124
3393
  * The CEILING tier derived from the configured agent key prefix (`org` | `project`
3125
- * | `inbox` | `unknown`). Advisory client-side hint only the server is the source
3394
+ * | `inbox` | `unknown`). Advisory client-side hint only - the server is the source
3126
3395
  * of truth. Lets an app branch (e.g. require a project pick for an org-tier key).
3127
3396
  */
3128
3397
  readonly keyTier: KeyTier;
@@ -3130,18 +3399,20 @@ declare class ExtrovertClient {
3130
3399
  private readonly handleOptions;
3131
3400
  constructor(options?: ExtrovertClientOptions);
3132
3401
  /**
3133
- * Redeem an enrollment token (`pk_enroll_...`) and mint a scoped agent key.
3402
+ * Redeem an enrollment token (`pk_enroll_...`) and issue a scoped agent key.
3134
3403
  *
3135
3404
  * Idempotent on `agent_handle`: redeeming twice with the same handle returns the same agent.
3136
- * Returns the raw `EnrollResponse` to immediately use the minted key, prefer
3405
+ * Returns the raw `EnrollResponse` - to immediately use the issued key, prefer
3137
3406
  * {@link ExtrovertClient.enrolled}.
3138
3407
  */
3139
3408
  enroll(req: EnrollRequest, signal?: AbortSignal): Promise<EnrollResponse>;
3140
3409
  /**
3141
- * Grab a free account in one unauthenticated call (Slice E). Provisions a tenant
3142
- * + a first inbox and returns a LIMITED-scope (read-only) agent key; a one-time
3143
- * code is emailed to `human_email`. Call {@link verify} with the code to unlock
3144
- * full scopes. Idempotent on `human_email`: re-calling rotates the key + resends.
3410
+ * Request a free account in one unauthenticated call. When free signup is
3411
+ * enabled, this provisions a tenant plus a first inbox and returns a
3412
+ * verification-only agent key. That key can only call {@link verify}; it cannot
3413
+ * read or send mail. A one-time code is emailed to `human_email`. Call
3414
+ * {@link verify} with the code to activate the account and receive full scopes.
3415
+ * Idempotent on `human_email`: re-calling rotates the key and resends the code.
3145
3416
  * When free signup is paused, this throws an `ApiError` with status 403 and
3146
3417
  * code `signup_disabled` without creating account state.
3147
3418
  */
@@ -3158,15 +3429,15 @@ declare class ExtrovertClient {
3158
3429
  /** Introspect the principal behind the current key (`GET /v1/auth/me`). */
3159
3430
  whoami(signal?: AbortSignal): Promise<WhoAmI>;
3160
3431
  /**
3161
- * Poll the status of an async job (`GET /v1/jobs/{job_id}`) currently only
3432
+ * Poll the status of an async job (`GET /v1/jobs/{job_id}`) - currently only
3162
3433
  * the domain-offboard teardown started by {@link Domains.offboard} enqueues
3163
3434
  * one. `status` is terminal on succeeded/failed/cancelled; keep polling
3164
3435
  * otherwise. An unknown or foreign job id is a {@link NotFoundError}.
3165
3436
  */
3166
3437
  getJob(jobId: string, signal?: AbortSignal): Promise<Job>;
3167
3438
  /**
3168
- * Redeem an enrollment token and return a *new* client already authenticated with the minted
3169
- * agent key the natural "redeem then act" flow for an agent.
3439
+ * Redeem an enrollment token and return a *new* client already authenticated with the issued
3440
+ * agent key - the natural "redeem then act" flow for an agent.
3170
3441
  *
3171
3442
  * ```ts
3172
3443
  * const bootstrap = new Extrovert({ apiKey: enrollmentToken });
@@ -3182,7 +3453,7 @@ declare class ExtrovertClient {
3182
3453
  enrollment: EnrollResponse;
3183
3454
  }>;
3184
3455
  /**
3185
- * Get an ergonomic handle to an existing inbox by address without an extra round-trip. Use this
3456
+ * Get an ergonomic handle to an existing inbox by address - without an extra round-trip. Use this
3186
3457
  * when you already know the address (e.g. from a previous create) and want to send/wait/reply.
3187
3458
  * Call {@link InboxHandle.refresh} to load the full record.
3188
3459
  */
@@ -3225,7 +3496,7 @@ declare class ExtrovertClient {
3225
3496
  */
3226
3497
  /**
3227
3498
  * The CLOSED problem code enum (mirrors `components.schemas.Problem.code` in the
3228
- * frozen OpenAPI). Adding a member is a contract change keep it in lockstep with
3499
+ * frozen OpenAPI). Adding a member is a contract change - keep it in lockstep with
3229
3500
  * the Go `ProblemCode` enum.
3230
3501
  */
3231
3502
  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";
@@ -3238,11 +3509,11 @@ declare const PROBLEM_CODES: readonly ProblemCode[];
3238
3509
  * compare-and-set (`stale`) and a redraft built against an older rule high-water
3239
3510
  * (`born_stale`) describe a situation a retry can fix, and each only a bounded
3240
3511
  * number of times (re-read, re-apply on top of the other party's change,
3241
- * resubmit). `wrong_state` means the verb is wrong, not the timing read the
3512
+ * resubmit). `wrong_state` means the verb is wrong, not the timing - read the
3242
3513
  * `allowed_action` hints and pick another one. `terminal` means the review is
3243
3514
  * finished forever; a `front_run_next` nudge is already waiting on the queue
3244
3515
  * with the outcome. `send_needs_reconciliation` means a delivery attempt is
3245
- * unconfirmed resending is precisely how a message goes out twice.
3516
+ * unconfirmed - resending is precisely how a message goes out twice.
3246
3517
  *
3247
3518
  * `intent_required` is listed false because retrying the SAME bytes fails
3248
3519
  * identically: the fix is to ADD an `intent` and send a different request. The
@@ -3347,38 +3618,38 @@ declare class ApiError extends Error {
3347
3618
  /** True for 5xx responses (server errors that may succeed on retry). */
3348
3619
  get isServerError(): boolean;
3349
3620
  }
3350
- /** 401 the agent key / enrollment token was missing, malformed, expired, or revoked. */
3621
+ /** 401 - the agent key / enrollment token was missing, malformed, expired, or revoked. */
3351
3622
  declare class AuthenticationError extends ApiError {
3352
3623
  }
3353
- /** 403 authenticated, but the key's scopes don't permit this action (capability denied). */
3624
+ /** 403 - authenticated, but the key's scopes don't permit this action (capability denied). */
3354
3625
  declare class PermissionError extends ApiError {
3355
3626
  }
3356
3627
  /**
3357
- * 403 `forbidden_scope` the call is outside the key's CEILING (e.g. a non-org key
3358
- * on the org-wide wildcard, or a mint that would escalate). A redesign-specific
3628
+ * 403 `forbidden_scope` - the call is outside the key's CEILING (e.g. a non-org key
3629
+ * on the org-wide wildcard, or an issuance that would escalate). A redesign-specific
3359
3630
  * subclass of {@link PermissionError} so existing `instanceof PermissionError`
3360
3631
  * branches keep working.
3361
3632
  */
3362
3633
  declare class ForbiddenScopeError extends PermissionError {
3363
3634
  }
3364
3635
  /**
3365
- * 400 `breadth_required` an org-tier key/operator issued a bare list that needs a
3636
+ * 400 `breadth_required` - an org-tier key/operator issued a bare list that needs a
3366
3637
  * breadth pick; the problem `errors`/`detail` name the next call
3367
3638
  * (`/v1/projects/{id}/inboxes` or `/v1/projects/-/inboxes`).
3368
3639
  */
3369
3640
  declare class BreadthRequiredError extends ApiError {
3370
3641
  }
3371
- /** 404 the inbox, message, thread, or webhook does not exist (or isn't visible to this tenant). */
3642
+ /** 404 - the inbox, message, thread, or webhook does not exist (or isn't visible to this tenant). */
3372
3643
  declare class NotFoundError extends ApiError {
3373
3644
  }
3374
- /** 409 a conflicting state, e.g. an enrollment token that already minted its max of N inboxes. */
3645
+ /** 409 - a conflicting state, e.g. an enrollment token that already created its maximum number of inboxes. */
3375
3646
  declare class ConflictError extends ApiError {
3376
3647
  }
3377
- /** 422 the request body failed validation; see `body.error.details`. */
3648
+ /** 422 - the request body failed validation; see `body.error.details`. */
3378
3649
  declare class ValidationError extends ApiError {
3379
3650
  }
3380
3651
  /**
3381
- * 422 `recipient_suppressed` a send/reply/forward was rejected because one or
3652
+ * 422 `recipient_suppressed` - a send/reply/forward was rejected because one or
3382
3653
  * more recipients have opted out (list-unsubscribe / suppression). The whole send
3383
3654
  * is rejected (never a silent partial drop). {@link suppressedRecipients} lists the
3384
3655
  * exact addresses to drop; retry the send without them. The scope/origin of the
@@ -3386,12 +3657,12 @@ declare class ValidationError extends ApiError {
3386
3657
  * existing `instanceof ValidationError` branches keep working.
3387
3658
  */
3388
3659
  declare class RecipientSuppressedError extends ValidationError {
3389
- /** The recipient addresses that are suppressed drop these and retry. */
3660
+ /** The recipient addresses that are suppressed - drop these and retry. */
3390
3661
  readonly suppressedRecipients: string[];
3391
3662
  constructor(args: ConstructorParameters<typeof ApiError>[0]);
3392
3663
  }
3393
3664
  /**
3394
- * 422 `intent_required` the inbox's resolved review policy requires a human to
3665
+ * 422 `intent_required` - the inbox's resolved review policy requires a human to
3395
3666
  * see this message before it goes out, and the request carried no `intent`.
3396
3667
  *
3397
3668
  * **Nothing was sent and nothing was queued.** The server checks this before it
@@ -3400,7 +3671,7 @@ declare class RecipientSuppressedError extends ValidationError {
3400
3671
  * splice in, and the human-readable remediation (the full recipe, including how
3401
3672
  * to monitor the resulting review) is on `.message` / `.problem.detail`.
3402
3673
  *
3403
- * Under `require_review` the default for every account this is the FIRST
3674
+ * Under `require_review` - the default for every account - this is the FIRST
3404
3675
  * thing most agents hit. Read `effective_review_policy` on
3405
3676
  * `GET /v1/inboxes/{id}` once at start-up and compose an intent up front instead
3406
3677
  * of learning the policy by being refused. A subclass of {@link ValidationError}
@@ -3409,7 +3680,7 @@ declare class RecipientSuppressedError extends ValidationError {
3409
3680
  declare class IntentRequiredError extends ValidationError {
3410
3681
  /** The resolved review policy, e.g. `require_review`. */
3411
3682
  readonly policy: string | undefined;
3412
- /** Where the policy came from a per-inbox override or the account default. */
3683
+ /** Where the policy came from - a per-inbox override or the account default. */
3413
3684
  readonly policySource: string | undefined;
3414
3685
  /** Literal JSON to merge into the original request body, then retry once. */
3415
3686
  readonly retryWith: string | undefined;
@@ -3427,7 +3698,7 @@ declare class IntentRequiredError extends ValidationError {
3427
3698
  declare class ReviewConflictError extends ConflictError {
3428
3699
  /** The review's CURRENT state (`needs_review`, `approved`, `sent`, …). */
3429
3700
  readonly currentState: string | undefined;
3430
- /** The current revision pass it as `parent_revision` on a legal retry. */
3701
+ /** The current revision - pass it as `parent_revision` on a legal retry. */
3431
3702
  readonly currentRevision: number | undefined;
3432
3703
  /** The current row version (the optional belt-and-braces CAS). */
3433
3704
  readonly currentVersion: number | undefined;
@@ -3436,13 +3707,13 @@ declare class ReviewConflictError extends ConflictError {
3436
3707
  constructor(args: ConstructorParameters<typeof ApiError>[0]);
3437
3708
  /**
3438
3709
  * Whether retrying the same call could ever succeed. False for every subclass
3439
- * except {@link StaleError} and {@link BornStaleError} and true there only
3710
+ * except {@link StaleError} and {@link BornStaleError} - and true there only
3440
3711
  * after re-reading and re-applying on top of the other party's change.
3441
3712
  */
3442
3713
  get isRetryable(): boolean;
3443
3714
  }
3444
3715
  /**
3445
- * 409 `stale` the `(revision[, version])` you named is no longer current
3716
+ * 409 `stale` - the `(revision[, version])` you named is no longer current
3446
3717
  * because a human or reviewer moved the draft. **Nothing was mutated.**
3447
3718
  *
3448
3719
  * The one genuinely retryable conflict, and bounded (≤3): re-read the draft and
@@ -3455,7 +3726,7 @@ declare class StaleError extends ReviewConflictError {
3455
3726
  get isRetryable(): boolean;
3456
3727
  }
3457
3728
  /**
3458
- * 409 `wrong_state` this VERB is illegal from the review's current state, but
3729
+ * 409 `wrong_state` - this VERB is illegal from the review's current state, but
3459
3730
  * the draft is still live.
3460
3731
  *
3461
3732
  * **Never retry the same verb**; the timing is not the problem, the choice of
@@ -3464,7 +3735,7 @@ declare class StaleError extends ReviewConflictError {
3464
3735
  declare class WrongStateError extends ReviewConflictError {
3465
3736
  }
3466
3737
  /**
3467
- * 409 `terminal` the review has already finished (sent / auto_sent /
3738
+ * 409 `terminal` - the review has already finished (sent / auto_sent /
3468
3739
  * cancelled). Nothing will EVER succeed on it.
3469
3740
  *
3470
3741
  * **Stop.** A `front_run_next` review event is waiting on the durable queue with
@@ -3478,12 +3749,12 @@ declare class TerminalError extends ReviewConflictError {
3478
3749
  constructor(args: ConstructorParameters<typeof ApiError>[0]);
3479
3750
  }
3480
3751
  /**
3481
- * 409 `born_stale` the redraft was composed against an OLDER writing-rule
3752
+ * 409 `born_stale` - the redraft was composed against an OLDER writing-rule
3482
3753
  * high-water than the one now in force. **Nothing was mutated** and the composer
3483
3754
  * has been re-nudged.
3484
3755
  *
3485
3756
  * Retryable at most once per rule high-water: re-read the rules, re-apply them,
3486
- * resubmit or `restamp_review` when re-reading shows nothing genuinely needed
3757
+ * resubmit - or `restamp_review` when re-reading shows nothing genuinely needed
3487
3758
  * to change. Restamping when the body DID need to change makes the draft lie to
3488
3759
  * the born-stale accounting, so do it only for a true no-op.
3489
3760
  */
@@ -3491,7 +3762,7 @@ declare class BornStaleError extends ReviewConflictError {
3491
3762
  get isRetryable(): boolean;
3492
3763
  }
3493
3764
  /**
3494
- * 409 `send_needs_reconciliation` a delivery attempt reached (or may have
3765
+ * 409 `send_needs_reconciliation` - a delivery attempt reached (or may have
3495
3766
  * reached) the mail provider and the process died before recording the outcome,
3496
3767
  * so the review is parked for recover-by-Message-ID.
3497
3768
  *
@@ -3502,17 +3773,17 @@ declare class BornStaleError extends ReviewConflictError {
3502
3773
  declare class SendNeedsReconciliationError extends ReviewConflictError {
3503
3774
  }
3504
3775
  /**
3505
- * 409 `idempotency_conflict` the same `Idempotency-Key` was replayed with a
3776
+ * 409 `idempotency_conflict` - the same `Idempotency-Key` was replayed with a
3506
3777
  * DIFFERENT request body within the same scope. The replay key is a hash of the
3507
3778
  * raw bytes, so "same message, different spelling" counts as different.
3508
3779
  *
3509
3780
  * A caller bug, not a race: do not retry under that key. Either send the byte-
3510
- * identical body, or mint a new key for the genuinely new message.
3781
+ * identical body, or use a new key for the genuinely new message.
3511
3782
  */
3512
3783
  declare class IdempotencyConflictError extends ConflictError {
3513
3784
  }
3514
3785
  /**
3515
- * 503 `unavailable` a dependency could not be read, so the request was failed
3786
+ * 503 `unavailable` - a dependency could not be read, so the request was failed
3516
3787
  * CLOSED rather than served on a guess. On the send path this specifically means
3517
3788
  * the account's review policy was unreadable: relaying unsupervised mail for a
3518
3789
  * customer whose stated policy we could not see is the failure that would be
@@ -3528,7 +3799,7 @@ declare class UnavailableError extends ApiError {
3528
3799
  retryAfter?: number;
3529
3800
  });
3530
3801
  }
3531
- /** 402 payment required (x402 test-mode). `paymentRequired` holds the raw challenge header. */
3802
+ /** 402 - payment required (x402 test-mode). `paymentRequired` holds the raw challenge header. */
3532
3803
  declare class PaymentRequiredError extends ApiError {
3533
3804
  /** The raw `PAYMENT-REQUIRED` header challenge to sign + retry (EIP-3009, Base Sepolia). */
3534
3805
  readonly paymentRequired: string | undefined;
@@ -3536,7 +3807,7 @@ declare class PaymentRequiredError extends ApiError {
3536
3807
  paymentRequired?: string;
3537
3808
  });
3538
3809
  }
3539
- /** 429 rate limited. `retryAfter` is the server's hint in seconds, when provided. */
3810
+ /** 429 - rate limited. `retryAfter` is the server's hint in seconds, when provided. */
3540
3811
  declare class RateLimitError extends ApiError {
3541
3812
  /** Seconds to wait before retrying, parsed from the `Retry-After` header. */
3542
3813
  readonly retryAfter: number | undefined;
@@ -3554,7 +3825,7 @@ declare class TimeoutError extends ApiError {
3554
3825
  }
3555
3826
 
3556
3827
  /**
3557
- * Narrowing helpers for {@link SendOutcome} the three shapes a send can answer.
3828
+ * Narrowing helpers for {@link SendOutcome} - the three shapes a send can answer.
3558
3829
  *
3559
3830
  * `inbox.send()` used to be typed as one struct with a REQUIRED `thread_id`, which
3560
3831
  * the direct-send response has never carried. The type checked; the value was
@@ -3565,7 +3836,7 @@ declare class TimeoutError extends ApiError {
3565
3836
  * has been delivered**. A human has to approve it first, and the delivery outcome
3566
3837
  * arrives later as a `sent` / `send_failed` review event. Code that treats every
3567
3838
  * 2xx from `send()` as "the mail went out" is wrong under the default
3568
- * `require_review` policy which is every account that has not changed it.
3839
+ * `require_review` policy - which is every account that has not changed it.
3569
3840
  */
3570
3841
 
3571
3842
  /**
@@ -3575,14 +3846,14 @@ declare class TimeoutError extends ApiError {
3575
3846
  */
3576
3847
  declare function isQueuedForReview(res: SendOutcome): res is QueuedForReviewResult;
3577
3848
  /**
3578
- * True when the message was delivered immediately either the review-loop
3849
+ * True when the message was delivered immediately - either the review-loop
3579
3850
  * `{kind:"sent"}` body or the legacy body a bare send gets under `allow_direct`.
3580
3851
  */
3581
3852
  declare function isSentImmediately(res: SendOutcome): res is SendResult | SentResult;
3582
3853
  /**
3583
3854
  * The delivered message id, or `undefined` when the message was queued instead.
3584
3855
  *
3585
- * `undefined` here is NOT an error it is the normal answer under
3856
+ * `undefined` here is NOT an error - it is the normal answer under
3586
3857
  * `require_review`. Pair it with {@link reviewIdOf} to follow the message to its
3587
3858
  * outcome.
3588
3859
  */
@@ -3690,7 +3961,7 @@ declare function verifyWebhookSignature(options: VerifyWebhookOptions): Promise<
3690
3961
  */
3691
3962
  declare function parseWebhook(options: VerifyWebhookOptions): Promise<WebhookPayload | null>;
3692
3963
  /**
3693
- * Produce the canonical `X-Extrovert-Signature` header value for a body the exact format the Go
3964
+ * Produce the canonical `X-Extrovert-Signature` header value for a body - the exact format the Go
3694
3965
  * delivery engine emits: `t=<unix>,v1=<hex hmac-sha256("<t>.<rawbody>")>`. Mainly useful for tests
3695
3966
  * and self-hosted senders; the platform signs deliveries server-side. The Go `SignWebhook` and this
3696
3967
  * helper are pinned to the same fixed conformance vector across languages.
@@ -3701,7 +3972,7 @@ declare function signWebhook(secret: string, body: string, timestampSeconds: num
3701
3972
  * The Extrovert Review-Loop **open contract** (HITL D14, spec §11).
3702
3973
  *
3703
3974
  * This module is the single, documented, *versioned* publication of the stable
3704
- * agent-facing JSON shapes that the Review Loop exposes the shapes agents and
3975
+ * agent-facing JSON shapes that the Review Loop exposes - the shapes agents and
3705
3976
  * third-party harnesses code against. It does **not** redesign any types: it
3706
3977
  * re-exports the canonical models built across M1–M8 (see `./models`) under one
3707
3978
  * named contract surface, stamps a {@link CONTRACT_VERSION}, and publishes a
@@ -3711,7 +3982,7 @@ declare function signWebhook(secret: string, body: string, timestampSeconds: num
3711
3982
  * ## This is a contract, NOT a protocol (D14)
3712
3983
  *
3713
3984
  * Per resolved decision **D14**, the open surface is published **now** as an open,
3714
- * documented **skill + SDK contract** explicitly **not** a wire protocol and
3985
+ * documented **skill + SDK contract** - explicitly **not** a wire protocol and
3715
3986
  * **not** a standalone `/v1/contract` endpoint. The contract is exactly: these SDK
3716
3987
  * types + the agent skills (`extrovert-send-email`, `extrovert-writing-rules`) + the
3717
3988
  * docs, **versioned with the SDK** (this package). Formal protocol
@@ -3719,7 +3990,7 @@ declare function signWebhook(secret: string, body: string, timestampSeconds: num
3719
3990
  *
3720
3991
  * ## Provisional, pre-1.0 (0.x)
3721
3992
  *
3722
- * {@link CONTRACT_VERSION} is **`0.1.0-pre.6`** a deliberately **provisional**, pre-1.0
3993
+ * {@link CONTRACT_VERSION} is **`0.1.0-pre.8`** - a deliberately **provisional**, pre-1.0
3723
3994
  * contract. It is open and documented, but it MAY still evolve before 1.0: there
3724
3995
  * are no external users yet, and the **D20 shared-pool auto-send governor** is a
3725
3996
  * hard prerequisite before onboarding external users. Pin the version; expect
@@ -3729,11 +4000,11 @@ declare function signWebhook(secret: string, body: string, timestampSeconds: num
3729
4000
  *
3730
4001
  * Every shape keys on **opaque, typed ids** (`rr_`, `turn_`, `cat_`, `rule_`,
3731
4002
  * `rln_`, `ndg_`, …) and never on names. Names/descriptions are mutable display
3732
- * metadata; renaming never breaks a reference. $0-LLM on our side the contract
4003
+ * metadata; renaming never breaks a reference. $0-LLM on our side - the contract
3733
4004
  * is pure deterministic JSON; all judgment lives in the agent skills.
3734
4005
  *
3735
4006
  * The canonical example payloads for the §11 core shapes (Intent, ReviewFeedback,
3736
- * DiffJson, Rule, Nudge) are the conformance golden fixtures see
4007
+ * DiffJson, Rule, Nudge) are the conformance golden fixtures - see
3737
4008
  * `golang/internal/extrovertapi/testdata/contract/` and the SDK
3738
4009
  * `contract.test.ts` (both assert these examples parse/validate without loss).
3739
4010
  *
@@ -3776,24 +4047,24 @@ interface DiffJson {
3776
4047
  /**
3777
4048
  * The published version of the Extrovert Review-Loop open contract (D14).
3778
4049
  *
3779
- * **`0.1.0-pre.6` PROVISIONAL, pre-1.0.** Versioned *with the SDK* (this package's
4050
+ * **`0.1.0-pre.8` - PROVISIONAL, pre-1.0.** Versioned *with the SDK* (this package's
3780
4051
  * `package.json` version) and aligned to the openapi `info.version`. Open and
3781
4052
  * documented, but MAY still evolve before 1.0 (no external users yet; the D20
3782
4053
  * shared-pool governor is required before external users). Pin it.
3783
4054
  */
3784
- declare const CONTRACT_VERSION: "0.1.0-pre.6";
4055
+ declare const CONTRACT_VERSION: "0.1.0-pre.8";
3785
4056
  /** The stability posture of a published contract version. */
3786
4057
  type ContractStability = "provisional" | "stable";
3787
4058
  /**
3788
- * The machine-readable manifest of the open contract (D14) what a harness pins.
4059
+ * The machine-readable manifest of the open contract (D14) - what a harness pins.
3789
4060
  *
3790
4061
  * It enumerates the canonical §11 **core** shapes and the **full** M1–M8 surface
3791
4062
  * by name, stamps {@link CONTRACT_VERSION}, and marks the {@link ContractStability}
3792
4063
  * posture so a consumer can reason about evolution risk. It carries no runtime
3793
- * behavior (M9 adds none types + a version + a test + docs) and no LLM.
4064
+ * behavior (M9 adds none - types + a version + a test + docs) and no LLM.
3794
4065
  */
3795
4066
  interface ContractManifest {
3796
- /** Stable contract name (NOT a protocol name D14). */
4067
+ /** Stable contract name (NOT a protocol name - D14). */
3797
4068
  readonly name: "extrovert.review-loop";
3798
4069
  /** The published contract version (== {@link CONTRACT_VERSION}). */
3799
4070
  readonly version: string;
@@ -3803,7 +4074,7 @@ interface ContractManifest {
3803
4074
  */
3804
4075
  readonly stability: ContractStability;
3805
4076
  /**
3806
- * D14: this is an SDK + skill contract, versioned WITH the SDK never a wire
4077
+ * D14: this is an SDK + skill contract, versioned WITH the SDK - never a wire
3807
4078
  * protocol or a standalone protocol endpoint.
3808
4079
  */
3809
4080
  readonly kind: "sdk+skill-contract";
@@ -3813,15 +4084,15 @@ interface ContractManifest {
3813
4084
  readonly core_shapes: readonly string[];
3814
4085
  /** The full published M1–M8 agent-facing contract surface (one 0.x contract; no tiering). */
3815
4086
  readonly shapes: readonly string[];
3816
- /** The agent skills that are part of the contract (D14 "skill + SDK"). */
4087
+ /** The agent skills that are part of the contract (D14 - "skill + SDK"). */
3817
4088
  readonly skills: readonly string[];
3818
4089
  }
3819
4090
  /**
3820
4091
  * The published manifest instance. Frozen so a harness can compare it
3821
4092
  * structurally. The `core_shapes` are the five §11 canonical shapes; `shapes` is
3822
4093
  * the full provisional-0.x surface. Keep this list in sync with the re-exports
3823
- * above the `contract.test.ts` drift test asserts every named shape resolves.
4094
+ * above - the `contract.test.ts` drift test asserts every named shape resolves.
3824
4095
  */
3825
4096
  declare const CONTRACT_MANIFEST: ContractManifest;
3826
4097
 
3827
- 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, 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 };
4098
+ 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 LearnReviewRuleRequest, type LearnedReviewRule, 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 };