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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts 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.7";
10
10
  interface RetryOptions {
11
11
  /** Max retry attempts for idempotent requests on 429/5xx/network errors. Default 2. */
12
12
  maxRetries: number;
@@ -33,7 +33,7 @@ type ReviewInclude = "category" | "turns";
33
33
  declare function serializeInclude(include?: readonly string[]): string | undefined;
34
34
 
35
35
  /**
36
- * Extrovert API typed request/response models.
36
+ * Extrovert API: typed request/response models.
37
37
  *
38
38
  * These mirror the Extrovert V1 REST contract (`/v1`, §8 of the build spec). The Go API does not
39
39
  * exist yet; field shapes here are the source of truth the client codes against and are validated
@@ -52,13 +52,13 @@ type IsoTimestamp = string;
52
52
  * its caveats but cannot exceed them (§5).
53
53
  *
54
54
  * The `mailbox:*` scope strings are the live wire contract (stored in issued keys'
55
- * caveats) and are NOT renamed despite the public "inbox" product naming renaming
56
- * them would invalidate every key already minted. `domain:manage` gates the domains
57
- * plane; `domain:purchase` is additionally required (and is opt-in, default-off) to
58
- * buy a new domain (`POST /v1/domains` with `mode: "purchased"`). `review:act` gates
59
- * the BYO reviewer decision plane.
55
+ * caveats) and are NOT renamed despite the public "inbox" product naming: renaming
56
+ * them would invalidate every key already issued. `domain:manage` gates onboarding
57
+ * for domains the customer already controls. `commerce:request` permits quotes,
58
+ * requests, and status reads, but never a human approval transition or direct spend.
59
+ * `review:act` gates the BYO reviewer decision plane.
60
60
  */
61
- type Scope = "mailbox:create" | "mailbox:read" | "mailbox:send" | "mailbox:quota" | "mailbox: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;
@@ -775,7 +799,7 @@ interface ReviewFeedbackComment {
775
799
  * The human's assembled feedback for a review (spec §11), returned by
776
800
  * `reviews.feedback(id)`: the unified + structured diff of the human edit, the human
777
801
  * 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.
802
+ * (rule_ ids whose source_review_id is this review). $0 LLM: pure assembly.
779
803
  */
780
804
  interface ReviewFeedback {
781
805
  review_id: string;
@@ -792,7 +816,7 @@ interface PostReviewChatRequest {
792
816
  }
793
817
  /**
794
818
  * 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
819
+ * D17). parent_revision is the PRIMARY CAS: it must equal the draft's current
796
820
  * revision, else 409 STALE with NO mutation. version is OPTIONAL belt-and-suspenders.
797
821
  */
798
822
  interface SubmitRevisionRequest {
@@ -801,7 +825,7 @@ interface SubmitRevisionRequest {
801
825
  subject?: string;
802
826
  /**
803
827
  * 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
828
+ * forward: the same concept should not have two names in the one flow an
805
829
  * agent runs most.
806
830
  */
807
831
  text?: string;
@@ -854,7 +878,7 @@ type ReviewEventReason =
854
878
  * cancel, so compose and submit a NEW message rather than retrying this one.
855
879
  */
856
880
  | "send_failed"
857
- /** Withdrawn by you, by a human, or as the close-out of a failed send. */
881
+ /** Withdrawn: by you, by a human, or as the close-out of a failed send. */
858
882
  | "cancelled"
859
883
  /**
860
884
  * You were front-run: the review reached a terminal state while you were
@@ -862,9 +886,9 @@ type ReviewEventReason =
862
886
  * `cancel_review` answered 409 `terminal`. STOP retrying that review.
863
887
  */
864
888
  | "front_run_next"
865
- /** RESERVED never emitted. Terminal success is `sent`. */
889
+ /** RESERVED: never emitted. Terminal success is `sent`. */
866
890
  | "approved"
867
- /** RESERVED no production producer (the D13 staleness detector is unbuilt). */
891
+ /** RESERVED: no production producer (the D13 staleness detector is unbuilt). */
868
892
  | "staleness";
869
893
  /**
870
894
  * One durable review nudge (ndg_…) drained from the AUTHORITATIVE liveness queue
@@ -880,12 +904,12 @@ interface ReviewEvent {
880
904
  payload?: Record<string, unknown>;
881
905
  created_at: IsoTimestamp;
882
906
  }
883
- /** The agent's per-(agent, review) ack frontier its strict-FIFO position. */
907
+ /** The agent's per-(agent, review) ack frontier: its strict-FIFO position. */
884
908
  interface ReviewEventCursor {
885
909
  review_id: string;
886
910
  last_acked_seq: number;
887
911
  }
888
- /** Drain result for list/wait un-acked events in FIFO seq order + cursors. */
912
+ /** Drain result for list/wait: un-acked events in FIFO seq order + cursors. */
889
913
  interface ReviewEventsResult {
890
914
  events: ReviewEvent[];
891
915
  cursors?: ReviewEventCursor[];
@@ -901,7 +925,7 @@ interface ListReviewEventsParams {
901
925
  * A category (cat_…) in the Review Loop registry (D9/D10). `name` + `description`
902
926
  * are skill-style metadata the agent fuzzy-matches against; nothing keys on the
903
927
  * name (renames never break a reference). Categories are CUSTOMER-scoped and
904
- * agent-attributed the deliberate cross-agent-404 exception. Opaque ids only.
928
+ * agent-attributed: the deliberate cross-agent-404 exception. Opaque ids only.
905
929
  */
906
930
  interface Category {
907
931
  id: string;
@@ -930,13 +954,13 @@ interface ProposeCategoryRequest {
930
954
  /** Defaults to org_shared server-side. */
931
955
  scope?: "org_shared" | "agent_private";
932
956
  }
933
- /** Rename / re-describe a category metadata only (spec §5.5; D10). */
957
+ /** Rename / re-describe a category: metadata only (spec §5.5; D10). */
934
958
  interface UpdateCategoryRequest {
935
959
  name?: string;
936
960
  description?: string;
937
961
  }
938
962
  /**
939
- * The account-wide default risk dial (Review Loop, D4/D12) the values a per-
963
+ * The account-wide default risk dial (Review Loop, D4/D12): the values a per-
940
964
  * category null override inherits. The single user-configurable brand-risk lever.
941
965
  */
942
966
  interface AccountRiskDial {
@@ -974,7 +998,7 @@ interface CategoryRiskDial {
974
998
  }
975
999
  /**
976
1000
  * 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
1001
+ * plus every category's overrides. Read-only for agents: flipping the dial is a
978
1002
  * console (human) action (D16).
979
1003
  */
980
1004
  interface RiskDial {
@@ -1027,7 +1051,7 @@ type ReviewerAction = "approve" | "edit" | "reject" | "escalate";
1027
1051
  * The REVIEWER's read-only decision surface for a review (BYO review-agent plane;
1028
1052
  * D5/§9), returned by `reviews.decisionContext(id)`: the intent + current draft + the
1029
1053
  * 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
1054
+ * EITHER breaker has tripped: the reviewer's next reject would be FORCED to the human
1031
1055
  * regardless of intent (the human is the only terminal authority, D17).
1032
1056
  */
1033
1057
  interface ReviewDecisionContext {
@@ -1051,7 +1075,7 @@ interface ReviewDecisionContext {
1051
1075
  /**
1052
1076
  * Body for a reviewer decision (`reviews.decide(id, req)`; reviewer_decide, D5/§9).
1053
1077
  * `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/
1078
+ *: a mismatch is a 409 STALE with NO mutation (the human always wins, D17). subject/
1055
1079
  * body carry the edited content for the edit action; feedback is the reviewer's note.
1056
1080
  */
1057
1081
  interface ReviewerDecisionRequest {
@@ -1068,8 +1092,8 @@ interface ReviewerDecisionRequest {
1068
1092
  feedback?: string;
1069
1093
  }
1070
1094
  /**
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);
1095
+ * The outcome of a reviewer decision (D5/§9). `kind=sent` when the platform sent
1096
+ * with the COMPOSER's creds (approve/edit: the reviewer NEVER holds mailbox:send);
1073
1097
  * `kind=sent_to_human` when the draft returned to the human queue (reject/escalate, or
1074
1098
  * a reject FORCED to the human by a circuit breaker, with `forced_by_breaker` naming it).
1075
1099
  */
@@ -1085,7 +1109,7 @@ interface ReviewerDecisionResult {
1085
1109
  /**
1086
1110
  * The D19/§8 backlog-reconciliation snapshot for a category (agent-readable, $0-LLM).
1087
1111
  * 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
1112
+ * category rules-version + house-style version (a pure integer compare). Read-only :
1089
1113
  * the agent READS the picture; the human / hooks TRIGGER the actual sweep.
1090
1114
  */
1091
1115
  interface ScanBacklogStatus {
@@ -1108,7 +1132,7 @@ interface PacingItem {
1108
1132
  state: "behind_cursor" | "in_window_fresh" | "in_window_redrafting" | "ahead";
1109
1133
  }
1110
1134
  /**
1111
- * The demand-driven pacing snapshot for a category (agent-readable, $0-LLM M7 Slice
1135
+ * The demand-driven pacing snapshot for a category (agent-readable, $0-LLM: M7 Slice
1112
1136
  * B/§8): the human review cursor, the effective window/ceiling/interval, the queued
1113
1137
  * count, and each queued draft's in-window/redrafting/behind-cursor classification.
1114
1138
  * Read-only; the cursor advances from the human's console approve/reject/edit actions.
@@ -1121,7 +1145,7 @@ interface CategoryPacingState {
1121
1145
  cursor_advanced_count: number;
1122
1146
  /** Effective freshness window (default org_settings.lookahead_window=3). */
1123
1147
  lookahead_window: number;
1124
- /** HARD per-nudge fan-out ceiling (default 10) one nudge can never fan to 500. */
1148
+ /** HARD per-nudge fan-out ceiling (default 10): one nudge can never fan to 500. */
1125
1149
  rework_batch_max: number;
1126
1150
  /** Per-agent token-bucket interval that coalesces feedback storms (default 5000). */
1127
1151
  nudge_min_interval_ms: number;
@@ -1202,11 +1226,11 @@ interface RuleSnapshot extends Page<Rule> {
1202
1226
  /**
1203
1227
  * Save / edit a writing rule (append-only by supersession; spec §5.4; D11).
1204
1228
  *
1205
- * Layering (org/project): an agent-plane save is ALWAYS project-layer the saved
1229
+ * Layering (org/project): an agent-plane save is ALWAYS project-layer: the saved
1206
1230
  * rule's `rule_layer` is `project`, bound to the calling key's project. There is no
1207
1231
  * settable `rule_layer` here: an agent cannot create org-layer / house-style
1208
1232
  * (`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
1233
+ * (`scope: "general"` still means a house-style rule WITHIN the project layer :
1210
1234
  * `scope` is the category axis, `rule_layer` is the ownership axis.)
1211
1235
  */
1212
1236
  interface SaveRuleRequest {
@@ -1229,7 +1253,7 @@ interface SaveRuleRequest {
1229
1253
  /**
1230
1254
  * D8 retro-propagation HUMAN OPT-IN (default false). When true, a NEW category rule
1231
1255
  * 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
1256
+ * (siblings + suggested_batch) so the agent redrafts a FEW at a time: never the
1233
1257
  * whole queue. Set only after the human said "apply to N pending?".
1234
1258
  */
1235
1259
  propagate_to_pending?: boolean;
@@ -1286,7 +1310,7 @@ interface SentResult {
1286
1310
  };
1287
1311
  /**
1288
1312
  * 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
1313
+ * service routed, i.e. all of them: it is the handle that makes a post-crash
1290
1314
  * `reviews.get(id)` possible on the direct path too.
1291
1315
  */
1292
1316
  review?: {
@@ -1306,14 +1330,20 @@ interface Thread {
1306
1330
  /** Owning inbox address. */
1307
1331
  inbox_id: string;
1308
1332
  subject: string;
1309
- /** Distinct participant address strings across the thread. */
1333
+ /** List/search summaries use the latest envelope; thread detail may include the full conversation set. */
1310
1334
  participants: string[];
1311
1335
  message_count: number;
1312
1336
  last_message_at: IsoTimestamp;
1313
1337
  /** Most-recent-message preview snippet. */
1314
1338
  snippet: string;
1339
+ /** Whether the latest message is unread. */
1340
+ unread?: boolean;
1341
+ /** Whether the newest message has one or more attachments. */
1342
+ last_message_has_attachments?: boolean;
1343
+ /** Opaque message id for optimistic reply freshness checks. */
1344
+ last_message_id?: string;
1315
1345
  }
1316
- /** A thread plus its messages (oldest-first) `GET /v1/inboxes/{addr}/threads/{id}`. */
1346
+ /** A thread plus its messages (oldest-first): `GET /v1/inboxes/{addr}/threads/{id}`. */
1317
1347
  interface ThreadDetail extends Thread {
1318
1348
  messages: Message[];
1319
1349
  }
@@ -1485,7 +1515,7 @@ interface SuppressionEntry {
1485
1515
  /**
1486
1516
  * The result of a pre-check (`GET /v1/suppressions?recipient=…`): whether the
1487
1517
  * 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.
1518
+ * only the caller's org state: never a global/shared/cross-tenant opt-out.
1489
1519
  */
1490
1520
  interface SuppressionPrecheck {
1491
1521
  recipient: string;
@@ -1504,7 +1534,7 @@ interface ListSuppressionsParams {
1504
1534
  /** Opaque cursor from a previous page's `next_cursor`. */
1505
1535
  cursor?: string;
1506
1536
  }
1507
- /** One DNS record the customer must set (manual mode) or that we serve (ns_delegated). */
1537
+ /** One nameserver record the customer must publish for delegated setup. */
1508
1538
  interface DomainRecord {
1509
1539
  name: string;
1510
1540
  type: string;
@@ -1518,40 +1548,43 @@ type DomainScope = "org" | "project";
1518
1548
  /**
1519
1549
  * Request body for `POST /v1/domains`. Onboards/adds a domain for the customer.
1520
1550
  *
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.
1551
+ * Requires the `domain:manage` scope. This request only adds a delegated inbox
1552
+ * domain the customer controls; it cannot register one.
1553
+ * New registrations use the separate commerce quote/request workflow.
1526
1554
  */
1527
1555
  interface OnboardDomainRequest {
1528
1556
  domain: string;
1529
1557
  /**
1530
- * Onboarding path. Defaults to `ns_delegated` server-side when omitted. `purchased`
1531
- * additionally requires the `domain:purchase` scope.
1558
+ * Onboarding path. Defaults to `ns_delegated` server-side when omitted.
1532
1559
  */
1533
- mode?: OnboardingMode;
1534
- /** A-record IP served at a delegated zone's apex (ns_delegated only). */
1535
- mail_host_ip?: string;
1560
+ mode?: "ns_delegated";
1536
1561
  /**
1537
1562
  * Domain visibility. Defaults to `org` (org-shared, usable by every project in the
1538
1563
  * 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
1564
+ * client-selected) so it is only visible/creatable from that project. A
1540
1565
  * legacy/unscoped key (no bound project) falls back to `org`.
1541
1566
  */
1542
1567
  scope?: DomainScope;
1543
1568
  /**
1544
- * Optional assertion that must match the key's bound project NEVER a selector.
1569
+ * Optional assertion that must match the key's bound project: NEVER a selector.
1545
1570
  * A mismatch is a 403. The binding is always derived from the key.
1546
1571
  */
1547
1572
  project_id?: string;
1548
1573
  }
1549
1574
  /**
1550
1575
  * 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.
1576
+ * `delegation_ns` is present on get / onboard / verify for delegated domains and
1577
+ * empty on list reads. `records` remains for legacy response compatibility.
1553
1578
  */
1554
1579
  interface Domain {
1580
+ /** Authoritative outcome. Absent only when talking to an older server; never infer readiness from DKIM. */
1581
+ readiness?: DomainReadiness;
1582
+ /** Customer DNS health, independent of mail provisioning readiness. */
1583
+ delegation?: {
1584
+ status: "pending" | "confirmed" | "rechecking" | "check_delayed" | "action_required";
1585
+ checked_at?: string;
1586
+ confirmed_at?: string;
1587
+ };
1555
1588
  id: string;
1556
1589
  domain: string;
1557
1590
  mode: OnboardingMode;
@@ -1566,10 +1599,48 @@ interface Domain {
1566
1599
  /** Human-facing copy for what the customer must do next. */
1567
1600
  instruction?: string;
1568
1601
  }
1602
+ interface DomainStatusEvent {
1603
+ id: string;
1604
+ type: string;
1605
+ domain: string;
1606
+ summary: string;
1607
+ data: {
1608
+ domain: string;
1609
+ readiness: DomainReadiness;
1610
+ };
1611
+ created_at: string;
1612
+ }
1613
+ interface DomainStatusEventPage {
1614
+ items: DomainStatusEvent[];
1615
+ next_cursor: string;
1616
+ has_more: boolean;
1617
+ poll_after_seconds: number;
1618
+ }
1619
+ interface DomainReadiness {
1620
+ status: "waiting_for_dns" | "checking" | "setting_up" | "ready" | "action_required" | "needs_attention";
1621
+ label: string;
1622
+ summary: string;
1623
+ reason: string;
1624
+ action_required_by: "customer" | "extrovert" | "none";
1625
+ next_action: "check_dns_entries" | "restore_dns" | "wait" | "create_inbox" | "use_inbox" | "ask_owner_to_create_inbox";
1626
+ /** Domain configuration only; creating an inbox still requires permission and available plan capacity. */
1627
+ ready_for_inboxes: boolean;
1628
+ checked_at?: IsoTimestamp;
1629
+ next_check_at?: IsoTimestamp;
1630
+ poll_after_seconds: number;
1631
+ /** Omitted without inbox-read permission. Counts never imply organization-wide visibility for an agent. */
1632
+ inboxes?: {
1633
+ scope: "agent" | "project" | "organization";
1634
+ total: number;
1635
+ ready: number;
1636
+ setting_up: number;
1637
+ needs_attention: number;
1638
+ };
1639
+ }
1569
1640
  /**
1570
1641
  * 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`
1642
+ * Teardown: reaping the outbound provider senders + routing rows, then scrubbing
1643
+ * the DNS zone/records and the domain row: runs as an async job. Poll `status_url`
1573
1644
  * (`GET /v1/jobs/{job_id}`, via {@link Job} / `client.getJob(job_id)`) until
1574
1645
  * `status` is terminal (succeeded/failed/cancelled); the domain is ACCEPTED for
1575
1646
  * offboard, not yet fully torn down when this returns.
@@ -1594,6 +1665,95 @@ interface Job {
1594
1665
  updated_at: IsoTimestamp;
1595
1666
  finished_at?: IsoTimestamp;
1596
1667
  }
1668
+ /** One exact reason a commerce request cannot advance automatically. */
1669
+ interface CommerceBlocker {
1670
+ code: string;
1671
+ message: string;
1672
+ scope?: "org" | "project" | "agent" | string;
1673
+ limit_id?: string;
1674
+ used_cents?: number;
1675
+ reserved_cents?: number;
1676
+ limit_cents?: number;
1677
+ requested_cents?: number;
1678
+ used_count?: number;
1679
+ reserved_count?: number;
1680
+ limit_count?: number;
1681
+ reset_at?: IsoTimestamp;
1682
+ manage_url?: string;
1683
+ }
1684
+ /** Request body for the non-spending domain quote endpoint. */
1685
+ interface QuoteDomainRequest {
1686
+ domain: string;
1687
+ }
1688
+ /** Current, expiring domain registration quote. Quoting never purchases. */
1689
+ interface DomainQuote {
1690
+ object: "domain_quote";
1691
+ domain: string;
1692
+ available: boolean;
1693
+ currency: string;
1694
+ quote_cents: number;
1695
+ renewal_cents: number;
1696
+ premium: boolean;
1697
+ quote_expires_at: IsoTimestamp;
1698
+ required_plan?: string;
1699
+ required_plan_price_cents?: number;
1700
+ blockers: CommerceBlocker[];
1701
+ }
1702
+ type CommerceRequestKind = "domain_purchase" | "plan_change";
1703
+ interface RequestDomainPurchaseRequest {
1704
+ domain: string;
1705
+ /** Stable retry identity; sent as the `Idempotency-Key` header, not in the JSON body. */
1706
+ idempotency_key: string;
1707
+ scope?: DomainScope;
1708
+ rationale?: string;
1709
+ auto_renew?: boolean;
1710
+ }
1711
+ interface RequestPlanChangeRequest {
1712
+ target_plan: "free" | "developer" | "startup";
1713
+ /** Stable retry identity; sent as the `Idempotency-Key` header, not in the JSON body. */
1714
+ idempotency_key: string;
1715
+ rationale?: string;
1716
+ }
1717
+ interface ListCommerceRequestsParams {
1718
+ limit?: number;
1719
+ page?: string;
1720
+ }
1721
+ /** Durable poll shape for an agent-initiated financial request. */
1722
+ interface CommerceRequest {
1723
+ object: "commerce_request";
1724
+ id: string;
1725
+ project_id?: string;
1726
+ agent_id?: string;
1727
+ kind: CommerceRequestKind;
1728
+ state: string;
1729
+ domain?: string;
1730
+ domain_scope?: DomainScope;
1731
+ target_plan?: string;
1732
+ current_plan?: string;
1733
+ rationale?: string;
1734
+ currency: string;
1735
+ quote_cents: number;
1736
+ renewal_cents: number;
1737
+ approved_max_cents?: number;
1738
+ quote_expires_at?: IsoTimestamp;
1739
+ auto_renew: boolean;
1740
+ required_plan?: string;
1741
+ required_plan_price_cents?: number;
1742
+ blocker_code?: string;
1743
+ blockers: CommerceBlocker[];
1744
+ approval_url?: string;
1745
+ payment_action_url?: string;
1746
+ external_job_id?: string;
1747
+ effective_at?: IsoTimestamp;
1748
+ notification_state?: string;
1749
+ notification_last_error?: string;
1750
+ agent_next_action: string;
1751
+ retry_safe: boolean;
1752
+ poll_after_seconds: number;
1753
+ version: number;
1754
+ created_at: IsoTimestamp;
1755
+ updated_at: IsoTimestamp;
1756
+ }
1597
1757
  /**
1598
1758
  * One event from the SSE stream (`GET /v1/inboxes/{addr}/stream` or `GET
1599
1759
  * /v1/events`). It is the SAME envelope a webhook delivers, so a stream consumer
@@ -1630,12 +1790,12 @@ interface StreamOptions {
1630
1790
  interface SignUpRequest {
1631
1791
  /** Human email that receives the one-time verification code. */
1632
1792
  human_email: string;
1633
- /** Desired local-part for the first inbox (optional; auto-generated when omitted). */
1793
+ /** Desired local part on `free.extrovertmail.com`. It must normalize to at least 5 characters and cannot use a reserved name. */
1634
1794
  username?: string;
1635
1795
  }
1636
1796
  /**
1637
1797
  * 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
1798
+ * (verification-only, with no inbox read or send permission) that expires with the emailed code. Successful verification revokes
1639
1799
  * it and returns a replacement full-scope key. The OTP itself is never returned.
1640
1800
  */
1641
1801
  interface SignUpResponse {
@@ -1645,7 +1805,7 @@ interface SignUpResponse {
1645
1805
  agent_key: string;
1646
1806
  key_prefix: string;
1647
1807
  scopes: Scope[];
1648
- /** The first inbox minted for the agent. */
1808
+ /** The first inbox created for the agent. */
1649
1809
  address: string;
1650
1810
  verified: boolean;
1651
1811
  /** Where the verification code was sent. */
@@ -1694,14 +1854,28 @@ interface VerifyResponse {
1694
1854
  org_claim_token?: string;
1695
1855
  }
1696
1856
  /**
1697
- * Response from `GET /v1/auth/me` the verified principal behind the key.
1857
+ * Response from `GET /v1/auth/me`: the verified principal behind the key.
1698
1858
  *
1699
1859
  * `org_id`/`project_id` are the FIXED org/project the key is bound to (resolved from
1700
1860
  * 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
1861
+ * scoped key: `whoami` is the canonical project-visibility surface; project
1702
1862
  * selection happens when the human/admin issues the enrollment token or agent key.
1703
1863
  */
1704
1864
  interface WhoAmI {
1865
+ connection_status?: "connected";
1866
+ summary?: string;
1867
+ agent_name?: string;
1868
+ organization_name?: string;
1869
+ project_name?: string;
1870
+ /** Granted permissions, not a guarantee of plan capacity or review approval. */
1871
+ capabilities?: {
1872
+ read_domain_status: boolean;
1873
+ connect_owned_domains: boolean;
1874
+ create_inboxes: boolean;
1875
+ read_inboxes: boolean;
1876
+ submit_mail_for_review: boolean;
1877
+ request_purchases: boolean;
1878
+ };
1705
1879
  customer_id: string;
1706
1880
  /**
1707
1881
  * The fixed org the key is bound to. Optional to match the OpenAPI contract: a
@@ -1723,7 +1897,7 @@ interface WhoAmI {
1723
1897
  *
1724
1898
  * Every redesign collection endpoint (the canonical `x.projects.inboxes.*` chain
1725
1899
  * 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
1900
+ * `next_cursor` is OPAQUE - treat it as a token and pass it back verbatim as
1727
1901
  * `?cursor` to fetch the next page. {@link ListPage} wraps a raw {@link List} with
1728
1902
  * ergonomic iteration (`for await … of`) and a `nextPage()` cursor walker so callers
1729
1903
  * never thread cursors by hand.
@@ -1773,7 +1947,7 @@ declare class ListPage<T> implements AsyncIterable<T> {
1773
1947
  readonly object: "list";
1774
1948
  constructor(raw: List<T>, fetcher: PageFetcher<T>);
1775
1949
  /**
1776
- * Fetch the next page. Throws if there is none guard with {@link hasMore}.
1950
+ * Fetch the next page. Throws if there is none - guard with {@link hasMore}.
1777
1951
  */
1778
1952
  nextPage(signal?: AbortSignal): Promise<ListPage<T>>;
1779
1953
  /**
@@ -1849,12 +2023,25 @@ interface Transport {
1849
2023
  precheckSuppression(recipient: string, signal?: AbortSignal): Promise<SuppressionPrecheck>;
1850
2024
  listSuppressions(params: ListSuppressionsParams, signal?: AbortSignal): Promise<Page<SuppressionEntry>>;
1851
2025
  revokeSuppression(id: string, reason: string, signal?: AbortSignal): Promise<SuppressionEntry>;
1852
- listDomains(signal?: AbortSignal): Promise<Page<Domain>>;
2026
+ listDomains(signal?: AbortSignal, params?: {
2027
+ page?: string;
2028
+ limit?: number;
2029
+ }): Promise<Page<Domain>>;
2030
+ listDomainEvents(domain: string, params: {
2031
+ after?: string;
2032
+ limit?: number;
2033
+ }, signal?: AbortSignal): Promise<DomainStatusEventPage>;
1853
2034
  getDomain(domain: string, signal?: AbortSignal): Promise<Domain>;
1854
2035
  onboardDomain(req: OnboardDomainRequest, signal?: AbortSignal): Promise<Domain>;
1855
2036
  verifyDomain(domain: string, signal?: AbortSignal): Promise<Domain>;
1856
2037
  offboardDomain(domain: string, signal?: AbortSignal): Promise<DomainOffboard>;
1857
2038
  getJob(jobId: string, signal?: AbortSignal): Promise<Job>;
2039
+ quoteDomain(req: QuoteDomainRequest, signal?: AbortSignal): Promise<DomainQuote>;
2040
+ requestDomainPurchase(req: RequestDomainPurchaseRequest, signal?: AbortSignal): Promise<CommerceRequest>;
2041
+ requestPlanChange(req: RequestPlanChangeRequest, signal?: AbortSignal): Promise<CommerceRequest>;
2042
+ getCommerceRequest(requestId: string, signal?: AbortSignal): Promise<CommerceRequest>;
2043
+ cancelCommerceRequest(requestId: string, signal?: AbortSignal): Promise<CommerceRequest>;
2044
+ listCommerceRequests(params: ListCommerceRequestsParams, signal?: AbortSignal): Promise<Page<CommerceRequest>>;
1858
2045
  submitForReview(address: string, req: SendRequest, signal?: AbortSignal): Promise<SendOutcome>;
1859
2046
  submitReplyForReview(address: string, req: ReplyRequest, signal?: AbortSignal): Promise<SendOutcome>;
1860
2047
  listReviews(params: ListReviewsParams, signal?: AbortSignal): Promise<Page<Review>>;
@@ -1903,7 +2090,7 @@ interface Transport {
1903
2090
  *
1904
2091
  * The mock honors the same request/response models as the real API and reproduces the few behaviors
1905
2092
  * 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.
2093
+ * an OTP). It is intentionally simple - not a full server - and never reaches the network.
1907
2094
  */
1908
2095
 
1909
2096
  /**
@@ -1931,7 +2118,7 @@ declare class MockBackend {
1931
2118
  * Normalize an inbox ref (opaque id OR address alias) to the canonical address the
1932
2119
  * mock keys its message/thread/contact maps on. The SDK now routes inbox ops by the
1933
2120
  * 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
2121
+ * canonical-key semantics), so the mock must resolve an id back to its address -
1935
2122
  * both key `state.inboxes` (same object), `state.messages` keys by address only.
1936
2123
  * Unknown refs pass through unchanged so the existing not-found paths still fire.
1937
2124
  */
@@ -1961,8 +2148,8 @@ declare class MockBackend {
1961
2148
  forward(address: string, messageId: string, req: ForwardRequest): SendOutcome;
1962
2149
  /**
1963
2150
  * 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
2151
+ * the real server, so it is literally the same call here: the resolved policy -
2152
+ * not which SDK method you picked - decides whether the message is queued
1966
2153
  * (`kind:"queued_for_review"`) or delivered.
1967
2154
  */
1968
2155
  submitForReview(address: string, req: SendRequest): SendOutcome;
@@ -1983,9 +2170,9 @@ declare class MockBackend {
1983
2170
  private setReviewState;
1984
2171
  /** Mark a review delivered on an auto-send path and emit its terminal `sent` nudge. */
1985
2172
  private markReviewAutoSent;
1986
- /** Raw delivery for a send no policy, only reachable from submitOutbound. */
2173
+ /** Raw delivery for a send - no policy, only reachable from submitOutbound. */
1987
2174
  private deliverSend;
1988
- /** Raw delivery for a reply no policy, only reachable from submitOutbound. */
2175
+ /** Raw delivery for a reply - no policy, only reachable from submitOutbound. */
1989
2176
  private deliverReply;
1990
2177
  /** Append the outbound message and shape the legacy send result. */
1991
2178
  private deliverRaw;
@@ -2049,7 +2236,7 @@ declare class MockBackend {
2049
2236
  reviewerDecide(reviewId: string, req: ReviewerDecisionRequest): ReviewerDecisionResult | undefined;
2050
2237
  /**
2051
2238
  * 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,
2239
+ * is a pure lexical filter (every token must appear in name+description) - NO LLM,
2053
2240
  * mirroring the server.
2054
2241
  */
2055
2242
  listCategories(params?: ListCategoriesParams): Page<Category>;
@@ -2057,14 +2244,14 @@ declare class MockBackend {
2057
2244
  getCategory(categoryId: string): Category | undefined;
2058
2245
  /** Propose a category (mock): stands immediately, author_kind=agent (D9). */
2059
2246
  proposeCategory(req: ProposeCategoryRequest): Category;
2060
- /** Rename / re-describe a category (mock) metadata only (D10). */
2247
+ /** Rename / re-describe a category (mock) - metadata only (D10). */
2061
2248
  updateCategory(categoryId: string, req: UpdateCategoryRequest): Category | undefined;
2062
2249
  /** The mock account-default risk dial (mirrors the server defaults). */
2063
2250
  private accountDial;
2064
2251
  /**
2065
2252
  * Read the effective risk dial (mock): the account default + every category with an
2066
2253
  * inherited (null override) effective dial. The mock category carries no overrides,
2067
- * so every category inherits effective == account.
2254
+ * so every category inherits - effective == account.
2068
2255
  */
2069
2256
  getRiskDial(): RiskDial;
2070
2257
  private nextGraduationState;
@@ -2076,19 +2263,19 @@ declare class MockBackend {
2076
2263
  getGraduationStatus(categoryId: string): GraduationStatus | undefined;
2077
2264
  /**
2078
2265
  * Propose graduating a category (mock): returns the current gate status without
2079
- * changing the category state (D16 an agent can never flip the bit).
2266
+ * changing the category state (D16 - an agent can never flip the bit).
2080
2267
  */
2081
2268
  proposeGraduation(categoryId: string, _req: ProposeGraduationRequest): GraduationStatus | undefined;
2082
2269
  /**
2083
2270
  * Read the D19/§8 backlog-reconciliation status (mock): counts the QUEUED drafts in a
2084
2271
  * category that are stale vs current-enough against the current rules-version. The
2085
2272
  * 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
2273
+ * draft reads as current-enough (composed 0 vs current 0) - the contract shape is
2087
2274
  * exercised; the integer-compare logic is covered by the Go tests.
2088
2275
  */
2089
2276
  getScanBacklogStatus(categoryId: string): ScanBacklogStatus | undefined;
2090
2277
  /**
2091
- * Read the demand-driven pacing state (mock M7 Slice B/§8): the cursor + effective
2278
+ * Read the demand-driven pacing state (mock - M7 Slice B/§8): the cursor + effective
2092
2279
  * window/ceiling/interval + each queued draft's classification. The mock has no cursor
2093
2280
  * (nothing reviewed) and no composed_* stamps, so every queued draft reads in-window-
2094
2281
  * fresh until the window fills, then ahead; the contract shape is exercised (the
@@ -2097,17 +2284,17 @@ declare class MockBackend {
2097
2284
  getCategoryPacingState(categoryId: string): CategoryPacingState | undefined;
2098
2285
  /** rank a rule for the §7 ladder (mock mirror of the server's deterministic order). */
2099
2286
  private ruleRank;
2100
- /** Get the ORDERED active rule set (mock) §7 ladder + category-before-general. */
2287
+ /** Get the ORDERED active rule set (mock) - §7 ladder + category-before-general. */
2101
2288
  getRules(params?: GetRulesParams): RuleSnapshot;
2102
- /** Save / edit a rule (mock) append-only by supersession (D11). */
2289
+ /** Save / edit a rule (mock) - append-only by supersession (D11). */
2103
2290
  saveRule(req: SaveRuleRequest): Rule;
2104
2291
  /** Promote a rule between layers (mock, via supersession), or undefined when unknown. */
2105
2292
  promoteRule(ruleId: string, toScope: "general" | "category"): Rule | undefined;
2106
- /** Retire a rule (mock) soft delete, or undefined when unknown. */
2293
+ /** Retire a rule (mock) - soft delete, or undefined when unknown. */
2107
2294
  retireRule(ruleId: string): Rule | undefined;
2108
2295
  /** Read the rule/category change audit log (mock). */
2109
2296
  getRuleAudit(params?: GetRuleAuditParams): Page<RuleAuditEntry>;
2110
- /** Undo a rule change (mock) restore the prior version; idempotent (re-undo 409). */
2297
+ /** Undo a rule change (mock) - restore the prior version; idempotent (re-undo 409). */
2111
2298
  undoRuleChange(udoId: string): Rule;
2112
2299
  /** recordRuleAudit appends one change/undo audit row (mock). */
2113
2300
  private recordRuleAudit;
@@ -2124,7 +2311,7 @@ declare class MockBackend {
2124
2311
  */
2125
2312
  private enqueueTerminalNudge;
2126
2313
  /**
2127
- * Enqueue `front_run_next` the signal that the review reached a terminal state
2314
+ * Enqueue `front_run_next` - the signal that the review reached a terminal state
2128
2315
  * while the agent was still trying to act on it.
2129
2316
  *
2130
2317
  * Deduped on (review, terminal state, parent revision) so a retry loop hitting
@@ -2142,8 +2329,8 @@ declare class MockBackend {
2142
2329
  }): Review | undefined;
2143
2330
  /**
2144
2331
  * 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
2332
+ * This is the case the composing agent was previously never told about - the
2333
+ * console showed the error and the agent's queue stayed silent - so the loop test
2147
2334
  * that matters most drives this path.
2148
2335
  */
2149
2336
  simulateSendFailed(reviewId: string, error?: string): Review | undefined;
@@ -2171,7 +2358,7 @@ declare class MockBackend {
2171
2358
  listReviewEvents(params?: ListReviewEventsParams): ReviewEventsResult;
2172
2359
  /**
2173
2360
  * 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
2361
+ * returns the immediate drain (empty when caught up) - the server's "empty on
2175
2362
  * timeout" contract.
2176
2363
  */
2177
2364
  waitForReviewEvent(params?: WaitForReviewEventParams): ReviewEventsResult;
@@ -2194,9 +2381,10 @@ declare class MockBackend {
2194
2381
  getMessageRaw(messageId: string): string;
2195
2382
  /** Full-text search scoped to one inbox. */
2196
2383
  searchMessages(address: string, params: SearchMessagesParams): Page<Message>;
2197
- listThreads(address: string): Page<Thread>;
2384
+ listThreads(address: string, params?: ListThreadsParams): Page<Thread>;
2198
2385
  /** Thread-level search (subject / snippet / participant substring). */
2199
2386
  searchThreads(address: string, params: SearchMessagesParams): Page<Thread>;
2387
+ private paginateThreads;
2200
2388
  /** Fetch one thread (with messages, oldest-first) by id under an inbox. */
2201
2389
  getThread(address: string, threadId: string): ThreadDetail;
2202
2390
  /**
@@ -2251,7 +2439,7 @@ declare class MockBackend {
2251
2439
  listContactLists(address: string): Page<ContactListEntry> | undefined;
2252
2440
  /** Delete a contact-list entry by id; returns false when it was not found. */
2253
2441
  deleteContactListEntry(_address: string, entryId: string): boolean;
2254
- /** Onboard a domain, mirroring the server's per-mode record set + status. Idempotent on the name. */
2442
+ /** Add a delegated domain and return only the customer-published nameservers. */
2255
2443
  onboardDomain(req: OnboardDomainRequest): Domain;
2256
2444
  /** List onboarded domains (records omitted on the summary, mirroring the server). */
2257
2445
  listDomains(): Page<Domain>;
@@ -2268,6 +2456,12 @@ declare class MockBackend {
2268
2456
  offboardDomain(domain: string): boolean;
2269
2457
  /** Get one async job's poll status; undefined when the id is unknown. */
2270
2458
  getJob(jobId: string): Job | undefined;
2459
+ quoteDomain(req: QuoteDomainRequest): DomainQuote;
2460
+ requestDomainPurchase(req: RequestDomainPurchaseRequest): CommerceRequest;
2461
+ requestPlanChange(req: RequestPlanChangeRequest): CommerceRequest;
2462
+ getCommerceRequest(requestId: string): CommerceRequest | undefined;
2463
+ cancelCommerceRequest(requestId: string): CommerceRequest | undefined;
2464
+ listCommerceRequests(params?: ListCommerceRequestsParams): Page<CommerceRequest>;
2271
2465
  /**
2272
2466
  * Pre-check whether the caller's org suppresses a recipient (mirrors
2273
2467
  * `GET /v1/suppressions?recipient=…`). Returns `{recipient, suppressed, rows}`
@@ -2285,7 +2479,7 @@ declare class MockBackend {
2285
2479
  /**
2286
2480
  * Reject the WHOLE send if ANY recipient has an active org-scope suppression,
2287
2481
  * 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.
2482
+ * can drop them and retry - mirroring the live `recipient_suppressed` (422) path.
2289
2483
  */
2290
2484
  private enforceSuppression;
2291
2485
  /**
@@ -2296,19 +2490,25 @@ declare class MockBackend {
2296
2490
  private enforceSendPolicy;
2297
2491
  }
2298
2492
 
2493
+ interface DomainWaitResult {
2494
+ domain: Domain;
2495
+ outcome: "ready" | "action_required" | "needs_attention" | "timed_out" | "status_unavailable";
2496
+ resume_after_seconds: number;
2497
+ }
2498
+
2299
2499
  /**
2300
2500
  * Key-tier awareness (redesign §3.1).
2301
2501
  *
2302
2502
  * 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
2503
+ * client input for scope - the tier is derived from the key the caller already
2304
2504
  * holds, purely as a client-side hint so an app can branch (e.g. an org-tier key
2305
2505
  * MUST pick a project breadth on a list; a project/inbox key may use the bare
2306
2506
  * sugar). The server remains the source of truth; this is advisory only.
2307
2507
  *
2308
2508
  * Prefix scheme (the secret tail is unchanged across tiers):
2309
- * - `pk_agent_org_…` → {@link KeyTier.Org} (admin/console mint only)
2509
+ * - `pk_agent_org_…` → {@link KeyTier.Org} (admin/console issuance only)
2310
2510
  * - `pk_agent_proj_…` → {@link KeyTier.Project} (enrollment redeem + console)
2311
- * - `pk_agent_inbox_…` → {@link KeyTier.Inbox} (admin/console mint only)
2511
+ * - `pk_agent_inbox_…` → {@link KeyTier.Inbox} (admin/console issuance only)
2312
2512
  * - legacy `pk_agent_…` (no tier segment) → {@link KeyTier.Project}
2313
2513
  */
2314
2514
  /** The ceiling tier encoded in an agent key's prefix. */
@@ -2316,7 +2516,7 @@ type KeyTier = "org" | "project" | "inbox" | "unknown";
2316
2516
  /**
2317
2517
  * Derive the {@link KeyTier} from a raw agent key by peeking the segment after the
2318
2518
  * `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
2519
+ * `"project"` - exactly today's behavior. A non-agent credential (enrollment
2320
2520
  * token, Clerk session, empty) returns `"unknown"`.
2321
2521
  */
2322
2522
  declare function parseKeyTier(apiKey: string | undefined): KeyTier;
@@ -2334,7 +2534,7 @@ declare function tierAllowsOrgWildcard(tier: KeyTier): boolean;
2334
2534
  declare function tierNeedsExplicitBreadth(tier: KeyTier): boolean;
2335
2535
 
2336
2536
  /**
2337
- * InboxHandle an ergonomic, bound handle to a single inbox.
2537
+ * InboxHandle: an ergonomic, bound handle to a single inbox.
2338
2538
  *
2339
2539
  * Returned by `extrovert.inboxes.create(...)` and `extrovert.inbox(address)`, it scopes every operation
2340
2540
  * to one address so agent code reads naturally: `inbox.send(...)`, `inbox.waitForEmail(...)`. This
@@ -2348,7 +2548,7 @@ interface InboxHandleOptions {
2348
2548
  declare class InboxHandle {
2349
2549
  private readonly transport;
2350
2550
  private readonly options;
2351
- /** The canonical address, e.g. `agent7@smtp.extrovert.dev`. */
2551
+ /** The canonical address, e.g. `agent7@extrovertmail.com`. */
2352
2552
  readonly address: string;
2353
2553
  /** The full inbox record this handle was created from (absent when constructed by address). */
2354
2554
  readonly record: Inbox | undefined;
@@ -2394,8 +2594,8 @@ declare class InboxHandle {
2394
2594
  * Returns a three-way {@link SendOutcome}: `kind:"queued_for_review"` means a
2395
2595
  * human has to approve it and NOTHING has been delivered yet; anything else was
2396
2596
  * 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.
2597
+ * `intent` raises `IntentRequiredError` (422) instead: nothing sent, nothing
2598
+ * queued: so pass one, or read `inbox.record.effective_review_policy` first.
2399
2599
  */
2400
2600
  send(req: SendRequest, signal?: AbortSignal): Promise<SendOutcome>;
2401
2601
  /**
@@ -2403,14 +2603,14 @@ declare class InboxHandle {
2403
2603
  * the latest message) or `message_id` (reply to that message); the server
2404
2604
  * derives To / Subject / In-Reply-To / References. Set `reply_all` to reply to
2405
2605
  * every thread recipient. Returns the same three-way {@link SendOutcome} as
2406
- * {@link send} a reply is governed by the review policy too.
2606
+ * {@link send}: a reply is governed by the review policy too.
2407
2607
  */
2408
2608
  reply(req: ReplyRequest, signal?: AbortSignal): Promise<SendOutcome>;
2409
2609
  /**
2410
2610
  * Forward a message in this inbox to new recipients, preserving the original.
2411
2611
  *
2412
2612
  * 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
2613
+ * inbound thread, so it is governed by the review policy exactly like a send :
2414
2614
  * same {@link SendOutcome} union, same `intent` requirement.
2415
2615
  */
2416
2616
  forward(messageId: string, req: ForwardRequest, signal?: AbortSignal): Promise<SendOutcome>;
@@ -2511,7 +2711,7 @@ declare class InboxHandle {
2511
2711
  }
2512
2712
 
2513
2713
  /**
2514
- * `extrovert.projects` the CANONICAL project-scoped resource chain (redesign §4).
2714
+ * `extrovert.projects`: the CANONICAL project-scoped resource chain (redesign §4).
2515
2715
  *
2516
2716
  * Scope lives in the KEY; a broad (org-tier) key narrows to one project by PATH.
2517
2717
  * The headline chain is `x.projects.inboxes.*`, mirroring
@@ -2526,7 +2726,7 @@ declare class InboxHandle {
2526
2726
  *
2527
2727
  * Operations are keyed by the OPAQUE `inbox_id` (the inbox's email address is also
2528
2728
  * 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`).
2729
+ * wildcard: only an org-tier key may use it (others get 403 `forbidden_scope`).
2530
2730
  *
2531
2731
  * The bare `x.inboxes.*` / `x.inbox(address)` surface is curl-style sugar that
2532
2732
  * resolves to the key's default project; this chain is the contract-canonical one.
@@ -2538,7 +2738,7 @@ interface ProjectsContext {
2538
2738
  handleOptions: InboxHandleOptions;
2539
2739
  }
2540
2740
  /**
2541
- * `x.projects.inboxes` create / list / get / update / delete inboxes, plus the
2741
+ * `x.projects.inboxes`: create / list / get / update / delete inboxes, plus the
2542
2742
  * send / reply / message / thread / wait operations, all scoped to one project (or
2543
2743
  * the `-` org wildcard for an org-tier key). List returns a {@link ListPage} that
2544
2744
  * auto-paginates over the opaque-cursor {@link import("../pagination.js").List} envelope.
@@ -2574,8 +2774,8 @@ declare class ProjectInboxes {
2574
2774
  * Returns a three-way {@link SendOutcome}: `kind:"queued_for_review"` means a
2575
2775
  * human has to approve it and NOTHING has been delivered yet; anything else was
2576
2776
  * 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.
2777
+ * `intent` raises `IntentRequiredError` (422) instead: nothing sent, nothing
2778
+ * queued: so pass one, or read `inbox.record.effective_review_policy` first.
2579
2779
  */
2580
2780
  send(projectId: string, inboxId: string, req: SendRequest, signal?: AbortSignal): Promise<SendOutcome>;
2581
2781
  /** Reply within a thread from an inbox in `projectId`. See {@link send} on the return union. */
@@ -2610,14 +2810,14 @@ declare class ProjectInboxes {
2610
2810
  *
2611
2811
  * The frozen contract project-prefixes ONLY the inbox collection/item/credentials
2612
2812
  * routes (`/v1/projects/{project_id}/inboxes[/{inbox_id}][/credentials]`); the
2613
- * send/reply/forward/message/thread/wait sub-ops have NO project-prefixed path
2813
+ * send/reply/forward/message/thread/wait sub-ops have NO project-prefixed path :
2614
2814
  * they address the inbox by its opaque id directly (`/v1/inboxes/{inbox_id}/…`),
2615
2815
  * where the project is implicit in (and enforced by) the inbox id server-side.
2616
2816
  *
2617
2817
  * So for these sub-ops `projectId` cannot be carried on the URL and is NOT a URL
2618
2818
  * selector. The adversarial review flagged that silently discarding it makes the
2619
2819
  * 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
2820
+ * symmetry with create/list/get/update/delete: the more disruptive option) but
2621
2821
  * VALIDATE it rather than ignore it. We reject the two client mistakes we can catch
2622
2822
  * without a round-trip:
2623
2823
  * - a blank / whitespace-only `projectId` (a required selector everywhere else in
@@ -2629,12 +2829,12 @@ declare class ProjectInboxes {
2629
2829
  private ref;
2630
2830
  }
2631
2831
  /**
2632
- * `extrovert.projects` the canonical project-scoped resource namespace. Today it
2832
+ * `extrovert.projects`: the canonical project-scoped resource namespace. Today it
2633
2833
  * exposes the `inboxes` chain (`x.projects.inboxes.*`); future project-scoped
2634
2834
  * resources (domains, agents) hang off the same namespace.
2635
2835
  */
2636
2836
  declare class Projects {
2637
- /** `x.projects.inboxes.*` the canonical inbox chain. */
2837
+ /** `x.projects.inboxes.*`: the canonical inbox chain. */
2638
2838
  readonly inboxes: ProjectInboxes;
2639
2839
  constructor(ctx: ProjectsContext);
2640
2840
  }
@@ -2655,25 +2855,26 @@ interface ResourceContext {
2655
2855
  */
2656
2856
  keyTier: KeyTier;
2657
2857
  }
2658
- /** `extrovert.inboxes` create, list, get, update, delete inboxes. */
2858
+ /** `extrovert.inboxes`: create, list, get, update, delete inboxes. */
2659
2859
  declare class Inboxes {
2660
2860
  private readonly ctx;
2661
2861
  constructor(ctx: ResourceContext);
2662
2862
  /**
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.
2863
+ * Create an inbox. The default path creates an address on `extrovertmail.com`
2864
+ * for paid accounts or `free.extrovertmail.com` for free signups, so it returns
2865
+ * a live inbox in one call.
2665
2866
  *
2666
2867
  * Pass `metadata` to attach arbitrary key-value data, and `client_id` for idempotent creation
2667
2868
  * (re-calling with the same id returns the same inbox, with its metadata replayed verbatim).
2668
2869
  */
2669
2870
  create(req?: CreateInboxRequest, signal?: AbortSignal): Promise<InboxHandle>;
2670
2871
  /**
2671
- * List inboxes visible to the calling key (the bare curl-sugar surface resolves
2872
+ * List inboxes visible to the calling key (the bare curl-sugar surface: resolves
2672
2873
  * to the key's default project). An org-tier key has no single default project, so
2673
2874
  * the bare list is ambiguous: fail fast client-side with a BreadthRequiredError that
2674
2875
  * names the next call, matching the MCP surface, instead of round-tripping to a 400.
2675
2876
  * Use `extrovert.projects.inboxes.list("<project_id>")` or `"-"` (org subtree) for
2676
- * an org key. The check is advisory the server stays authoritative.
2877
+ * an org key. The check is advisory: the server stays authoritative.
2677
2878
  */
2678
2879
  list(params?: ListInboxesParams, signal?: AbortSignal): Promise<Page<Inbox>>;
2679
2880
  /** Fetch a single inbox and return an ergonomic handle bound to it. */
@@ -2694,7 +2895,7 @@ declare class Inboxes {
2694
2895
  delete(address: string, signal?: AbortSignal): Promise<void>;
2695
2896
  }
2696
2897
  /**
2697
- * `extrovert.messages` read a message, fetch its raw bytes, mark it read.
2898
+ * `extrovert.messages`: read a message, fetch its raw bytes, mark it read.
2698
2899
  *
2699
2900
  * Reply and forward are inbox-scoped (the server resolves the parent and derives
2700
2901
  * recipients), so they live on the {@link InboxHandle} (`inbox.reply(...)`,
@@ -2739,21 +2940,27 @@ declare class Messages {
2739
2940
  getAttachment(inbox: string, messageId: string, attachmentId: string, signal?: AbortSignal): Promise<AttachmentDownload>;
2740
2941
  }
2741
2942
  /**
2742
- * `extrovert.threads` fetch a conversation thread (with its messages) by id,
2743
- * scoped to its owning inbox.
2943
+ * `extrovert.threads`: list, search, read, reply to, and delete conversations,
2944
+ * scoped to their owning inbox.
2744
2945
  */
2745
2946
  declare class Threads {
2746
2947
  private readonly ctx;
2747
2948
  constructor(ctx: ResourceContext);
2949
+ /** List conversations newest-active first. Pass `next_cursor` back as `cursor` for the next page. */
2950
+ list(inbox: string, params?: ListThreadsParams, signal?: AbortSignal): Promise<Page<Thread>>;
2951
+ /** Search thread subjects, snippets, and participants. Cursor pagination matches {@link list}. */
2952
+ search(inbox: string, params: SearchMessagesParams, signal?: AbortSignal): Promise<Page<Thread>>;
2748
2953
  /** Fetch one thread (+ its messages, oldest-first) by id under its owning inbox address. */
2749
2954
  get(inbox: string, threadId: string, signal?: AbortSignal): Promise<ThreadDetail>;
2955
+ /** Reply in a thread; recipients and RFC reply headers are derived server-side. */
2956
+ reply(inbox: string, req: ReplyRequest, signal?: AbortSignal): Promise<SendOutcome>;
2750
2957
  /**
2751
2958
  * Delete an entire thread (every message): move to Trash (default) or
2752
2959
  * permanently remove when `expunge` is true. `inbox` is the owning address.
2753
2960
  */
2754
2961
  delete(inbox: string, threadId: string, expunge?: boolean, signal?: AbortSignal): Promise<DeleteResult>;
2755
2962
  }
2756
- /** `extrovert.webhooks` register / list / get / update / delete HMAC-signed inbound webhooks. */
2963
+ /** `extrovert.webhooks`: register / list / get / update / delete HMAC-signed inbound webhooks. */
2757
2964
  declare class Webhooks {
2758
2965
  private readonly ctx;
2759
2966
  constructor(ctx: ResourceContext);
@@ -2774,7 +2981,7 @@ declare class Webhooks {
2774
2981
  delete(webhookId: string, signal?: AbortSignal): Promise<void>;
2775
2982
  }
2776
2983
  /**
2777
- * `extrovert.contactLists` per-inbox allow/block lists of addresses/domains.
2984
+ * `extrovert.contactLists`: per-inbox allow/block lists of addresses/domains.
2778
2985
  * A `block` entry rejects a send to a matching recipient; once an `allow` entry
2779
2986
  * exists for an inbox, sends from it are restricted to matching recipients
2780
2987
  * (allowlist mode). Entries are addressable by their opaque id (`lst_…`).
@@ -2790,12 +2997,12 @@ declare class ContactLists {
2790
2997
  delete(inbox: string, entryId: string, signal?: AbortSignal): Promise<void>;
2791
2998
  }
2792
2999
  /**
2793
- * `extrovert.suppressions` recipient opt-outs (list-unsubscribe). A recipient
3000
+ * `extrovert.suppressions`: recipient opt-outs (list-unsubscribe). A recipient
2794
3001
  * that has unsubscribed cannot be mailed by this org: a send to them is rejected
2795
3002
  * with `recipient_suppressed` ({@link RecipientSuppressedError}). Use `precheck`
2796
3003
  * before composing to skip a would-be-rejected recipient, `list` to browse the
2797
3004
  * 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
3005
+ * recipient. All reads/writes are scoped to the caller's OWN org: a
2799
3006
  * platform-global or shared-domain opt-out is never surfaced here.
2800
3007
  */
2801
3008
  declare class Suppressions {
@@ -2803,7 +3010,7 @@ declare class Suppressions {
2803
3010
  constructor(ctx: ResourceContext);
2804
3011
  /**
2805
3012
  * 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
3013
+ * composing. `suppressed: true` means a send to them would be rejected: skip
2807
3014
  * that recipient. Returns the matching org rows too (never a global/shared row).
2808
3015
  */
2809
3016
  precheck(recipient: string, signal?: AbortSignal): Promise<SuppressionPrecheck>;
@@ -2817,25 +3024,36 @@ declare class Suppressions {
2817
3024
  revoke(id: string, reason: string, signal?: AbortSignal): Promise<SuppressionEntry>;
2818
3025
  }
2819
3026
  /**
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).
3027
+ * `extrovert.domains`: read with domain:read or domain:manage; changes require
3028
+ * domain:manage. Add delegated inbox domains the customer
3029
+ * controls, read status + nameserver records inline, trigger/refresh
3030
+ * verification, and offboard. New registrations use `extrovert.commerce`: quote
3031
+ * first, create a request, then poll its status. Set `scope: "project"` to bind a
3032
+ * customer-controlled domain to the key's project; it defaults to `org`.
2827
3033
  */
2828
3034
  declare class Domains {
2829
3035
  private readonly ctx;
2830
3036
  constructor(ctx: ResourceContext);
2831
3037
  /** 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. */
3038
+ list(paramsOrSignal?: {
3039
+ page?: string;
3040
+ limit?: number;
3041
+ } | AbortSignal, signal?: AbortSignal): Promise<Page<Domain>>;
3042
+ /** Get one domain's detail, verification status, and nameserver records. */
2834
3043
  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.
3044
+ /** Wait up to 50 seconds, then return an explicit resumable outcome. No DNS writes. */
3045
+ wait(domain: string, options?: {
3046
+ timeout_seconds?: number;
3047
+ signal?: AbortSignal;
3048
+ }): Promise<DomainWaitResult>;
3049
+ /** Resume durable updates for this domain using the previous next_cursor as after. */
3050
+ events(domain: string, params?: {
3051
+ after?: string;
3052
+ limit?: number;
3053
+ }, signal?: AbortSignal): Promise<DomainStatusEventPage>;
3054
+ /**
3055
+ * Add a delegated inbox domain the customer controls. Returns the nameserver
3056
+ * records to publish and never spends money.
2839
3057
  */
2840
3058
  onboard(req: OnboardDomainRequest, signal?: AbortSignal): Promise<Domain>;
2841
3059
  /** Trigger or refresh verification for a domain; returns its (possibly advanced) status. */
@@ -2849,7 +3067,29 @@ declare class Domains {
2849
3067
  offboard(domain: string, signal?: AbortSignal): Promise<DomainOffboard>;
2850
3068
  }
2851
3069
  /**
2852
- * `extrovert.reviews` the Review Loop (HITL) agent-plane reads. A sending agent
3070
+ * `extrovert.commerce`: quote, request, cancel, and poll financial operations. Agents
3071
+ * can never approve a request through this resource; approval is a human console
3072
+ * action. Every create requires a stable idempotency key.
3073
+ */
3074
+ declare class Commerce {
3075
+ private readonly ctx;
3076
+ constructor(ctx: ResourceContext);
3077
+ private requireIdempotencyKey;
3078
+ /** Quote a domain without purchasing, reserving, or approving it. */
3079
+ quoteDomain(req: QuoteDomainRequest, signal?: AbortSignal): Promise<DomainQuote>;
3080
+ /** Create a durable domain-purchase request for human approval. */
3081
+ requestDomainPurchase(req: RequestDomainPurchaseRequest, signal?: AbortSignal): Promise<CommerceRequest>;
3082
+ /** Create a durable plan-upgrade or downgrade request for human approval. */
3083
+ requestPlanChange(req: RequestPlanChangeRequest, signal?: AbortSignal): Promise<CommerceRequest>;
3084
+ /** Poll one request's exact blockers, approval URL, and next-action guidance. */
3085
+ get(requestId: string, signal?: AbortSignal): Promise<CommerceRequest>;
3086
+ /** Withdraw this agent's request while its durable state still permits cancellation. */
3087
+ cancel(requestId: string, signal?: AbortSignal): Promise<CommerceRequest>;
3088
+ /** List visible commerce requests using the API's opaque page token. */
3089
+ list(params?: ListCommerceRequestsParams, signal?: AbortSignal): Promise<Page<CommerceRequest>>;
3090
+ }
3091
+ /**
3092
+ * `extrovert.reviews`: the Review Loop (HITL) agent-plane reads. A sending agent
2853
3093
  * monitors its submissions in the human-review queue: list/get a review request and
2854
3094
  * read its append-only thread of turns (intent, drafts, human comments/edits/
2855
3095
  * decisions, captured diffs). Submitting FOR review rides `inbox.send` /
@@ -2859,7 +3099,7 @@ declare class Domains {
2859
3099
  declare class Reviews {
2860
3100
  private readonly ctx;
2861
3101
  /**
2862
- * `extrovert.reviews.events` the Review Loop (HITL) realtime plane: drain,
3102
+ * `extrovert.reviews.events`: the Review Loop (HITL) realtime plane: drain,
2863
3103
  * long-poll, and ack the durable nudge queue (the AUTHORITATIVE liveness source;
2864
3104
  * SSE/webhook are best-effort fast paths on top of it).
2865
3105
  */
@@ -2874,20 +3114,20 @@ declare class Reviews {
2874
3114
  /**
2875
3115
  * Get the human's assembled feedback (M5): the diff + comments + decision + the
2876
3116
  * 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.
3117
+ * the human wanted. $0 LLM: pure assembly on our side.
2878
3118
  */
2879
3119
  feedback(reviewId: string, signal?: AbortSignal): Promise<ReviewFeedback>;
2880
3120
  /**
2881
3121
  * Post a chat turn on a review's thread (M5): an agent question to the human
2882
3122
  * reviewer; flips in_review -> chatting on the first turn. Idempotent on the
2883
- * optional `idempotencyKey` (the `Idempotency-Key` header). $0 LLM you compose it.
3123
+ * optional `idempotencyKey` (the `Idempotency-Key` header). $0 LLM: you compose it.
2884
3124
  */
2885
3125
  chat(reviewId: string, req: PostReviewChatRequest, idempotencyKey?: string, signal?: AbortSignal): Promise<Review>;
2886
3126
  /**
2887
3127
  * Post a new agent draft under a parent_revision CAS (M5; D17). parent_revision
2888
3128
  * 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.
3129
+ * human always wins: re-read, re-apply, retry). On success the draft is re-rendered
3130
+ * in place (revision++) and returns to needs_review. $0 LLM: you compose the redraft.
2891
3131
  */
2892
3132
  revise(reviewId: string, req: SubmitRevisionRequest, signal?: AbortSignal): Promise<Review>;
2893
3133
  /**
@@ -2900,9 +3140,9 @@ declare class Reviews {
2900
3140
  * assert "I reviewed this against rules vX and no change is needed", advancing the
2901
3141
  * draft's composed_* versions with no new draft, no revision bump, no nudge. A
2902
3142
  * 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().
3143
+ * releasable on the next reconciliation sweep: the cheap counterpart to revise().
2904
3144
  * against_version above the category's current rules-version is 400; a terminal draft
2905
- * 409s. $0 LLM you judged.
3145
+ * 409s. $0 LLM: you judged.
2906
3146
  */
2907
3147
  restamp(reviewId: string, req: RestampReviewRequest, signal?: AbortSignal): Promise<Review>;
2908
3148
  /**
@@ -2917,22 +3157,22 @@ declare class Reviews {
2917
3157
  decisionContext(reviewId: string, signal?: AbortSignal): Promise<ReviewDecisionContext>;
2918
3158
  /**
2919
3159
  * 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
3160
+ * PLATFORM sends with the COMPOSER's credentials (the reviewer NEVER holds
3161
+ * mailbox:send on an inbox it doesn't own: the credential boundary); reject → back to
2922
3162
  * 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,
3163
+ * version are the CAS (409 STALE on mismatch, NO mutation: the human always wins,
2924
3164
  * 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.
3165
+ * FORCE a reject to the human regardless of intent: `forced_by_breaker` names it. $0
3166
+ * LLM: you judged; we route, send, and enforce the breakers.
2927
3167
  */
2928
3168
  decide(reviewId: string, req: ReviewerDecisionRequest, signal?: AbortSignal): Promise<ReviewerDecisionResult>;
2929
3169
  }
2930
3170
  /**
2931
- * `extrovert.reviews.events` drain / long-poll / ack the durable review nudge
3171
+ * `extrovert.reviews.events`: drain / long-poll / ack the durable review nudge
2932
3172
  * queue (spec §5.9). `list` is a non-blocking, side-effect-free drain of the next
2933
3173
  * un-acked nudges in FIFO seq order (strict per review); `wait` long-polls
2934
3174
  * (~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).
3175
+ * monotonically (idempotent: re-acking an older seq is a no-op).
2936
3176
  */
2937
3177
  declare class ReviewEvents {
2938
3178
  private readonly ctx;
@@ -2945,10 +3185,10 @@ declare class ReviewEvents {
2945
3185
  ack(req: AckReviewEventRequest, signal?: AbortSignal): Promise<AckReviewEventResult>;
2946
3186
  }
2947
3187
  /**
2948
- * `extrovert.categories` the Review Loop category registry (D9/D10). Browse and
3188
+ * `extrovert.categories`: the Review Loop category registry (D9/D10). Browse and
2949
3189
  * MATCH an existing category before composing (like a skills registry), or propose
2950
3190
  * 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
3191
+ * cross-agent-404 exception); identity is opaque cat_ ids: nothing keys on the
2952
3192
  * name, so renames never break a reference. `match` is a pure lexical filter (NO
2953
3193
  * LLM on our side); the agent does the semantic matching. Merging / deleting a
2954
3194
  * category is a human (console) action, not exposed here (D17).
@@ -2962,12 +3202,12 @@ declare class Categories {
2962
3202
  get(categoryId: string, signal?: AbortSignal): Promise<Category>;
2963
3203
  /** Propose a new category; it stands immediately and writes a create audit row. */
2964
3204
  propose(req: ProposeCategoryRequest, signal?: AbortSignal): Promise<Category>;
2965
- /** Rename / re-describe a category metadata only (D10). */
3205
+ /** Rename / re-describe a category: metadata only (D10). */
2966
3206
  update(categoryId: string, req: UpdateCategoryRequest, signal?: AbortSignal): Promise<Category>;
2967
3207
  /**
2968
3208
  * Read the effective risk dial (D4/D12): the account default + every category's
2969
3209
  * 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)
3210
+ * Read-only: agents read but NEVER flip the dial; setting it is a human (console)
2971
3211
  * action (D16).
2972
3212
  */
2973
3213
  riskDial(signal?: AbortSignal): Promise<RiskDial>;
@@ -2979,14 +3219,14 @@ declare class Categories {
2979
3219
  graduationStatus(categoryId: string, signal?: AbortSignal): Promise<GraduationStatus>;
2980
3220
  /**
2981
3221
  * 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
3222
+ * returns the current gate status. It does NOT change the category state: flipping
2983
3223
  * the bit is a human (console) action; an agent only proposes.
2984
3224
  */
2985
3225
  proposeGraduation(categoryId: string, req?: ProposeGraduationRequest, signal?: AbortSignal): Promise<GraduationStatus>;
2986
3226
  /**
2987
3227
  * Read the D19/§8 backlog-reconciliation status: how many of the category's QUEUED
2988
3228
  * 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
3229
+ * integer compare, $0 LLM). Read-only: you READ the picture; the human (console
2990
3230
  * scan-backlog) or the graduate/rule-change hooks TRIGGER the actual reconciliation
2991
3231
  * sweep that releases current-enough drafts and nudges stale ones to redraft.
2992
3232
  */
@@ -3002,14 +3242,14 @@ declare class Categories {
3002
3242
  pacingState(categoryId: string, signal?: AbortSignal): Promise<CategoryPacingState>;
3003
3243
  }
3004
3244
  /**
3005
- * `extrovert.rules` the Review Loop writing-rule store + house-style + the §7
3245
+ * `extrovert.rules`: the Review Loop writing-rule store + house-style + the §7
3006
3246
  * 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
3247
+ * edit, promote, retire, and undo rules (the deliberate cross-agent exception: the
3008
3248
  * shared house-style is the whole pitch). `get()` returns the ORDERED active rule
3009
3249
  * set with the precedence ladder applied SERVER-SIDE (NO LLM on our side); the agent
3010
3250
  * reconciles the list semantically. Rules are append-only by supersession; undo
3011
3251
  * restores the prior version as a forward 'restore' supersession. Identity is opaque
3012
- * rule_/rln_/udo_ ids nothing keys on a name.
3252
+ * rule_/rln_/udo_ ids: nothing keys on a name.
3013
3253
  */
3014
3254
  declare class Rules {
3015
3255
  private readonly ctx;
@@ -3020,21 +3260,21 @@ declare class Rules {
3020
3260
  * Save / edit a rule (append-only by supersession; D11). An agent-plane save is
3021
3261
  * ALWAYS project-layer: the saved rule's `rule_layer` is `project`, bound to the
3022
3262
  * key's project. Agents cannot author org-layer / house-style (`rule_layer:"org"`)
3023
- * rules in v1 that is a console/admin action.
3263
+ * rules in v1: that is a console/admin action.
3024
3264
  */
3025
3265
  save(req: SaveRuleRequest, signal?: AbortSignal): Promise<Rule>;
3026
3266
  /** Promote a rule between the category and general/house-style layers. */
3027
3267
  promote(ruleId: string, toScope: "general" | "category", signal?: AbortSignal): Promise<Rule>;
3028
- /** Retire a rule soft delete; the history survives as training data. */
3268
+ /** Retire a rule: soft delete; the history survives as training data. */
3029
3269
  retire(ruleId: string, signal?: AbortSignal): Promise<Rule>;
3030
3270
  /** Read the rule/category change audit log (the safety net, D11). */
3031
3271
  audit(params?: GetRuleAuditParams, signal?: AbortSignal): Promise<Page<RuleAuditEntry>>;
3032
- /** Undo a rule change by its audit-row id (udo_…) restore the prior version. */
3272
+ /** Undo a rule change by its audit-row id (udo_…): restore the prior version. */
3033
3273
  undo(udoId: string, signal?: AbortSignal): Promise<Rule>;
3034
3274
  }
3035
3275
 
3036
3276
  /**
3037
- * ExtrovertClient the entry point.
3277
+ * ExtrovertClient - the entry point.
3038
3278
  *
3039
3279
  * ```ts
3040
3280
  * import { Extrovert } from "@extrovert.dev/sdk";
@@ -3085,28 +3325,30 @@ interface ExtrovertClientOptions {
3085
3325
  mockBackend?: MockBackend;
3086
3326
  }
3087
3327
  declare class ExtrovertClient {
3088
- /** `extrovert.inboxes` create / list / get / update / delete inboxes. */
3328
+ /** `extrovert.inboxes` - create / list / get / update / delete inboxes. */
3089
3329
  readonly inboxes: Inboxes;
3090
- /** `extrovert.messages` read a message, reply to it (threaded). */
3330
+ /** `extrovert.messages` - read a message, reply to it (threaded). */
3091
3331
  readonly messages: Messages;
3092
- /** `extrovert.threads` fetch a conversation thread. */
3332
+ /** `extrovert.threads` - fetch a conversation thread. */
3093
3333
  readonly threads: Threads;
3094
- /** `extrovert.webhooks` register HMAC-signed inbound webhooks. */
3334
+ /** `extrovert.webhooks` - register HMAC-signed inbound webhooks. */
3095
3335
  readonly webhooks: Webhooks;
3096
- /** `extrovert.contactLists` per-inbox allow/block lists of addresses/domains. */
3336
+ /** `extrovert.contactLists` - per-inbox allow/block lists of addresses/domains. */
3097
3337
  readonly contactLists: ContactLists;
3098
- /** `extrovert.suppressions` recipient opt-outs (list-unsubscribe); precheck/list/revoke. */
3338
+ /** `extrovert.suppressions` - recipient opt-outs (list-unsubscribe); precheck/list/revoke. */
3099
3339
  readonly suppressions: Suppressions;
3100
- /** `extrovert.domains` the customer's domains (privileged; domain:manage scope). */
3340
+ /** `extrovert.domains` - domain readiness and setup (domain:read or domain:manage to read; domain:manage to change). */
3101
3341
  readonly domains: Domains;
3102
- /** `extrovert.reviews` the Review Loop (HITL) agent-plane reads. */
3342
+ /** `extrovert.commerce` - quote/request/cancel/poll financial actions; no agent approval methods. */
3343
+ readonly commerce: Commerce;
3344
+ /** `extrovert.reviews` - the Review Loop (HITL) agent-plane reads. */
3103
3345
  readonly reviews: Reviews;
3104
- /** `extrovert.categories` the Review Loop category registry (browse/propose/curate). */
3346
+ /** `extrovert.categories` - the Review Loop category registry (browse/propose/curate). */
3105
3347
  readonly categories: Categories;
3106
- /** `extrovert.rules` the Review Loop writing-rule store + house-style + audit/undo. */
3348
+ /** `extrovert.rules` - the Review Loop writing-rule store + house-style + audit/undo. */
3107
3349
  readonly rules: Rules;
3108
3350
  /**
3109
- * `extrovert.projects` the CANONICAL project-scoped chain. The headline is
3351
+ * `extrovert.projects` - the CANONICAL project-scoped chain. The headline is
3110
3352
  * `extrovert.projects.inboxes.*` (create/list/get/update/delete/send/...), keyed by
3111
3353
  * the opaque `inbox_id` and scoped to a `{project_id}` path (or `-` for the org
3112
3354
  * wildcard on an org-tier key). The bare `extrovert.inboxes` surface is curl sugar
@@ -3122,7 +3364,7 @@ declare class ExtrovertClient {
3122
3364
  readonly apiVersion: string;
3123
3365
  /**
3124
3366
  * 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
3367
+ * | `inbox` | `unknown`). Advisory client-side hint only - the server is the source
3126
3368
  * of truth. Lets an app branch (e.g. require a project pick for an org-tier key).
3127
3369
  */
3128
3370
  readonly keyTier: KeyTier;
@@ -3130,18 +3372,20 @@ declare class ExtrovertClient {
3130
3372
  private readonly handleOptions;
3131
3373
  constructor(options?: ExtrovertClientOptions);
3132
3374
  /**
3133
- * Redeem an enrollment token (`pk_enroll_...`) and mint a scoped agent key.
3375
+ * Redeem an enrollment token (`pk_enroll_...`) and issue a scoped agent key.
3134
3376
  *
3135
3377
  * 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
3378
+ * Returns the raw `EnrollResponse` - to immediately use the issued key, prefer
3137
3379
  * {@link ExtrovertClient.enrolled}.
3138
3380
  */
3139
3381
  enroll(req: EnrollRequest, signal?: AbortSignal): Promise<EnrollResponse>;
3140
3382
  /**
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.
3383
+ * Request a free account in one unauthenticated call. When free signup is
3384
+ * enabled, this provisions a tenant plus a first inbox and returns a
3385
+ * verification-only agent key. That key can only call {@link verify}; it cannot
3386
+ * read or send mail. A one-time code is emailed to `human_email`. Call
3387
+ * {@link verify} with the code to activate the account and receive full scopes.
3388
+ * Idempotent on `human_email`: re-calling rotates the key and resends the code.
3145
3389
  * When free signup is paused, this throws an `ApiError` with status 403 and
3146
3390
  * code `signup_disabled` without creating account state.
3147
3391
  */
@@ -3158,15 +3402,15 @@ declare class ExtrovertClient {
3158
3402
  /** Introspect the principal behind the current key (`GET /v1/auth/me`). */
3159
3403
  whoami(signal?: AbortSignal): Promise<WhoAmI>;
3160
3404
  /**
3161
- * Poll the status of an async job (`GET /v1/jobs/{job_id}`) currently only
3405
+ * Poll the status of an async job (`GET /v1/jobs/{job_id}`) - currently only
3162
3406
  * the domain-offboard teardown started by {@link Domains.offboard} enqueues
3163
3407
  * one. `status` is terminal on succeeded/failed/cancelled; keep polling
3164
3408
  * otherwise. An unknown or foreign job id is a {@link NotFoundError}.
3165
3409
  */
3166
3410
  getJob(jobId: string, signal?: AbortSignal): Promise<Job>;
3167
3411
  /**
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.
3412
+ * Redeem an enrollment token and return a *new* client already authenticated with the issued
3413
+ * agent key - the natural "redeem then act" flow for an agent.
3170
3414
  *
3171
3415
  * ```ts
3172
3416
  * const bootstrap = new Extrovert({ apiKey: enrollmentToken });
@@ -3182,7 +3426,7 @@ declare class ExtrovertClient {
3182
3426
  enrollment: EnrollResponse;
3183
3427
  }>;
3184
3428
  /**
3185
- * Get an ergonomic handle to an existing inbox by address without an extra round-trip. Use this
3429
+ * Get an ergonomic handle to an existing inbox by address - without an extra round-trip. Use this
3186
3430
  * when you already know the address (e.g. from a previous create) and want to send/wait/reply.
3187
3431
  * Call {@link InboxHandle.refresh} to load the full record.
3188
3432
  */
@@ -3225,7 +3469,7 @@ declare class ExtrovertClient {
3225
3469
  */
3226
3470
  /**
3227
3471
  * 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
3472
+ * frozen OpenAPI). Adding a member is a contract change - keep it in lockstep with
3229
3473
  * the Go `ProblemCode` enum.
3230
3474
  */
3231
3475
  type ProblemCode = "bad_request" | "unauthorized" | "forbidden_scope" | "not_found" | "conflict" | "idempotency_conflict" | "breadth_required" | "quota_exceeded" | "rate_limited" | "domain_not_allowed" | "recipient_blocked" | "recipient_suppressed" | "not_configured" | "domain_unavailable" | "internal" | "intent_required" | "wrong_state" | "terminal" | "stale" | "born_stale" | "send_needs_reconciliation" | "graduation_locked" | "maturity_gate_unmet" | "scope_taken" | "unavailable";
@@ -3238,11 +3482,11 @@ declare const PROBLEM_CODES: readonly ProblemCode[];
3238
3482
  * compare-and-set (`stale`) and a redraft built against an older rule high-water
3239
3483
  * (`born_stale`) describe a situation a retry can fix, and each only a bounded
3240
3484
  * 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
3485
+ * resubmit). `wrong_state` means the verb is wrong, not the timing - read the
3242
3486
  * `allowed_action` hints and pick another one. `terminal` means the review is
3243
3487
  * finished forever; a `front_run_next` nudge is already waiting on the queue
3244
3488
  * with the outcome. `send_needs_reconciliation` means a delivery attempt is
3245
- * unconfirmed resending is precisely how a message goes out twice.
3489
+ * unconfirmed - resending is precisely how a message goes out twice.
3246
3490
  *
3247
3491
  * `intent_required` is listed false because retrying the SAME bytes fails
3248
3492
  * identically: the fix is to ADD an `intent` and send a different request. The
@@ -3347,38 +3591,38 @@ declare class ApiError extends Error {
3347
3591
  /** True for 5xx responses (server errors that may succeed on retry). */
3348
3592
  get isServerError(): boolean;
3349
3593
  }
3350
- /** 401 the agent key / enrollment token was missing, malformed, expired, or revoked. */
3594
+ /** 401 - the agent key / enrollment token was missing, malformed, expired, or revoked. */
3351
3595
  declare class AuthenticationError extends ApiError {
3352
3596
  }
3353
- /** 403 authenticated, but the key's scopes don't permit this action (capability denied). */
3597
+ /** 403 - authenticated, but the key's scopes don't permit this action (capability denied). */
3354
3598
  declare class PermissionError extends ApiError {
3355
3599
  }
3356
3600
  /**
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
3601
+ * 403 `forbidden_scope` - the call is outside the key's CEILING (e.g. a non-org key
3602
+ * on the org-wide wildcard, or an issuance that would escalate). A redesign-specific
3359
3603
  * subclass of {@link PermissionError} so existing `instanceof PermissionError`
3360
3604
  * branches keep working.
3361
3605
  */
3362
3606
  declare class ForbiddenScopeError extends PermissionError {
3363
3607
  }
3364
3608
  /**
3365
- * 400 `breadth_required` an org-tier key/operator issued a bare list that needs a
3609
+ * 400 `breadth_required` - an org-tier key/operator issued a bare list that needs a
3366
3610
  * breadth pick; the problem `errors`/`detail` name the next call
3367
3611
  * (`/v1/projects/{id}/inboxes` or `/v1/projects/-/inboxes`).
3368
3612
  */
3369
3613
  declare class BreadthRequiredError extends ApiError {
3370
3614
  }
3371
- /** 404 the inbox, message, thread, or webhook does not exist (or isn't visible to this tenant). */
3615
+ /** 404 - the inbox, message, thread, or webhook does not exist (or isn't visible to this tenant). */
3372
3616
  declare class NotFoundError extends ApiError {
3373
3617
  }
3374
- /** 409 a conflicting state, e.g. an enrollment token that already minted its max of N inboxes. */
3618
+ /** 409 - a conflicting state, e.g. an enrollment token that already created its maximum number of inboxes. */
3375
3619
  declare class ConflictError extends ApiError {
3376
3620
  }
3377
- /** 422 the request body failed validation; see `body.error.details`. */
3621
+ /** 422 - the request body failed validation; see `body.error.details`. */
3378
3622
  declare class ValidationError extends ApiError {
3379
3623
  }
3380
3624
  /**
3381
- * 422 `recipient_suppressed` a send/reply/forward was rejected because one or
3625
+ * 422 `recipient_suppressed` - a send/reply/forward was rejected because one or
3382
3626
  * more recipients have opted out (list-unsubscribe / suppression). The whole send
3383
3627
  * is rejected (never a silent partial drop). {@link suppressedRecipients} lists the
3384
3628
  * exact addresses to drop; retry the send without them. The scope/origin of the
@@ -3386,12 +3630,12 @@ declare class ValidationError extends ApiError {
3386
3630
  * existing `instanceof ValidationError` branches keep working.
3387
3631
  */
3388
3632
  declare class RecipientSuppressedError extends ValidationError {
3389
- /** The recipient addresses that are suppressed drop these and retry. */
3633
+ /** The recipient addresses that are suppressed - drop these and retry. */
3390
3634
  readonly suppressedRecipients: string[];
3391
3635
  constructor(args: ConstructorParameters<typeof ApiError>[0]);
3392
3636
  }
3393
3637
  /**
3394
- * 422 `intent_required` the inbox's resolved review policy requires a human to
3638
+ * 422 `intent_required` - the inbox's resolved review policy requires a human to
3395
3639
  * see this message before it goes out, and the request carried no `intent`.
3396
3640
  *
3397
3641
  * **Nothing was sent and nothing was queued.** The server checks this before it
@@ -3400,7 +3644,7 @@ declare class RecipientSuppressedError extends ValidationError {
3400
3644
  * splice in, and the human-readable remediation (the full recipe, including how
3401
3645
  * to monitor the resulting review) is on `.message` / `.problem.detail`.
3402
3646
  *
3403
- * Under `require_review` the default for every account this is the FIRST
3647
+ * Under `require_review` - the default for every account - this is the FIRST
3404
3648
  * thing most agents hit. Read `effective_review_policy` on
3405
3649
  * `GET /v1/inboxes/{id}` once at start-up and compose an intent up front instead
3406
3650
  * of learning the policy by being refused. A subclass of {@link ValidationError}
@@ -3409,7 +3653,7 @@ declare class RecipientSuppressedError extends ValidationError {
3409
3653
  declare class IntentRequiredError extends ValidationError {
3410
3654
  /** The resolved review policy, e.g. `require_review`. */
3411
3655
  readonly policy: string | undefined;
3412
- /** Where the policy came from a per-inbox override or the account default. */
3656
+ /** Where the policy came from - a per-inbox override or the account default. */
3413
3657
  readonly policySource: string | undefined;
3414
3658
  /** Literal JSON to merge into the original request body, then retry once. */
3415
3659
  readonly retryWith: string | undefined;
@@ -3427,7 +3671,7 @@ declare class IntentRequiredError extends ValidationError {
3427
3671
  declare class ReviewConflictError extends ConflictError {
3428
3672
  /** The review's CURRENT state (`needs_review`, `approved`, `sent`, …). */
3429
3673
  readonly currentState: string | undefined;
3430
- /** The current revision pass it as `parent_revision` on a legal retry. */
3674
+ /** The current revision - pass it as `parent_revision` on a legal retry. */
3431
3675
  readonly currentRevision: number | undefined;
3432
3676
  /** The current row version (the optional belt-and-braces CAS). */
3433
3677
  readonly currentVersion: number | undefined;
@@ -3436,13 +3680,13 @@ declare class ReviewConflictError extends ConflictError {
3436
3680
  constructor(args: ConstructorParameters<typeof ApiError>[0]);
3437
3681
  /**
3438
3682
  * Whether retrying the same call could ever succeed. False for every subclass
3439
- * except {@link StaleError} and {@link BornStaleError} and true there only
3683
+ * except {@link StaleError} and {@link BornStaleError} - and true there only
3440
3684
  * after re-reading and re-applying on top of the other party's change.
3441
3685
  */
3442
3686
  get isRetryable(): boolean;
3443
3687
  }
3444
3688
  /**
3445
- * 409 `stale` the `(revision[, version])` you named is no longer current
3689
+ * 409 `stale` - the `(revision[, version])` you named is no longer current
3446
3690
  * because a human or reviewer moved the draft. **Nothing was mutated.**
3447
3691
  *
3448
3692
  * The one genuinely retryable conflict, and bounded (≤3): re-read the draft and
@@ -3455,7 +3699,7 @@ declare class StaleError extends ReviewConflictError {
3455
3699
  get isRetryable(): boolean;
3456
3700
  }
3457
3701
  /**
3458
- * 409 `wrong_state` this VERB is illegal from the review's current state, but
3702
+ * 409 `wrong_state` - this VERB is illegal from the review's current state, but
3459
3703
  * the draft is still live.
3460
3704
  *
3461
3705
  * **Never retry the same verb**; the timing is not the problem, the choice of
@@ -3464,7 +3708,7 @@ declare class StaleError extends ReviewConflictError {
3464
3708
  declare class WrongStateError extends ReviewConflictError {
3465
3709
  }
3466
3710
  /**
3467
- * 409 `terminal` the review has already finished (sent / auto_sent /
3711
+ * 409 `terminal` - the review has already finished (sent / auto_sent /
3468
3712
  * cancelled). Nothing will EVER succeed on it.
3469
3713
  *
3470
3714
  * **Stop.** A `front_run_next` review event is waiting on the durable queue with
@@ -3478,12 +3722,12 @@ declare class TerminalError extends ReviewConflictError {
3478
3722
  constructor(args: ConstructorParameters<typeof ApiError>[0]);
3479
3723
  }
3480
3724
  /**
3481
- * 409 `born_stale` the redraft was composed against an OLDER writing-rule
3725
+ * 409 `born_stale` - the redraft was composed against an OLDER writing-rule
3482
3726
  * high-water than the one now in force. **Nothing was mutated** and the composer
3483
3727
  * has been re-nudged.
3484
3728
  *
3485
3729
  * 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
3730
+ * resubmit - or `restamp_review` when re-reading shows nothing genuinely needed
3487
3731
  * to change. Restamping when the body DID need to change makes the draft lie to
3488
3732
  * the born-stale accounting, so do it only for a true no-op.
3489
3733
  */
@@ -3491,7 +3735,7 @@ declare class BornStaleError extends ReviewConflictError {
3491
3735
  get isRetryable(): boolean;
3492
3736
  }
3493
3737
  /**
3494
- * 409 `send_needs_reconciliation` a delivery attempt reached (or may have
3738
+ * 409 `send_needs_reconciliation` - a delivery attempt reached (or may have
3495
3739
  * reached) the mail provider and the process died before recording the outcome,
3496
3740
  * so the review is parked for recover-by-Message-ID.
3497
3741
  *
@@ -3502,17 +3746,17 @@ declare class BornStaleError extends ReviewConflictError {
3502
3746
  declare class SendNeedsReconciliationError extends ReviewConflictError {
3503
3747
  }
3504
3748
  /**
3505
- * 409 `idempotency_conflict` the same `Idempotency-Key` was replayed with a
3749
+ * 409 `idempotency_conflict` - the same `Idempotency-Key` was replayed with a
3506
3750
  * DIFFERENT request body within the same scope. The replay key is a hash of the
3507
3751
  * raw bytes, so "same message, different spelling" counts as different.
3508
3752
  *
3509
3753
  * 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.
3754
+ * identical body, or use a new key for the genuinely new message.
3511
3755
  */
3512
3756
  declare class IdempotencyConflictError extends ConflictError {
3513
3757
  }
3514
3758
  /**
3515
- * 503 `unavailable` a dependency could not be read, so the request was failed
3759
+ * 503 `unavailable` - a dependency could not be read, so the request was failed
3516
3760
  * CLOSED rather than served on a guess. On the send path this specifically means
3517
3761
  * the account's review policy was unreadable: relaying unsupervised mail for a
3518
3762
  * customer whose stated policy we could not see is the failure that would be
@@ -3528,7 +3772,7 @@ declare class UnavailableError extends ApiError {
3528
3772
  retryAfter?: number;
3529
3773
  });
3530
3774
  }
3531
- /** 402 payment required (x402 test-mode). `paymentRequired` holds the raw challenge header. */
3775
+ /** 402 - payment required (x402 test-mode). `paymentRequired` holds the raw challenge header. */
3532
3776
  declare class PaymentRequiredError extends ApiError {
3533
3777
  /** The raw `PAYMENT-REQUIRED` header challenge to sign + retry (EIP-3009, Base Sepolia). */
3534
3778
  readonly paymentRequired: string | undefined;
@@ -3536,7 +3780,7 @@ declare class PaymentRequiredError extends ApiError {
3536
3780
  paymentRequired?: string;
3537
3781
  });
3538
3782
  }
3539
- /** 429 rate limited. `retryAfter` is the server's hint in seconds, when provided. */
3783
+ /** 429 - rate limited. `retryAfter` is the server's hint in seconds, when provided. */
3540
3784
  declare class RateLimitError extends ApiError {
3541
3785
  /** Seconds to wait before retrying, parsed from the `Retry-After` header. */
3542
3786
  readonly retryAfter: number | undefined;
@@ -3554,7 +3798,7 @@ declare class TimeoutError extends ApiError {
3554
3798
  }
3555
3799
 
3556
3800
  /**
3557
- * Narrowing helpers for {@link SendOutcome} the three shapes a send can answer.
3801
+ * Narrowing helpers for {@link SendOutcome} - the three shapes a send can answer.
3558
3802
  *
3559
3803
  * `inbox.send()` used to be typed as one struct with a REQUIRED `thread_id`, which
3560
3804
  * the direct-send response has never carried. The type checked; the value was
@@ -3565,7 +3809,7 @@ declare class TimeoutError extends ApiError {
3565
3809
  * has been delivered**. A human has to approve it first, and the delivery outcome
3566
3810
  * arrives later as a `sent` / `send_failed` review event. Code that treats every
3567
3811
  * 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.
3812
+ * `require_review` policy - which is every account that has not changed it.
3569
3813
  */
3570
3814
 
3571
3815
  /**
@@ -3575,14 +3819,14 @@ declare class TimeoutError extends ApiError {
3575
3819
  */
3576
3820
  declare function isQueuedForReview(res: SendOutcome): res is QueuedForReviewResult;
3577
3821
  /**
3578
- * True when the message was delivered immediately either the review-loop
3822
+ * True when the message was delivered immediately - either the review-loop
3579
3823
  * `{kind:"sent"}` body or the legacy body a bare send gets under `allow_direct`.
3580
3824
  */
3581
3825
  declare function isSentImmediately(res: SendOutcome): res is SendResult | SentResult;
3582
3826
  /**
3583
3827
  * The delivered message id, or `undefined` when the message was queued instead.
3584
3828
  *
3585
- * `undefined` here is NOT an error it is the normal answer under
3829
+ * `undefined` here is NOT an error - it is the normal answer under
3586
3830
  * `require_review`. Pair it with {@link reviewIdOf} to follow the message to its
3587
3831
  * outcome.
3588
3832
  */
@@ -3690,7 +3934,7 @@ declare function verifyWebhookSignature(options: VerifyWebhookOptions): Promise<
3690
3934
  */
3691
3935
  declare function parseWebhook(options: VerifyWebhookOptions): Promise<WebhookPayload | null>;
3692
3936
  /**
3693
- * Produce the canonical `X-Extrovert-Signature` header value for a body the exact format the Go
3937
+ * Produce the canonical `X-Extrovert-Signature` header value for a body - the exact format the Go
3694
3938
  * delivery engine emits: `t=<unix>,v1=<hex hmac-sha256("<t>.<rawbody>")>`. Mainly useful for tests
3695
3939
  * and self-hosted senders; the platform signs deliveries server-side. The Go `SignWebhook` and this
3696
3940
  * helper are pinned to the same fixed conformance vector across languages.
@@ -3701,7 +3945,7 @@ declare function signWebhook(secret: string, body: string, timestampSeconds: num
3701
3945
  * The Extrovert Review-Loop **open contract** (HITL D14, spec §11).
3702
3946
  *
3703
3947
  * 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
3948
+ * agent-facing JSON shapes that the Review Loop exposes - the shapes agents and
3705
3949
  * third-party harnesses code against. It does **not** redesign any types: it
3706
3950
  * re-exports the canonical models built across M1–M8 (see `./models`) under one
3707
3951
  * named contract surface, stamps a {@link CONTRACT_VERSION}, and publishes a
@@ -3711,7 +3955,7 @@ declare function signWebhook(secret: string, body: string, timestampSeconds: num
3711
3955
  * ## This is a contract, NOT a protocol (D14)
3712
3956
  *
3713
3957
  * Per resolved decision **D14**, the open surface is published **now** as an open,
3714
- * documented **skill + SDK contract** explicitly **not** a wire protocol and
3958
+ * documented **skill + SDK contract** - explicitly **not** a wire protocol and
3715
3959
  * **not** a standalone `/v1/contract` endpoint. The contract is exactly: these SDK
3716
3960
  * types + the agent skills (`extrovert-send-email`, `extrovert-writing-rules`) + the
3717
3961
  * docs, **versioned with the SDK** (this package). Formal protocol
@@ -3719,7 +3963,7 @@ declare function signWebhook(secret: string, body: string, timestampSeconds: num
3719
3963
  *
3720
3964
  * ## Provisional, pre-1.0 (0.x)
3721
3965
  *
3722
- * {@link CONTRACT_VERSION} is **`0.1.0-pre.6`** a deliberately **provisional**, pre-1.0
3966
+ * {@link CONTRACT_VERSION} is **`0.1.0-pre.7`** - a deliberately **provisional**, pre-1.0
3723
3967
  * contract. It is open and documented, but it MAY still evolve before 1.0: there
3724
3968
  * are no external users yet, and the **D20 shared-pool auto-send governor** is a
3725
3969
  * hard prerequisite before onboarding external users. Pin the version; expect
@@ -3729,11 +3973,11 @@ declare function signWebhook(secret: string, body: string, timestampSeconds: num
3729
3973
  *
3730
3974
  * Every shape keys on **opaque, typed ids** (`rr_`, `turn_`, `cat_`, `rule_`,
3731
3975
  * `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
3976
+ * metadata; renaming never breaks a reference. $0-LLM on our side - the contract
3733
3977
  * is pure deterministic JSON; all judgment lives in the agent skills.
3734
3978
  *
3735
3979
  * The canonical example payloads for the §11 core shapes (Intent, ReviewFeedback,
3736
- * DiffJson, Rule, Nudge) are the conformance golden fixtures see
3980
+ * DiffJson, Rule, Nudge) are the conformance golden fixtures - see
3737
3981
  * `golang/internal/extrovertapi/testdata/contract/` and the SDK
3738
3982
  * `contract.test.ts` (both assert these examples parse/validate without loss).
3739
3983
  *
@@ -3776,24 +4020,24 @@ interface DiffJson {
3776
4020
  /**
3777
4021
  * The published version of the Extrovert Review-Loop open contract (D14).
3778
4022
  *
3779
- * **`0.1.0-pre.6` PROVISIONAL, pre-1.0.** Versioned *with the SDK* (this package's
4023
+ * **`0.1.0-pre.7` - PROVISIONAL, pre-1.0.** Versioned *with the SDK* (this package's
3780
4024
  * `package.json` version) and aligned to the openapi `info.version`. Open and
3781
4025
  * documented, but MAY still evolve before 1.0 (no external users yet; the D20
3782
4026
  * shared-pool governor is required before external users). Pin it.
3783
4027
  */
3784
- declare const CONTRACT_VERSION: "0.1.0-pre.6";
4028
+ declare const CONTRACT_VERSION: "0.1.0-pre.7";
3785
4029
  /** The stability posture of a published contract version. */
3786
4030
  type ContractStability = "provisional" | "stable";
3787
4031
  /**
3788
- * The machine-readable manifest of the open contract (D14) what a harness pins.
4032
+ * The machine-readable manifest of the open contract (D14) - what a harness pins.
3789
4033
  *
3790
4034
  * It enumerates the canonical §11 **core** shapes and the **full** M1–M8 surface
3791
4035
  * by name, stamps {@link CONTRACT_VERSION}, and marks the {@link ContractStability}
3792
4036
  * 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.
4037
+ * behavior (M9 adds none - types + a version + a test + docs) and no LLM.
3794
4038
  */
3795
4039
  interface ContractManifest {
3796
- /** Stable contract name (NOT a protocol name D14). */
4040
+ /** Stable contract name (NOT a protocol name - D14). */
3797
4041
  readonly name: "extrovert.review-loop";
3798
4042
  /** The published contract version (== {@link CONTRACT_VERSION}). */
3799
4043
  readonly version: string;
@@ -3803,7 +4047,7 @@ interface ContractManifest {
3803
4047
  */
3804
4048
  readonly stability: ContractStability;
3805
4049
  /**
3806
- * D14: this is an SDK + skill contract, versioned WITH the SDK never a wire
4050
+ * D14: this is an SDK + skill contract, versioned WITH the SDK - never a wire
3807
4051
  * protocol or a standalone protocol endpoint.
3808
4052
  */
3809
4053
  readonly kind: "sdk+skill-contract";
@@ -3813,15 +4057,15 @@ interface ContractManifest {
3813
4057
  readonly core_shapes: readonly string[];
3814
4058
  /** The full published M1–M8 agent-facing contract surface (one 0.x contract; no tiering). */
3815
4059
  readonly shapes: readonly string[];
3816
- /** The agent skills that are part of the contract (D14 "skill + SDK"). */
4060
+ /** The agent skills that are part of the contract (D14 - "skill + SDK"). */
3817
4061
  readonly skills: readonly string[];
3818
4062
  }
3819
4063
  /**
3820
4064
  * The published manifest instance. Frozen so a harness can compare it
3821
4065
  * structurally. The `core_shapes` are the five §11 canonical shapes; `shapes` is
3822
4066
  * 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.
4067
+ * above - the `contract.test.ts` drift test asserts every named shape resolves.
3824
4068
  */
3825
4069
  declare const CONTRACT_MANIFEST: ContractManifest;
3826
4070
 
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 };
4071
+ export { API_VERSION_HEADER, type AccountRiskDial, type AckReviewEventEntry, type AckReviewEventRequest, type AckReviewEventResult, type AddContactListRequest, type Agent, type AgentStatus, ApiError, type ApiErrorBody, type Attachment, type AttachmentDownload, type AttachmentInput, AuthenticationError, type BatchUpdateMessagesRequest, type BatchUpdateResult, BornStaleError, BreadthRequiredError, CONTRACT_MANIFEST, CONTRACT_VERSION, CURRENT_API_VERSION, Categories, type Category, type CategoryPacingState, type CategoryRiskDial, Commerce, type CommerceBlocker, type CommerceRequest, type CommerceRequestKind, ConflictError, ConnectionError, type ContactListDirection, type ContactListEntry, type ContactListKind, ContactLists, type ContractManifest, type ContractStability, type CreateInboxRequest, type Cursor, DEFAULT_BASE_URL, type DeleteResult, type DiffHunk, type DiffJson, type Domain, type DomainOffboard, type DomainQuote, type DomainReadiness, type DomainRecord, type DomainScope, type DomainStatusEvent, type DomainStatusEventPage, type DomainWaitResult, Domains, type EffectiveRiskDial, type EmailAddress, type EnrollRequest, type EnrollResponse, type ExtractedCredentials, ExtrovertClient as Extrovert, ExtrovertClient, type ExtrovertClientOptions, ForbiddenScopeError, type ForwardRequest, type GetInboxParams, type GetRuleAuditParams, type GetRulesParams, type GraduationStatus, IdempotencyConflictError, type Inbox, type InboxCredentials, InboxHandle, type InboxInclude, type InboxMetadata, type InboxMetadataPatch, type InboxMetadataValue, type InboxStatus, Inboxes, IntentRequiredError, type IsoTimestamp, type Job, type KeyTier, type List, type ListCategoriesParams, type ListCommerceRequestsParams, type ListInboxesParams, type ListMessagesParams, ListPage, type ListParams, type ListReviewEventsParams, type ListReviewsParams, type ListSuppressionsParams, type ListThreadsParams, MOCK_BASE_URL, type MailFolder, type MailboxQuickstart, type MailboxQuickstartCall, type MarkReadRequest, type Message, type MessageDirection, Messages, MockBackend, NotFoundError, type OnboardDomainRequest, type OnboardingMode, PROBLEM_CODES, type PacingItem, type Page, type PageFetcher, PaymentRequiredError, PermissionError, type PostReviewChatRequest, type Problem, type ProblemCode, type ProblemField, type ProjectInboxListParams, ProjectInboxes, Projects, type ProposeCategoryRequest, type ProposeGraduationRequest, type QueuedForReviewResult, type QuoteDomainRequest, REVIEW_PROBLEM_RETRYABLE, RateLimitError, RecipientSuppressedError, type RegisterWebhookRequest, type ReplyRequest, type RequestDomainPurchaseRequest, type RequestPlanChangeRequest, type RestampReviewRequest, type Review, ReviewConflictError, type ReviewDecisionContext, type ReviewEvent, type ReviewEventCursor, type ReviewEventReason, ReviewEvents, type ReviewEventsResult, type ReviewFeedback, type ReviewFeedbackComment, type ReviewInclude, type ReviewIntent, type ReviewMode, type ReviewPolicy, type ReviewState, type ReviewTurn, type ReviewerAction, type ReviewerDecisionRequest, type ReviewerDecisionResult, Reviews, type RiskDial, type Rule, type RuleAuditEntry, type RuleLayer, type RuleSnapshot, Rules, SDK_VERSION, type SaveRuleRequest, type ScanBacklogStatus, type Scope, type SearchMessagesParams, SendNeedsReconciliationError, type SendOutcome, type SendRequest, type SendResult, type SentResult, type SignUpRequest, type SignUpResponse, StaleError, type StreamEvent, type StreamOptions, type SubmitForReviewResult, type SubmitRevisionRequest, type SuppressionEntry, type SuppressionPrecheck, type SuppressionScope, type SuppressionSource, Suppressions, TerminalError, type Thread, type ThreadDetail, Threads, TimeoutError, UnavailableError, type UpdateCategoryRequest, type UpdateInboxRequest, type UpdateWebhookRequest, ValidationError, type VerifyRequest, type VerifyResponse, type VerifyWebhookOptions, type WaitForEmailRequest, type WaitForEmailResult, type WaitForReviewEventParams, type Webhook, type WebhookEvent, type WebhookPayload, Webhooks, type WhoAmI, WrongStateError, extractCredentials, extractLink, extractOtp, isProblemCode, isQueuedForReview, isSentImmediately, listPage, parseKeyTier, parseProblem, parseWebhook, reviewIdOf, sentMessageIdOf, serializeInclude, signWebhook, threadIdOf, tierAllowsOrgWildcard, tierNeedsExplicitBreadth, verifyWebhookSignature };