primcli 3.0.0-preview.12 → 3.0.0-preview.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import { B as ensureSearchReportsReplyState, Gn as sdk_gen_exports, J as EMAIL_RULE_REQUEST_EVENT_TYPES, K as replyStateSurfaceForOperation, L as ReplyStateUnsupportedError, Qt as getOwnGrant, R as assertAwaitingFilterRows, Ut as getEmail, W as isAwaitingRejectedError, X as WEBHOOK_EVENT_TYPES, Y as SENT_EMAIL_EVENT_TYPES, _n as listEndpoints, at as assertAutomatedVerdict, ct as ensureSearchReportsAutomated, dt as isAutomatedRejectedError, it as AutomatedFilterUnsupportedError, lt as expectedAutomatedVerdicts, nn as getThread, ot as automatedRejectedError, q as EMAIL_RULE_OBJECTION_EVENT_TYPES, st as automatedSurfaceForOperation, v as parseRetryAfter, z as awaitingRejectedError } from "./repeats-Dj_o6c-X-wjmw2Jbx.js";
1
+ import { B as ensureSearchReportsReplyState, Gn as sdk_gen_exports, J as EMAIL_RULE_REQUEST_EVENT_TYPES, K as replyStateSurfaceForOperation, L as ReplyStateUnsupportedError, Qt as getOwnGrant, R as assertAwaitingFilterRows, Ut as getEmail, W as isAwaitingRejectedError, X as WEBHOOK_EVENT_TYPES, Y as SENT_EMAIL_EVENT_TYPES, _n as listEndpoints, at as assertAutomatedVerdict, ct as ensureSearchReportsAutomated, dt as isAutomatedRejectedError, it as AutomatedFilterUnsupportedError, lt as expectedAutomatedVerdicts, nn as getThread, ot as automatedRejectedError, q as EMAIL_RULE_OBJECTION_EVENT_TYPES, st as automatedSurfaceForOperation, v as parseRetryAfter, z as awaitingRejectedError } from "./repeats-Dj_o6c-X-ykfsraq6.js";
2
2
  import { C as saveCliCredentials, F as agentProfilesDirectory, H as requireDefaultLoginProfile, N as agentProfileDirectory, R as loadConnectedAgentProfile, S as resolveCliAuth, W as PrimitiveApiClient, _ as deleteCliCredentials, b as loadCliCredentials, c as resolveConfigEnvironment, d as validateCliHeaderName, f as validateCliHeaderValue, i as loadCliConfig, j as AGENT_PROFILE_ENV, m as cliAccessTokenExpiresAt, p as acquireCliCredentialsLock, w as saveSignupCredentials, x as normalizeApiBaseUrl, y as detectPrimitiveKeyEnvMisname } from "./cli-config-Ms_0vNjq.js";
3
3
  import "./oclif/global-org-flag.js";
4
4
  import { a as thrownErrorBody } from "./json-output-ch756TXV.js";
@@ -863,7 +863,7 @@ const operationManifest = [
863
863
  },
864
864
  "state": {
865
865
  "type": "string",
866
- "description": "Where it stands now: enabled, disabled, deleted or replaced (endpoints and routes), enabled or disabled (filters, wake schedules), live, suspended or deleted (Functions), active, paused or ended (repeating sends), scheduled (scheduled sends), active, suspended, expired or revoked (API keys), pending, claimed, connected or revoked (agents), draft, observe or active (email rules), pending, accepted, declined or withdrawn (rule requests and objections), and for a coverage notice what it told: started (a rule began covering your mailbox), new_version, or baseline (it already covered you when notices began). pending: a rule started covering your mailbox and the notices have not recorded that start yet (a restart within an hour of the last start notice is recorded without a new one); its id is then the rule's, and created_at when the rule last changed."
866
+ "description": "Where it stands now: enabled, disabled, deleted or replaced (endpoints and routes), enabled or disabled (filters, wake schedules), live, suspended or deleted (Functions), active, paused or ended (repeating sends), scheduled (scheduled sends), active, suspended, expired or revoked (API keys), pending, claimed, connected or revoked (agents), draft, observe or active (email rules), pending, accepted, declined or withdrawn (rule requests and objections), and for a coverage notice what it told: started (a rule was made or turned active over your mailboxes, or an active rule came to reach you; once per rule, not per mailbox), new_version, or baseline (it already covered you when notices began). pending: a rule started covering your mailbox and the notices have not recorded that start yet (a restart within an hour of the last start notice is recorded without a new one); its id is then the rule's, and created_at when the rule last changed."
867
867
  },
868
868
  "created_at": {
869
869
  "type": "string",
@@ -872,7 +872,7 @@ const operationManifest = [
872
872
  "ended_at": {
873
873
  "type": ["string", "null"],
874
874
  "format": "date-time",
875
- "description": "When it was deleted, replaced or revoked, when an API key expired, when a repeating send stopped, or when a rule request or objection was decided (accepted, declined or withdrawn); null otherwise."
875
+ "description": "When it was deleted, replaced or revoked, when an API key expired, when a repeating send stopped, or when a rule request or objection was decided (accepted, declined or withdrawn); null otherwise, as on every coverage notice."
876
876
  },
877
877
  "owned_now": {
878
878
  "type": "string",
@@ -900,6 +900,11 @@ const operationManifest = [
900
900
  "id",
901
901
  "name"
902
902
  ]
903
+ },
904
+ "rule_id": {
905
+ "description": "For email_rule_coverage, always: the rule it is about, since names need not be unique (for pending, the same as id). GET /v1/email-rules/covering-me/{rule_id} shows the rule while it covers you, or as it last decided on your mail; otherwise it answers not_found.",
906
+ "type": "string",
907
+ "format": "uuid"
903
908
  }
904
909
  },
905
910
  "required": [
@@ -11227,6 +11232,27 @@ const operationManifest = [
11227
11232
  "additionalProperties": {}
11228
11233
  }
11229
11234
  },
11235
+ "rules_added": {
11236
+ "description": "Each rule (or share) the edit put on a key that reads mail, with granted_emails, how many emails it has already shared, which the key can now read while it is active: counted up to 10,000, with more: true past that; null when not counted.",
11237
+ "type": "array",
11238
+ "items": {
11239
+ "type": "object",
11240
+ "properties": {
11241
+ "id": { "type": "string" },
11242
+ "granted_emails": {
11243
+ "type": ["integer", "null"],
11244
+ "minimum": 0,
11245
+ "maximum": 9007199254740991
11246
+ },
11247
+ "more": {
11248
+ "type": "boolean",
11249
+ "const": true
11250
+ }
11251
+ },
11252
+ "required": ["id", "granted_emails"],
11253
+ "additionalProperties": {}
11254
+ }
11255
+ },
11230
11256
  "grant_unguarded": {
11231
11257
  "description": "Present, as true, when the grant was changed without expected_grant_ref, so the change was not checked against changes made since the key was read. Send grant.ref from GET /v1/keys/{id} as expected_grant_ref to have such a change refused instead (409 conflict, details.reason grant_changed).",
11232
11258
  "type": "boolean",
@@ -12344,11 +12370,17 @@ const operationManifest = [
12344
12370
  "type": "string"
12345
12371
  }],
12346
12372
  "queryParams": [{
12347
- "description": "When true, include only outbound DNS records. Verified domains default to outbound-only; pending claims default to all required records.",
12373
+ "description": "When true, include only outbound DNS records. Cannot be combined with inbound_only=true. By default, include all records.",
12348
12374
  "enum": null,
12349
12375
  "name": "outbound_only",
12350
12376
  "required": false,
12351
12377
  "type": "boolean"
12378
+ }, {
12379
+ "description": "When true, include only inbound MX and ownership TXT records. Cannot be combined with outbound_only=true.",
12380
+ "enum": null,
12381
+ "name": "inbound_only",
12382
+ "required": false,
12383
+ "type": "boolean"
12352
12384
  }],
12353
12385
  "headerParams": [],
12354
12386
  "permissions": ["domains:read"],
@@ -13141,8 +13173,14 @@ const operationManifest = [
13141
13173
  "email"
13142
13174
  ]
13143
13175
  },
13144
- "is_objector": { "type": "boolean" },
13145
- "is_author": { "type": "boolean" },
13176
+ "is_objector": {
13177
+ "type": "boolean",
13178
+ "description": "Whether you made it, in your current membership."
13179
+ },
13180
+ "is_author": {
13181
+ "type": "boolean",
13182
+ "description": "Whether it is to a rule you wrote, in your current membership."
13183
+ },
13146
13184
  "message": {
13147
13185
  "description": "Why the objector objects; null when none was given, or once withdrawn.",
13148
13186
  "type": ["string", "null"]
@@ -13289,8 +13327,14 @@ const operationManifest = [
13289
13327
  "email"
13290
13328
  ]
13291
13329
  },
13292
- "is_objector": { "type": "boolean" },
13293
- "is_author": { "type": "boolean" },
13330
+ "is_objector": {
13331
+ "type": "boolean",
13332
+ "description": "Whether you made it, in your current membership."
13333
+ },
13334
+ "is_author": {
13335
+ "type": "boolean",
13336
+ "description": "Whether it is to a rule you wrote, in your current membership."
13337
+ },
13294
13338
  "message": {
13295
13339
  "description": "Why the objector objects; null when none was given, or once withdrawn.",
13296
13340
  "type": ["string", "null"]
@@ -13435,8 +13479,14 @@ const operationManifest = [
13435
13479
  "email"
13436
13480
  ]
13437
13481
  },
13438
- "is_objector": { "type": "boolean" },
13439
- "is_author": { "type": "boolean" },
13482
+ "is_objector": {
13483
+ "type": "boolean",
13484
+ "description": "Whether you made it, in your current membership."
13485
+ },
13486
+ "is_author": {
13487
+ "type": "boolean",
13488
+ "description": "Whether it is to a rule you wrote, in your current membership."
13489
+ },
13440
13490
  "message": {
13441
13491
  "description": "Why the objector objects; null when none was given, or once withdrawn.",
13442
13492
  "type": ["string", "null"]
@@ -13576,7 +13626,163 @@ const operationManifest = [
13576
13626
  "description": "Null when covers_now is false."
13577
13627
  },
13578
13628
  "receivers": {
13579
- "description": "Null when covers_now is false (who receives it now is not about your mail), or when it could not be read in time.",
13629
+ "description": "Null when covers_now is false (who receives it now is not about your mail), when it could not be read in time, or for a rule shown in draft or observe that turned active or was deleted after it was read; try again.",
13630
+ "anyOf": [{
13631
+ "type": "object",
13632
+ "properties": {
13633
+ "keys": {
13634
+ "type": "array",
13635
+ "items": {
13636
+ "type": "object",
13637
+ "properties": {
13638
+ "owner": { "anyOf": [{
13639
+ "type": "object",
13640
+ "properties": {
13641
+ "kind": {
13642
+ "type": "string",
13643
+ "const": "member"
13644
+ },
13645
+ "user_id": {
13646
+ "type": "string",
13647
+ "description": "The member's user id.",
13648
+ "format": "uuid"
13649
+ },
13650
+ "name": {
13651
+ "description": "Their name; null when they have none set.",
13652
+ "type": ["string", "null"]
13653
+ }
13654
+ },
13655
+ "required": [
13656
+ "kind",
13657
+ "user_id",
13658
+ "name"
13659
+ ]
13660
+ }, {
13661
+ "type": "object",
13662
+ "properties": { "kind": {
13663
+ "type": "string",
13664
+ "const": "organization",
13665
+ "description": "Held by no member: an organization key, or one whose holder has left."
13666
+ } },
13667
+ "required": ["kind"]
13668
+ }] },
13669
+ "count": {
13670
+ "type": "integer",
13671
+ "exclusiveMinimum": 0
13672
+ },
13673
+ "reads_in_full": {
13674
+ "description": "On a rule over your mail: how many of these keys also list one of your own mailboxes, or its domain, so they read your mail there beyond what this rule matches.",
13675
+ "type": "integer",
13676
+ "minimum": 0
13677
+ }
13678
+ },
13679
+ "required": ["owner", "count"]
13680
+ },
13681
+ "description": "API keys that work now (not revoked, expired or suspended) and hold mail:read, whose access lists the rule or its live share. Owner: who holds each, or the organization."
13682
+ },
13683
+ "webhooks": {
13684
+ "type": "array",
13685
+ "items": {
13686
+ "type": "object",
13687
+ "properties": {
13688
+ "owner": { "anyOf": [{
13689
+ "type": "object",
13690
+ "properties": {
13691
+ "kind": {
13692
+ "type": "string",
13693
+ "const": "member"
13694
+ },
13695
+ "user_id": {
13696
+ "type": "string",
13697
+ "description": "The member's user id.",
13698
+ "format": "uuid"
13699
+ },
13700
+ "name": {
13701
+ "description": "Their name; null when they have none set.",
13702
+ "type": ["string", "null"]
13703
+ }
13704
+ },
13705
+ "required": [
13706
+ "kind",
13707
+ "user_id",
13708
+ "name"
13709
+ ]
13710
+ }, {
13711
+ "type": "object",
13712
+ "properties": { "kind": {
13713
+ "type": "string",
13714
+ "const": "organization",
13715
+ "description": "Held by no member: an organization key, or one whose holder has left."
13716
+ } },
13717
+ "required": ["kind"]
13718
+ }] },
13719
+ "count": {
13720
+ "type": "integer",
13721
+ "exclusiveMinimum": 0
13722
+ },
13723
+ "hosts": {
13724
+ "description": "Distinct sites they deliver to (the domain a host is registered under, an app's own name on a known app platform, or a function URL service in its region), sorted, at most 10; \"unknown host\" (last) for any that cannot be named.",
13725
+ "type": "array",
13726
+ "items": { "type": "string" }
13727
+ },
13728
+ "hosts_not_listed": {
13729
+ "description": "Hosts past those listed.",
13730
+ "type": "integer",
13731
+ "minimum": 0
13732
+ }
13733
+ },
13734
+ "required": ["owner", "count"]
13735
+ },
13736
+ "description": "Webhooks taking received mail, bounces or reports that are sent what it matches: those of the key delivery acts as, when it lists the rule or its live share (owner: its holder, or the organization), and those of the member it is shared with (owner: that member)."
13737
+ },
13738
+ "shares": {
13739
+ "type": "array",
13740
+ "items": {
13741
+ "type": "object",
13742
+ "properties": {
13743
+ "beneficiary": {
13744
+ "type": "object",
13745
+ "properties": {
13746
+ "kind": {
13747
+ "type": "string",
13748
+ "const": "member"
13749
+ },
13750
+ "user_id": {
13751
+ "type": "string",
13752
+ "description": "The member's user id.",
13753
+ "format": "uuid"
13754
+ },
13755
+ "name": {
13756
+ "description": "Their name; null when they have none set.",
13757
+ "type": ["string", "null"]
13758
+ }
13759
+ },
13760
+ "required": [
13761
+ "kind",
13762
+ "user_id",
13763
+ "name"
13764
+ ]
13765
+ },
13766
+ "count": {
13767
+ "type": "integer",
13768
+ "exclusiveMinimum": 0
13769
+ }
13770
+ },
13771
+ "required": ["beneficiary", "count"]
13772
+ },
13773
+ "description": "The rule's live share (at most one), by its member, if they can read it and it is among their newest 20 shares."
13774
+ }
13775
+ },
13776
+ "required": [
13777
+ "keys",
13778
+ "webhooks",
13779
+ "shares"
13780
+ ],
13781
+ "description": "Who receives what the rule shares, by person and count. As receivers, empty unless it is an active grant rule."
13782
+ }, { "type": "null" }]
13783
+ },
13784
+ "receivers_once_active": {
13785
+ "description": "As on the list; also null when covers_now is false.",
13580
13786
  "anyOf": [{
13581
13787
  "type": "object",
13582
13788
  "properties": {
@@ -13619,6 +13825,11 @@ const operationManifest = [
13619
13825
  "count": {
13620
13826
  "type": "integer",
13621
13827
  "exclusiveMinimum": 0
13828
+ },
13829
+ "reads_in_full": {
13830
+ "description": "On a rule over your mail: how many of these keys also list one of your own mailboxes, or its domain, so they read your mail there beyond what this rule matches.",
13831
+ "type": "integer",
13832
+ "minimum": 0
13622
13833
  }
13623
13834
  },
13624
13835
  "required": ["owner", "count"]
@@ -13666,7 +13877,7 @@ const operationManifest = [
13666
13877
  "exclusiveMinimum": 0
13667
13878
  },
13668
13879
  "hosts": {
13669
- "description": "Distinct sites they deliver to (a host's registrable domain, or a tunnel, preview or function service alone), sorted, at most 10; \"unknown host\" (last) for any that cannot be named.",
13880
+ "description": "Distinct sites they deliver to (the domain a host is registered under, an app's own name on a known app platform, or a function URL service in its region), sorted, at most 10; \"unknown host\" (last) for any that cannot be named.",
13670
13881
  "type": "array",
13671
13882
  "items": { "type": "string" }
13672
13883
  },
@@ -13723,7 +13934,7 @@ const operationManifest = [
13723
13934
  "webhooks",
13724
13935
  "shares"
13725
13936
  ],
13726
- "description": "Who receives what the rule shares now, by person and count; empty unless it is an active grant rule."
13937
+ "description": "Who receives what the rule shares, by person and count. As receivers, empty unless it is an active grant rule."
13727
13938
  }, { "type": "null" }]
13728
13939
  },
13729
13940
  "created_at": {
@@ -13819,6 +14030,7 @@ const operationManifest = [
13819
14030
  "covers",
13820
14031
  "current_version",
13821
14032
  "receivers",
14033
+ "receivers_once_active",
13822
14034
  "created_at",
13823
14035
  "covers_now",
13824
14036
  "current"
@@ -13920,8 +14132,14 @@ const operationManifest = [
13920
14132
  "email"
13921
14133
  ]
13922
14134
  },
13923
- "is_objector": { "type": "boolean" },
13924
- "is_author": { "type": "boolean" },
14135
+ "is_objector": {
14136
+ "type": "boolean",
14137
+ "description": "Whether you made it, in your current membership."
14138
+ },
14139
+ "is_author": {
14140
+ "type": "boolean",
14141
+ "description": "Whether it is to a rule you wrote, in your current membership."
14142
+ },
13925
14143
  "message": {
13926
14144
  "description": "Why the objector objects; null when none was given, or once withdrawn.",
13927
14145
  "type": ["string", "null"]
@@ -14087,7 +14305,7 @@ const operationManifest = [
14087
14305
  "binaryResponse": false,
14088
14306
  "bodyRequired": false,
14089
14307
  "command": "list-email-rule-objections",
14090
- "description": "Objections you made, objections to rules you wrote, or every objection you can see, newest first. An objection is seen by the member who made it, the rule's author and the organization's owners and admins. It stays pending until the rule's author accepts it, turning the rule off, or declines it, or the member who made it withdraws it, which clears its message. It never changes after that. Needs mail:read, the email rules feature, and a member's own full-access credential (no API key, agent key or narrowed token). Only on your own dashboard session or the Primitive CLI.",
14308
+ "description": "Objections you made and objections to rules you wrote (by default), only one of the two, or every objection you can see, newest first. An objection is seen by the member who made it, the rule's author and the organization's owners and admins. It stays pending until the rule's author accepts it, turning the rule off, or declines it, or the member who made it withdraws it, which clears its message. It never changes after that. Needs mail:read, the email rules feature, and a member's own full-access credential (no API key, agent key or narrowed token). Only on your own dashboard session or the Primitive CLI.",
14091
14309
  "hasJsonBody": false,
14092
14310
  "method": "GET",
14093
14311
  "operationId": "listEmailRuleObjections",
@@ -14095,9 +14313,10 @@ const operationManifest = [
14095
14313
  "pathParams": [],
14096
14314
  "queryParams": [
14097
14315
  {
14098
- "default": "outgoing",
14099
- "description": "outgoing (the default): objections you made. incoming: objections to rules you wrote. all: every objection you can see.",
14316
+ "default": "mine",
14317
+ "description": "mine (the default): objections you made and objections to rules you wrote, each saying which (is_objector, is_author). outgoing: only those you made. incoming: only those to rules you wrote. all: every objection you can see.",
14100
14318
  "enum": [
14319
+ "mine",
14101
14320
  "outgoing",
14102
14321
  "incoming",
14103
14322
  "all"
@@ -14212,8 +14431,14 @@ const operationManifest = [
14212
14431
  "email"
14213
14432
  ]
14214
14433
  },
14215
- "is_objector": { "type": "boolean" },
14216
- "is_author": { "type": "boolean" },
14434
+ "is_objector": {
14435
+ "type": "boolean",
14436
+ "description": "Whether you made it, in your current membership."
14437
+ },
14438
+ "is_author": {
14439
+ "type": "boolean",
14440
+ "description": "Whether it is to a rule you wrote, in your current membership."
14441
+ },
14217
14442
  "message": {
14218
14443
  "description": "Why the objector objects; null when none was given, or once withdrawn.",
14219
14444
  "type": ["string", "null"]
@@ -14253,6 +14478,126 @@ const operationManifest = [
14253
14478
  "tag": "Email Rule Oversight",
14254
14479
  "tagCommand": "email-rule-oversight"
14255
14480
  },
14481
+ {
14482
+ "binaryResponse": false,
14483
+ "bodyRequired": false,
14484
+ "command": "list-email-rule-versions-covering-me",
14485
+ "description": "The versions of a rule that covers one of your own mailboxes now that applied to your mail: its current version and each earlier one that decided on mail at your own mailboxes, so a decision can be read in the words of the version that made it. Each has what the covering view shows of a version: its wording, tree, explanation and assumptions. A version that did neither is not listed. Without versions, newest first, a page at a time (meta.cursor); with versions, only those named that are listed, oldest first. Needs mail:read, the email rules feature, and a member's own full-access credential (no API key, agent key or narrowed token). Only on your own dashboard session or the Primitive CLI.",
14486
+ "hasJsonBody": false,
14487
+ "method": "GET",
14488
+ "operationId": "listEmailRuleVersionsCoveringMe",
14489
+ "path": "/email-rules/covering-me/{id}/versions",
14490
+ "pathParams": [{
14491
+ "description": "The rule id.",
14492
+ "enum": null,
14493
+ "name": "id",
14494
+ "required": true,
14495
+ "type": "string"
14496
+ }],
14497
+ "queryParams": [
14498
+ {
14499
+ "description": "Versions per page when versions is not given: 1 to 100, default 50.",
14500
+ "enum": null,
14501
+ "maximum": 100,
14502
+ "minimum": 1,
14503
+ "name": "limit",
14504
+ "required": false,
14505
+ "type": "integer"
14506
+ },
14507
+ {
14508
+ "description": "meta.cursor from the preceding page. Omit for the first page. Not with versions.",
14509
+ "enum": null,
14510
+ "name": "cursor",
14511
+ "required": false,
14512
+ "type": "string"
14513
+ },
14514
+ {
14515
+ "description": "Read only these version numbers, comma-separated, at most 100. Not with limit or cursor.",
14516
+ "enum": null,
14517
+ "name": "versions",
14518
+ "required": false,
14519
+ "type": "string"
14520
+ }
14521
+ ],
14522
+ "headerParams": [],
14523
+ "permissions": ["mail:read"],
14524
+ "access": null,
14525
+ "requestSchema": null,
14526
+ "responseSchema": {
14527
+ "type": "array",
14528
+ "items": {
14529
+ "type": "object",
14530
+ "properties": {
14531
+ "version": {
14532
+ "type": "integer",
14533
+ "exclusiveMinimum": 0
14534
+ },
14535
+ "english": {
14536
+ "type": "string",
14537
+ "description": "What its author asked for, in their words."
14538
+ },
14539
+ "tree": {
14540
+ "type": "object",
14541
+ "properties": {
14542
+ "version": {
14543
+ "type": "number",
14544
+ "const": 1
14545
+ },
14546
+ "vocabulary": {
14547
+ "type": "string",
14548
+ "description": "Vocabulary version, such as v1."
14549
+ },
14550
+ "when": {
14551
+ "type": "object",
14552
+ "propertyNames": { "type": "string" },
14553
+ "additionalProperties": {},
14554
+ "description": "A condition {column, op, value?, min_confidence?} (see GET /email-rules/vocabulary) or {all: [...]}, {any: [...]}, {not: ...}."
14555
+ },
14556
+ "questions": {
14557
+ "type": "array",
14558
+ "items": { "type": "string" },
14559
+ "description": "Yes/no questions asked once the conditions match, over the email's text and attachment names, never attachment contents. A grant rule needs every one yes; a do_not_share rule matches on any yes."
14560
+ }
14561
+ },
14562
+ "required": [
14563
+ "version",
14564
+ "vocabulary",
14565
+ "when",
14566
+ "questions"
14567
+ ]
14568
+ },
14569
+ "explanation": {
14570
+ "type": "string",
14571
+ "description": "What the rule matches, as compiled."
14572
+ },
14573
+ "assumptions": {
14574
+ "type": "array",
14575
+ "items": { "type": "string" }
14576
+ },
14577
+ "compiled_by": { "type": "string" },
14578
+ "vocabulary": { "type": "string" },
14579
+ "created_at": {
14580
+ "type": "string",
14581
+ "format": "date-time"
14582
+ }
14583
+ },
14584
+ "required": [
14585
+ "version",
14586
+ "english",
14587
+ "tree",
14588
+ "explanation",
14589
+ "assumptions",
14590
+ "compiled_by",
14591
+ "vocabulary",
14592
+ "created_at"
14593
+ ]
14594
+ }
14595
+ },
14596
+ "sdkName": "listEmailRuleVersionsCoveringMe",
14597
+ "summary": "Read versions of a rule over your mail",
14598
+ "tag": "Email Rule Oversight",
14599
+ "tagCommand": "email-rule-oversight"
14600
+ },
14256
14601
  {
14257
14602
  "binaryResponse": false,
14258
14603
  "bodyRequired": false,
@@ -14358,7 +14703,7 @@ const operationManifest = [
14358
14703
  "exclusiveMinimum": 0
14359
14704
  },
14360
14705
  "receivers": {
14361
- "description": "Null when it could not be read in time; try again.",
14706
+ "description": "Null when it could not be read in time, or for a rule shown in draft or observe that turned active or was deleted after the page was read; try again.",
14362
14707
  "anyOf": [{
14363
14708
  "type": "object",
14364
14709
  "properties": {
@@ -14401,6 +14746,167 @@ const operationManifest = [
14401
14746
  "count": {
14402
14747
  "type": "integer",
14403
14748
  "exclusiveMinimum": 0
14749
+ },
14750
+ "reads_in_full": {
14751
+ "description": "On a rule over your mail: how many of these keys also list one of your own mailboxes, or its domain, so they read your mail there beyond what this rule matches.",
14752
+ "type": "integer",
14753
+ "minimum": 0
14754
+ }
14755
+ },
14756
+ "required": ["owner", "count"]
14757
+ },
14758
+ "description": "API keys that work now (not revoked, expired or suspended) and hold mail:read, whose access lists the rule or its live share. Owner: who holds each, or the organization."
14759
+ },
14760
+ "webhooks": {
14761
+ "type": "array",
14762
+ "items": {
14763
+ "type": "object",
14764
+ "properties": {
14765
+ "owner": { "anyOf": [{
14766
+ "type": "object",
14767
+ "properties": {
14768
+ "kind": {
14769
+ "type": "string",
14770
+ "const": "member"
14771
+ },
14772
+ "user_id": {
14773
+ "type": "string",
14774
+ "description": "The member's user id.",
14775
+ "format": "uuid"
14776
+ },
14777
+ "name": {
14778
+ "description": "Their name; null when they have none set.",
14779
+ "type": ["string", "null"]
14780
+ }
14781
+ },
14782
+ "required": [
14783
+ "kind",
14784
+ "user_id",
14785
+ "name"
14786
+ ]
14787
+ }, {
14788
+ "type": "object",
14789
+ "properties": { "kind": {
14790
+ "type": "string",
14791
+ "const": "organization",
14792
+ "description": "Held by no member: an organization key, or one whose holder has left."
14793
+ } },
14794
+ "required": ["kind"]
14795
+ }] },
14796
+ "count": {
14797
+ "type": "integer",
14798
+ "exclusiveMinimum": 0
14799
+ },
14800
+ "hosts": {
14801
+ "description": "Distinct sites they deliver to (the domain a host is registered under, an app's own name on a known app platform, or a function URL service in its region), sorted, at most 10; \"unknown host\" (last) for any that cannot be named.",
14802
+ "type": "array",
14803
+ "items": { "type": "string" }
14804
+ },
14805
+ "hosts_not_listed": {
14806
+ "description": "Hosts past those listed.",
14807
+ "type": "integer",
14808
+ "minimum": 0
14809
+ }
14810
+ },
14811
+ "required": ["owner", "count"]
14812
+ },
14813
+ "description": "Webhooks taking received mail, bounces or reports that are sent what it matches: those of the key delivery acts as, when it lists the rule or its live share (owner: its holder, or the organization), and those of the member it is shared with (owner: that member)."
14814
+ },
14815
+ "shares": {
14816
+ "type": "array",
14817
+ "items": {
14818
+ "type": "object",
14819
+ "properties": {
14820
+ "beneficiary": {
14821
+ "type": "object",
14822
+ "properties": {
14823
+ "kind": {
14824
+ "type": "string",
14825
+ "const": "member"
14826
+ },
14827
+ "user_id": {
14828
+ "type": "string",
14829
+ "description": "The member's user id.",
14830
+ "format": "uuid"
14831
+ },
14832
+ "name": {
14833
+ "description": "Their name; null when they have none set.",
14834
+ "type": ["string", "null"]
14835
+ }
14836
+ },
14837
+ "required": [
14838
+ "kind",
14839
+ "user_id",
14840
+ "name"
14841
+ ]
14842
+ },
14843
+ "count": {
14844
+ "type": "integer",
14845
+ "exclusiveMinimum": 0
14846
+ }
14847
+ },
14848
+ "required": ["beneficiary", "count"]
14849
+ },
14850
+ "description": "The rule's live share (at most one), by its member, if they can read it and it is among their newest 20 shares."
14851
+ }
14852
+ },
14853
+ "required": [
14854
+ "keys",
14855
+ "webhooks",
14856
+ "shares"
14857
+ ],
14858
+ "description": "Who receives what the rule shares, by person and count. As receivers, empty unless it is an active grant rule."
14859
+ }, { "type": "null" }]
14860
+ },
14861
+ "receivers_once_active": {
14862
+ "description": "For a grant rule in draft or observe: who would receive what it matches once it is turned active. None of them receives anything yet. Null for any other rule, and as receivers is null.",
14863
+ "anyOf": [{
14864
+ "type": "object",
14865
+ "properties": {
14866
+ "keys": {
14867
+ "type": "array",
14868
+ "items": {
14869
+ "type": "object",
14870
+ "properties": {
14871
+ "owner": { "anyOf": [{
14872
+ "type": "object",
14873
+ "properties": {
14874
+ "kind": {
14875
+ "type": "string",
14876
+ "const": "member"
14877
+ },
14878
+ "user_id": {
14879
+ "type": "string",
14880
+ "description": "The member's user id.",
14881
+ "format": "uuid"
14882
+ },
14883
+ "name": {
14884
+ "description": "Their name; null when they have none set.",
14885
+ "type": ["string", "null"]
14886
+ }
14887
+ },
14888
+ "required": [
14889
+ "kind",
14890
+ "user_id",
14891
+ "name"
14892
+ ]
14893
+ }, {
14894
+ "type": "object",
14895
+ "properties": { "kind": {
14896
+ "type": "string",
14897
+ "const": "organization",
14898
+ "description": "Held by no member: an organization key, or one whose holder has left."
14899
+ } },
14900
+ "required": ["kind"]
14901
+ }] },
14902
+ "count": {
14903
+ "type": "integer",
14904
+ "exclusiveMinimum": 0
14905
+ },
14906
+ "reads_in_full": {
14907
+ "description": "On a rule over your mail: how many of these keys also list one of your own mailboxes, or its domain, so they read your mail there beyond what this rule matches.",
14908
+ "type": "integer",
14909
+ "minimum": 0
14404
14910
  }
14405
14911
  },
14406
14912
  "required": ["owner", "count"]
@@ -14448,7 +14954,7 @@ const operationManifest = [
14448
14954
  "exclusiveMinimum": 0
14449
14955
  },
14450
14956
  "hosts": {
14451
- "description": "Distinct sites they deliver to (a host's registrable domain, or a tunnel, preview or function service alone), sorted, at most 10; \"unknown host\" (last) for any that cannot be named.",
14957
+ "description": "Distinct sites they deliver to (the domain a host is registered under, an app's own name on a known app platform, or a function URL service in its region), sorted, at most 10; \"unknown host\" (last) for any that cannot be named.",
14452
14958
  "type": "array",
14453
14959
  "items": { "type": "string" }
14454
14960
  },
@@ -14505,7 +15011,7 @@ const operationManifest = [
14505
15011
  "webhooks",
14506
15012
  "shares"
14507
15013
  ],
14508
- "description": "Who receives what the rule shares now, by person and count; empty unless it is an active grant rule."
15014
+ "description": "Who receives what the rule shares, by person and count. As receivers, empty unless it is an active grant rule."
14509
15015
  }, { "type": "null" }]
14510
15016
  },
14511
15017
  "created_at": {
@@ -14523,6 +15029,7 @@ const operationManifest = [
14523
15029
  "covers",
14524
15030
  "current_version",
14525
15031
  "receivers",
15032
+ "receivers_once_active",
14526
15033
  "created_at"
14527
15034
  ]
14528
15035
  }
@@ -14629,8 +15136,14 @@ const operationManifest = [
14629
15136
  "email"
14630
15137
  ]
14631
15138
  },
14632
- "is_objector": { "type": "boolean" },
14633
- "is_author": { "type": "boolean" },
15139
+ "is_objector": {
15140
+ "type": "boolean",
15141
+ "description": "Whether you made it, in your current membership."
15142
+ },
15143
+ "is_author": {
15144
+ "type": "boolean",
15145
+ "description": "Whether it is to a rule you wrote, in your current membership."
15146
+ },
14634
15147
  "message": {
14635
15148
  "description": "Why the objector objects; null when none was given, or once withdrawn.",
14636
15149
  "type": ["string", "null"]
@@ -14757,7 +15270,7 @@ const operationManifest = [
14757
15270
  }
14758
15271
  },
14759
15272
  "warnings": {
14760
- "description": "The compile response's warnings. Stored as sent, then any server note they lack on an address or domain the description names that the rule does not test (on a rule request, every compiler note on the rule).",
15273
+ "description": "The compile response's warnings. Stored as sent, then any server note they lack on an address or domain the description names that the rule does not test, or on a grant rule that tests only who an email was sent to (on a rule request, every compiler note on the rule).",
14761
15274
  "maxItems": 10,
14762
15275
  "type": "array",
14763
15276
  "items": {
@@ -14780,7 +15293,7 @@ const operationManifest = [
14780
15293
  "checked": {
14781
15294
  "type": "integer",
14782
15295
  "minimum": 0,
14783
- "description": "Classified emails the conditions were decided for: of the newest 200 from the last 30 days in your own mailboxes (for a grant rule, those you may share), the ones you can still read."
15296
+ "description": "Classified emails the conditions were decided for: of the newest 200 from the last 30 days in the scope counted (evaluation_scope as sent; by default your own mailboxes, for a grant rule those you may share), the ones you can still read."
14784
15297
  },
14785
15298
  "matched": {
14786
15299
  "type": "integer",
@@ -14799,7 +15312,7 @@ const operationManifest = [
14799
15312
  "checked": {
14800
15313
  "type": "integer",
14801
15314
  "minimum": 0,
14802
- "description": "Classified emails the conditions were decided for: of the newest 200 from the last 30 days in your own mailboxes (for a grant rule, those you may share), the ones you can still read."
15315
+ "description": "Classified emails the conditions were decided for: of the newest 200 from the last 30 days in the scope counted (evaluation_scope as sent; by default your own mailboxes, for a grant rule those you may share), the ones you can still read."
14803
15316
  },
14804
15317
  "matched": {
14805
15318
  "type": "integer",
@@ -14896,6 +15409,16 @@ const operationManifest = [
14896
15409
  "pattern": "^[^\\u0000]*$"
14897
15410
  }
14898
15411
  },
15412
+ "attachment_names": {
15413
+ "maxItems": 10,
15414
+ "type": "array",
15415
+ "items": {
15416
+ "type": "string",
15417
+ "minLength": 1,
15418
+ "maxLength": 255,
15419
+ "pattern": "^[^\\u0000-\\u001f\\u007f]*$"
15420
+ }
15421
+ },
14899
15422
  "automated": { "type": "boolean" },
14900
15423
  "from_mailing_list": { "type": "boolean" },
14901
15424
  "spam_score": {
@@ -15206,6 +15729,15 @@ const operationManifest = [
15206
15729
  "type": "boolean",
15207
15730
  "description": "Whether you are its author, in your current membership. Only its author edits it."
15208
15731
  },
15732
+ "pending_objections": {
15733
+ "description": "To its author, on the dashboard or the Primitive CLI: objections to it waiting for their answer (GET /email-rule-objections). A write's answer leaves it out when it could not be read in time: absent is not 0.",
15734
+ "type": "integer",
15735
+ "minimum": 0
15736
+ },
15737
+ "objection_notice": {
15738
+ "description": "With pending_objections above 0: that members asked you to turn it off, and how to answer.",
15739
+ "type": "string"
15740
+ },
15209
15741
  "created_at": {
15210
15742
  "type": "string",
15211
15743
  "format": "date-time"
@@ -15473,7 +16005,7 @@ const operationManifest = [
15473
16005
  ]
15474
16006
  },
15475
16007
  "notice": {
15476
- "description": "What is now shared, in words.",
16008
+ "description": "What is now shared, in words. When you changed the rule and it can now match mail the request left out by who it was sent to (such as mail where an address is only copied), that comes first.",
15477
16009
  "type": "string"
15478
16010
  }
15479
16011
  },
@@ -15574,7 +16106,7 @@ const operationManifest = [
15574
16106
  "binaryResponse": false,
15575
16107
  "bodyRequired": true,
15576
16108
  "command": "compile-email-rule",
15577
- "description": "Turns a plain-English description of which received emails to match into a rule tree over the column contract, with an explanation of what it matches, the assumptions made, and warnings for what the columns cannot express. Where the columns fall short it adds up to five yes/no questions, asked only after the conditions match; they read the subject, the new text and attachment file names, never attachment contents. Nothing is saved. For a rule with no questions, breadth counts, read only, how much of your recent classified mail its conditions match; for a grant rule with questions, conditions_breadth counts its conditions alone. include_sql returns the SQL it renders to. kind do_not_share compiles for recall. Needs mail:read, the email rules feature, and a member's own full-access credential (no API key, agent key or narrowed token).",
16109
+ "description": "Turns a plain-English description of which received emails to match into a rule tree over the column contract, with an explanation of what it matches, the assumptions made, and warnings for what the columns cannot express. Where the columns fall short it adds up to five yes/no questions, asked only after the conditions match; they read the subject, the new text and attachment file names, never attachment contents. Nothing is saved. For a rule with no questions, breadth counts, read only, how much of the recent classified mail in evaluation_scope (by default your own mailboxes) its conditions match; for a grant rule with questions, conditions_breadth counts its conditions alone. include_sql returns the SQL it renders to. kind do_not_share compiles for recall. Needs mail:read, the email rules feature, and a member's own full-access credential (no API key, agent key or narrowed token).",
15578
16110
  "hasJsonBody": true,
15579
16111
  "method": "POST",
15580
16112
  "operationId": "compileEmailRule",
@@ -15607,6 +16139,42 @@ const operationManifest = [
15607
16139
  "include_sql": {
15608
16140
  "description": "Also return the SQL the rule renders to. Off by default.",
15609
16141
  "type": "boolean"
16142
+ },
16143
+ "evaluation_scope": {
16144
+ "description": "The scope breadth is counted over, as a test of the tree runs it: send the one you will save the rule with. Nothing is saved. own_mailboxes (the default): mail to your own addresses and agents (for a rule that shares, those mail:share_own lets you share). author: all you can read, inboxes added later included. selected: what scope_selection names.",
16145
+ "type": "string",
16146
+ "enum": [
16147
+ "author",
16148
+ "own_mailboxes",
16149
+ "selected"
16150
+ ]
16151
+ },
16152
+ "scope_selection": {
16153
+ "type": "object",
16154
+ "properties": {
16155
+ "addresses": {
16156
+ "maxItems": 100,
16157
+ "type": "array",
16158
+ "items": {
16159
+ "type": "string",
16160
+ "minLength": 3,
16161
+ "maxLength": 320,
16162
+ "pattern": "^[^\\s@]+@[^\\s@]+$"
16163
+ }
16164
+ },
16165
+ "domains": {
16166
+ "maxItems": 50,
16167
+ "type": "array",
16168
+ "items": {
16169
+ "type": "string",
16170
+ "minLength": 1,
16171
+ "maxLength": 253,
16172
+ "pattern": "^[^\\s@]+\\.[^\\s@]+$"
16173
+ }
16174
+ }
16175
+ },
16176
+ "additionalProperties": false,
16177
+ "description": "For a selected rule: inboxes, and domains (each address at them the author reads); each one you can read."
15610
16178
  }
15611
16179
  },
15612
16180
  "required": ["english"],
@@ -15669,14 +16237,14 @@ const operationManifest = [
15669
16237
  "enum": ["grant", "do_not_share"]
15670
16238
  },
15671
16239
  "breadth": {
15672
- "description": "How many of your recent emails its conditions hold for, counted over your own mailboxes whatever scope you save it with, warning or not. Null when not counted in full: a rule with questions, headers-only access, no test of it possible as you, or a count that failed or ran out of time. Writes ignore it, so a compile answer (without include_sql) can be sent back unchanged.",
16240
+ "description": "How many recent emails its conditions hold for, warning or not, counted over evaluation_scope as sent (by default your own mailboxes, whatever scope you save it with). Null when not counted in full: a rule with questions, headers-only access, no test of it possible as you, a count that failed or ran out of time, or, with no scope sent, a rule that holds only for mail to To or Cc addresses outside your own mailboxes (a warning says so). Writes ignore it, so a compile answer (without include_sql) can be sent back unchanged.",
15673
16241
  "anyOf": [{
15674
16242
  "type": "object",
15675
16243
  "properties": {
15676
16244
  "checked": {
15677
16245
  "type": "integer",
15678
16246
  "minimum": 0,
15679
- "description": "Classified emails the conditions were decided for: of the newest 200 from the last 30 days in your own mailboxes (for a grant rule, those you may share), the ones you can still read."
16247
+ "description": "Classified emails the conditions were decided for: of the newest 200 from the last 30 days in the scope counted (evaluation_scope as sent; by default your own mailboxes, for a grant rule those you may share), the ones you can still read."
15680
16248
  },
15681
16249
  "matched": {
15682
16250
  "type": "integer",
@@ -15695,7 +16263,7 @@ const operationManifest = [
15695
16263
  "checked": {
15696
16264
  "type": "integer",
15697
16265
  "minimum": 0,
15698
- "description": "Classified emails the conditions were decided for: of the newest 200 from the last 30 days in your own mailboxes (for a grant rule, those you may share), the ones you can still read."
16266
+ "description": "Classified emails the conditions were decided for: of the newest 200 from the last 30 days in the scope counted (evaluation_scope as sent; by default your own mailboxes, for a grant rule those you may share), the ones you can still read."
15699
16267
  },
15700
16268
  "matched": {
15701
16269
  "type": "integer",
@@ -15919,6 +16487,16 @@ const operationManifest = [
15919
16487
  "pattern": "^[^\\u0000]*$"
15920
16488
  }
15921
16489
  },
16490
+ "attachment_names": {
16491
+ "maxItems": 10,
16492
+ "type": "array",
16493
+ "items": {
16494
+ "type": "string",
16495
+ "minLength": 1,
16496
+ "maxLength": 255,
16497
+ "pattern": "^[^\\u0000-\\u001f\\u007f]*$"
16498
+ }
16499
+ },
15922
16500
  "automated": { "type": "boolean" },
15923
16501
  "from_mailing_list": { "type": "boolean" },
15924
16502
  "spam_score": {
@@ -15997,7 +16575,7 @@ const operationManifest = [
15997
16575
  }
15998
16576
  },
15999
16577
  "warnings": {
16000
- "description": "The compile response's warnings. Stored as sent, then any server note they lack on an address or domain the description names that the rule does not test (on a rule request, every compiler note on the rule).",
16578
+ "description": "The compile response's warnings. Stored as sent, then any server note they lack on an address or domain the description names that the rule does not test, or on a grant rule that tests only who an email was sent to (on a rule request, every compiler note on the rule).",
16001
16579
  "maxItems": 10,
16002
16580
  "type": "array",
16003
16581
  "items": {
@@ -16020,7 +16598,7 @@ const operationManifest = [
16020
16598
  "checked": {
16021
16599
  "type": "integer",
16022
16600
  "minimum": 0,
16023
- "description": "Classified emails the conditions were decided for: of the newest 200 from the last 30 days in your own mailboxes (for a grant rule, those you may share), the ones you can still read."
16601
+ "description": "Classified emails the conditions were decided for: of the newest 200 from the last 30 days in the scope counted (evaluation_scope as sent; by default your own mailboxes, for a grant rule those you may share), the ones you can still read."
16024
16602
  },
16025
16603
  "matched": {
16026
16604
  "type": "integer",
@@ -16039,7 +16617,7 @@ const operationManifest = [
16039
16617
  "checked": {
16040
16618
  "type": "integer",
16041
16619
  "minimum": 0,
16042
- "description": "Classified emails the conditions were decided for: of the newest 200 from the last 30 days in your own mailboxes (for a grant rule, those you may share), the ones you can still read."
16620
+ "description": "Classified emails the conditions were decided for: of the newest 200 from the last 30 days in the scope counted (evaluation_scope as sent; by default your own mailboxes, for a grant rule those you may share), the ones you can still read."
16043
16621
  },
16044
16622
  "matched": {
16045
16623
  "type": "integer",
@@ -16148,6 +16726,15 @@ const operationManifest = [
16148
16726
  "type": "boolean",
16149
16727
  "description": "Whether you are its author, in your current membership. Only its author edits it."
16150
16728
  },
16729
+ "pending_objections": {
16730
+ "description": "To its author, on the dashboard or the Primitive CLI: objections to it waiting for their answer (GET /email-rule-objections). A write's answer leaves it out when it could not be read in time: absent is not 0.",
16731
+ "type": "integer",
16732
+ "minimum": 0
16733
+ },
16734
+ "objection_notice": {
16735
+ "description": "With pending_objections above 0: that members asked you to turn it off, and how to answer.",
16736
+ "type": "string"
16737
+ },
16151
16738
  "created_at": {
16152
16739
  "type": "string",
16153
16740
  "format": "date-time"
@@ -16274,6 +16861,27 @@ const operationManifest = [
16274
16861
  ]
16275
16862
  }
16276
16863
  },
16864
+ "expectations": {
16865
+ "description": "Its saved expectations, each list by email id, as stored: on every create, and on an update that set or removed them.",
16866
+ "type": "object",
16867
+ "properties": {
16868
+ "match": {
16869
+ "type": "array",
16870
+ "items": {
16871
+ "type": "string",
16872
+ "format": "uuid"
16873
+ }
16874
+ },
16875
+ "no_match": {
16876
+ "type": "array",
16877
+ "items": {
16878
+ "type": "string",
16879
+ "format": "uuid"
16880
+ }
16881
+ }
16882
+ },
16883
+ "required": ["match", "no_match"]
16884
+ },
16277
16885
  "expectation_samples": {
16278
16886
  "description": "Its saved made-up emails, when this write set or added some.",
16279
16887
  "type": "array",
@@ -16351,6 +16959,16 @@ const operationManifest = [
16351
16959
  "pattern": "^[^\\u0000]*$"
16352
16960
  }
16353
16961
  },
16962
+ "attachment_names": {
16963
+ "maxItems": 10,
16964
+ "type": "array",
16965
+ "items": {
16966
+ "type": "string",
16967
+ "minLength": 1,
16968
+ "maxLength": 255,
16969
+ "pattern": "^[^\\u0000-\\u001f\\u007f]*$"
16970
+ }
16971
+ },
16354
16972
  "automated": { "type": "boolean" },
16355
16973
  "from_mailing_list": { "type": "boolean" },
16356
16974
  "spam_score": {
@@ -16476,6 +17094,10 @@ const operationManifest = [
16476
17094
  "notice": {
16477
17095
  "description": "After a write that saved a version of an active rule keys or webhooks read without checking it first: what it changes, and how to have the next one checked.",
16478
17096
  "type": "string"
17097
+ },
17098
+ "share_notice": {
17099
+ "description": "After a write that ended the rule's share: that it did, given even when affects is not, with whom it was with and the version they accepted when those can be read.",
17100
+ "type": "string"
16479
17101
  }
16480
17102
  },
16481
17103
  "required": [
@@ -16595,7 +17217,7 @@ const operationManifest = [
16595
17217
  }
16596
17218
  },
16597
17219
  "warnings": {
16598
- "description": "The compile response's warnings. Stored as sent, then any server note they lack on an address or domain the description names that the rule does not test (on a rule request, every compiler note on the rule).",
17220
+ "description": "The compile response's warnings. Stored as sent, then any server note they lack on an address or domain the description names that the rule does not test, or on a grant rule that tests only who an email was sent to (on a rule request, every compiler note on the rule).",
16599
17221
  "maxItems": 10,
16600
17222
  "type": "array",
16601
17223
  "items": {
@@ -16618,7 +17240,7 @@ const operationManifest = [
16618
17240
  "checked": {
16619
17241
  "type": "integer",
16620
17242
  "minimum": 0,
16621
- "description": "Classified emails the conditions were decided for: of the newest 200 from the last 30 days in your own mailboxes (for a grant rule, those you may share), the ones you can still read."
17243
+ "description": "Classified emails the conditions were decided for: of the newest 200 from the last 30 days in the scope counted (evaluation_scope as sent; by default your own mailboxes, for a grant rule those you may share), the ones you can still read."
16622
17244
  },
16623
17245
  "matched": {
16624
17246
  "type": "integer",
@@ -16637,7 +17259,7 @@ const operationManifest = [
16637
17259
  "checked": {
16638
17260
  "type": "integer",
16639
17261
  "minimum": 0,
16640
- "description": "Classified emails the conditions were decided for: of the newest 200 from the last 30 days in your own mailboxes (for a grant rule, those you may share), the ones you can still read."
17262
+ "description": "Classified emails the conditions were decided for: of the newest 200 from the last 30 days in the scope counted (evaluation_scope as sent; by default your own mailboxes, for a grant rule those you may share), the ones you can still read."
16641
17263
  },
16642
17264
  "matched": {
16643
17265
  "type": "integer",
@@ -17097,7 +17719,7 @@ const operationManifest = [
17097
17719
  "binaryResponse": false,
17098
17720
  "bodyRequired": false,
17099
17721
  "command": "delete-email-rule",
17100
- "description": "Deletes a rule with its versions, its decisions and the access it granted. A share of it ends (end_reason rule_deleted), and the member who shared can still list what it handed over. The answer lists the shares it ended (ended_shares) and the unrevoked keys that still list it, which now read nothing through it (keys, other_keys; left out when they could not be read). The author or a reader of all the organization's mail may delete it; while it is shared, only the author or someone who manages members from the dashboard. Needs mail:read, the email rules feature, and a member's own full-access credential (no API key, agent key or narrowed token).",
17722
+ "description": "Deletes a rule with its versions, its decisions and the access it granted. A share of it ends (end_reason rule_deleted), and the member who shared can still list what it handed over. The answer lists the shares it ended (ended_shares), says whom with (share_notice), and lists the unrevoked keys that still list it, which now read nothing through it (keys, other_keys; left out when they could not be read). The author or a reader of all the organization's mail may delete it; while it is shared, only the author or someone who manages members from the dashboard. Needs mail:read, the email rules feature, and a member's own full-access credential (no API key, agent key or narrowed token).",
17101
17723
  "hasJsonBody": false,
17102
17724
  "method": "DELETE",
17103
17725
  "operationId": "deleteEmailRule",
@@ -17149,6 +17771,10 @@ const operationManifest = [
17149
17771
  "other_keys": {
17150
17772
  "description": "How many more keys, not revoked, list the rule that you may not read. They are not named.",
17151
17773
  "type": "integer"
17774
+ },
17775
+ "share_notice": {
17776
+ "description": "When the delete ended a share: that it did, with whom it was with and the version they accepted when those can be read.",
17777
+ "type": "string"
17152
17778
  }
17153
17779
  },
17154
17780
  "required": ["deleted"]
@@ -17321,7 +17947,7 @@ const operationManifest = [
17321
17947
  "description": "For a selected rule: inboxes, and domains (each address at them the author reads); each one you can read."
17322
17948
  },
17323
17949
  "rule_id": {
17324
- "description": "A saved rule you can see: its current version and words.",
17950
+ "description": "A saved rule you can see, or one that covers your mailboxes (as you, sent to one of them; dashboard or Primitive CLI only): its current version and words.",
17325
17951
  "type": "string",
17326
17952
  "format": "uuid"
17327
17953
  },
@@ -17447,6 +18073,10 @@ const operationManifest = [
17447
18073
  "type": "array",
17448
18074
  "items": { "type": "string" }
17449
18075
  },
18076
+ "attachment_names": {
18077
+ "type": "array",
18078
+ "items": { "type": "string" }
18079
+ },
17450
18080
  "automated": { "type": "boolean" },
17451
18081
  "from_mailing_list": { "type": "boolean" }
17452
18082
  },
@@ -17457,6 +18087,7 @@ const operationManifest = [
17457
18087
  "subject",
17458
18088
  "text",
17459
18089
  "attachment_types",
18090
+ "attachment_names",
17460
18091
  "automated",
17461
18092
  "from_mailing_list"
17462
18093
  ],
@@ -17671,6 +18302,15 @@ const operationManifest = [
17671
18302
  "type": "boolean",
17672
18303
  "description": "Whether you are its author, in your current membership. Only its author edits it."
17673
18304
  },
18305
+ "pending_objections": {
18306
+ "description": "To its author, on the dashboard or the Primitive CLI: objections to it waiting for their answer (GET /email-rule-objections). A write's answer leaves it out when it could not be read in time: absent is not 0.",
18307
+ "type": "integer",
18308
+ "minimum": 0
18309
+ },
18310
+ "objection_notice": {
18311
+ "description": "With pending_objections above 0: that members asked you to turn it off, and how to answer.",
18312
+ "type": "string"
18313
+ },
17674
18314
  "created_at": {
17675
18315
  "type": "string",
17676
18316
  "format": "date-time"
@@ -17865,6 +18505,16 @@ const operationManifest = [
17865
18505
  "pattern": "^[^\\u0000]*$"
17866
18506
  }
17867
18507
  },
18508
+ "attachment_names": {
18509
+ "maxItems": 10,
18510
+ "type": "array",
18511
+ "items": {
18512
+ "type": "string",
18513
+ "minLength": 1,
18514
+ "maxLength": 255,
18515
+ "pattern": "^[^\\u0000-\\u001f\\u007f]*$"
18516
+ }
18517
+ },
17868
18518
  "automated": { "type": "boolean" },
17869
18519
  "from_mailing_list": { "type": "boolean" },
17870
18520
  "spam_score": {
@@ -19329,6 +19979,11 @@ const operationManifest = [
19329
19979
  "count": {
19330
19980
  "type": "integer",
19331
19981
  "exclusiveMinimum": 0
19982
+ },
19983
+ "reads_in_full": {
19984
+ "description": "On a rule over your mail: how many of these keys also list one of your own mailboxes, or its domain, so they read your mail there beyond what this rule matches.",
19985
+ "type": "integer",
19986
+ "minimum": 0
19332
19987
  }
19333
19988
  },
19334
19989
  "required": ["owner", "count"]
@@ -19376,7 +20031,7 @@ const operationManifest = [
19376
20031
  "exclusiveMinimum": 0
19377
20032
  },
19378
20033
  "hosts": {
19379
- "description": "Distinct sites they deliver to (a host's registrable domain, or a tunnel, preview or function service alone), sorted, at most 10; \"unknown host\" (last) for any that cannot be named.",
20034
+ "description": "Distinct sites they deliver to (the domain a host is registered under, an app's own name on a known app platform, or a function URL service in its region), sorted, at most 10; \"unknown host\" (last) for any that cannot be named.",
19380
20035
  "type": "array",
19381
20036
  "items": { "type": "string" }
19382
20037
  },
@@ -19433,7 +20088,7 @@ const operationManifest = [
19433
20088
  "webhooks",
19434
20089
  "shares"
19435
20090
  ],
19436
- "description": "Who receives what the rule shares now, by person and count; empty unless it is an active grant rule."
20091
+ "description": "Who receives what the rule shares, by person and count. As receivers, empty unless it is an active grant rule."
19437
20092
  }, { "type": "null" }]
19438
20093
  }
19439
20094
  },
@@ -20420,6 +21075,15 @@ const operationManifest = [
20420
21075
  "type": "boolean",
20421
21076
  "description": "Whether you are its author, in your current membership. Only its author edits it."
20422
21077
  },
21078
+ "pending_objections": {
21079
+ "description": "To its author, on the dashboard or the Primitive CLI: objections to it waiting for their answer (GET /email-rule-objections). A write's answer leaves it out when it could not be read in time: absent is not 0.",
21080
+ "type": "integer",
21081
+ "minimum": 0
21082
+ },
21083
+ "objection_notice": {
21084
+ "description": "With pending_objections above 0: that members asked you to turn it off, and how to answer.",
21085
+ "type": "string"
21086
+ },
20423
21087
  "created_at": {
20424
21088
  "type": "string",
20425
21089
  "format": "date-time"
@@ -20867,6 +21531,16 @@ const operationManifest = [
20867
21531
  "pattern": "^[^\\u0000]*$"
20868
21532
  }
20869
21533
  },
21534
+ "attachment_names": {
21535
+ "maxItems": 10,
21536
+ "type": "array",
21537
+ "items": {
21538
+ "type": "string",
21539
+ "minLength": 1,
21540
+ "maxLength": 255,
21541
+ "pattern": "^[^\\u0000-\\u001f\\u007f]*$"
21542
+ }
21543
+ },
20870
21544
  "automated": { "type": "boolean" },
20871
21545
  "from_mailing_list": { "type": "boolean" },
20872
21546
  "spam_score": {
@@ -21177,6 +21851,11 @@ const operationManifest = [
21177
21851
  "minimum": 0,
21178
21852
  "description": "Emails decided on their conditions: matched, near_miss and no_match, less any missing a fact the rule reads."
21179
21853
  },
21854
+ "conditions_held": {
21855
+ "description": "Of decided, how many its conditions alone held for. Compile's breadth and conditions_breadth count this over recent mail in the scope sent to it, by default your own; here it is counted over the emails this test decided.",
21856
+ "type": "integer",
21857
+ "minimum": 0
21858
+ },
21180
21859
  "conditions": {
21181
21860
  "type": "array",
21182
21861
  "items": {
@@ -21244,7 +21923,7 @@ const operationManifest = [
21244
21923
  "warnings": {
21245
21924
  "type": "array",
21246
21925
  "items": { "type": "string" },
21247
- "description": "What to look at first, such as what stopped every email when nothing matched."
21926
+ "description": "What to look at first, such as what stopped every email when nothing matched. On a test of the recent window, a grant rule whose conditions held for more than 20% of at least 20 emails checked (at least 90% if it has no questions), or for every one of fewer, gets a warning saying so, before those about what it decided."
21248
21927
  }
21249
21928
  },
21250
21929
  "required": [
@@ -21447,7 +22126,7 @@ const operationManifest = [
21447
22126
  "binaryResponse": false,
21448
22127
  "bodyRequired": true,
21449
22128
  "command": "test-email-rule-on-sample",
21450
- "description": "Reports what a rule would decide for an email you describe (sender, recipients, subject, plain text, attachment types; optionally automated, from a mailing list, and a spam score), classified and decided as received mail would be. A rule reading a spam score you gave none for decides on none (unset_columns). Nothing is stored. Test an unsaved tree or a saved rule by rule_id. The answer includes what the classifier read. Needs mail:read, the email rules feature, and a member's own full-access credential (no API key, agent key or narrowed token).",
22129
+ "description": "Reports what a rule would decide for an email you describe (sender, recipients, subject, plain text, attachment types and file names; optionally automated, from a mailing list, and a spam score), classified and decided as received mail would be. A rule reading a spam score you gave none for decides on none (unset_columns). Nothing is stored. Test an unsaved tree or a saved rule by rule_id. The answer includes what the classifier read. Needs mail:read, the email rules feature, and a member's own full-access credential (no API key, agent key or narrowed token).",
21451
22130
  "hasJsonBody": true,
21452
22131
  "method": "POST",
21453
22132
  "operationId": "testEmailRuleOnSample",
@@ -21533,7 +22212,7 @@ const operationManifest = [
21533
22212
  "description": "For a selected rule: inboxes, and domains (each address at them the author reads); each one you can read."
21534
22213
  },
21535
22214
  "rule_id": {
21536
- "description": "A saved rule you can see. Its current version is tested.",
22215
+ "description": "A saved rule you can see, or one that covers your mailboxes (as you; dashboard or Primitive CLI only). Its current version is tested.",
21537
22216
  "type": "string",
21538
22217
  "format": "uuid"
21539
22218
  },
@@ -21604,6 +22283,17 @@ const operationManifest = [
21604
22283
  "maxLength": 255
21605
22284
  }
21606
22285
  },
22286
+ "attachment_names": {
22287
+ "description": "File names of those attachments, which the classifier and the questions read. With attachment_types, the same number, paired in order.",
22288
+ "maxItems": 20,
22289
+ "type": "array",
22290
+ "items": {
22291
+ "type": "string",
22292
+ "minLength": 1,
22293
+ "maxLength": 255,
22294
+ "pattern": "^[^\\u0000-\\u001f\\u007f]*$"
22295
+ }
22296
+ },
21607
22297
  "automated": {
21608
22298
  "description": "Whether the email was sent automatically, as its headers would show. Defaults to false.",
21609
22299
  "type": "boolean"
@@ -21890,7 +22580,7 @@ const operationManifest = [
21890
22580
  }
21891
22581
  },
21892
22582
  "warnings": {
21893
- "description": "The compile response's warnings. Stored as sent, then any server note they lack on an address or domain the description names that the rule does not test (on a rule request, every compiler note on the rule).",
22583
+ "description": "The compile response's warnings. Stored as sent, then any server note they lack on an address or domain the description names that the rule does not test, or on a grant rule that tests only who an email was sent to (on a rule request, every compiler note on the rule).",
21894
22584
  "maxItems": 10,
21895
22585
  "type": "array",
21896
22586
  "items": {
@@ -21913,7 +22603,7 @@ const operationManifest = [
21913
22603
  "checked": {
21914
22604
  "type": "integer",
21915
22605
  "minimum": 0,
21916
- "description": "Classified emails the conditions were decided for: of the newest 200 from the last 30 days in your own mailboxes (for a grant rule, those you may share), the ones you can still read."
22606
+ "description": "Classified emails the conditions were decided for: of the newest 200 from the last 30 days in the scope counted (evaluation_scope as sent; by default your own mailboxes, for a grant rule those you may share), the ones you can still read."
21917
22607
  },
21918
22608
  "matched": {
21919
22609
  "type": "integer",
@@ -21932,7 +22622,7 @@ const operationManifest = [
21932
22622
  "checked": {
21933
22623
  "type": "integer",
21934
22624
  "minimum": 0,
21935
- "description": "Classified emails the conditions were decided for: of the newest 200 from the last 30 days in your own mailboxes (for a grant rule, those you may share), the ones you can still read."
22625
+ "description": "Classified emails the conditions were decided for: of the newest 200 from the last 30 days in the scope counted (evaluation_scope as sent; by default your own mailboxes, for a grant rule those you may share), the ones you can still read."
21936
22626
  },
21937
22627
  "matched": {
21938
22628
  "type": "integer",
@@ -22091,6 +22781,16 @@ const operationManifest = [
22091
22781
  "pattern": "^[^\\u0000]*$"
22092
22782
  }
22093
22783
  },
22784
+ "attachment_names": {
22785
+ "maxItems": 10,
22786
+ "type": "array",
22787
+ "items": {
22788
+ "type": "string",
22789
+ "minLength": 1,
22790
+ "maxLength": 255,
22791
+ "pattern": "^[^\\u0000-\\u001f\\u007f]*$"
22792
+ }
22793
+ },
22094
22794
  "automated": { "type": "boolean" },
22095
22795
  "from_mailing_list": { "type": "boolean" },
22096
22796
  "spam_score": {
@@ -22198,6 +22898,16 @@ const operationManifest = [
22198
22898
  "pattern": "^[^\\u0000]*$"
22199
22899
  }
22200
22900
  },
22901
+ "attachment_names": {
22902
+ "maxItems": 10,
22903
+ "type": "array",
22904
+ "items": {
22905
+ "type": "string",
22906
+ "minLength": 1,
22907
+ "maxLength": 255,
22908
+ "pattern": "^[^\\u0000-\\u001f\\u007f]*$"
22909
+ }
22910
+ },
22201
22911
  "automated": { "type": "boolean" },
22202
22912
  "from_mailing_list": { "type": "boolean" },
22203
22913
  "spam_score": {
@@ -22332,6 +23042,15 @@ const operationManifest = [
22332
23042
  "type": "boolean",
22333
23043
  "description": "Whether you are its author, in your current membership. Only its author edits it."
22334
23044
  },
23045
+ "pending_objections": {
23046
+ "description": "To its author, on the dashboard or the Primitive CLI: objections to it waiting for their answer (GET /email-rule-objections). A write's answer leaves it out when it could not be read in time: absent is not 0.",
23047
+ "type": "integer",
23048
+ "minimum": 0
23049
+ },
23050
+ "objection_notice": {
23051
+ "description": "With pending_objections above 0: that members asked you to turn it off, and how to answer.",
23052
+ "type": "string"
23053
+ },
22335
23054
  "created_at": {
22336
23055
  "type": "string",
22337
23056
  "format": "date-time"
@@ -22458,6 +23177,27 @@ const operationManifest = [
22458
23177
  ]
22459
23178
  }
22460
23179
  },
23180
+ "expectations": {
23181
+ "description": "Its saved expectations, each list by email id, as stored: on every create, and on an update that set or removed them.",
23182
+ "type": "object",
23183
+ "properties": {
23184
+ "match": {
23185
+ "type": "array",
23186
+ "items": {
23187
+ "type": "string",
23188
+ "format": "uuid"
23189
+ }
23190
+ },
23191
+ "no_match": {
23192
+ "type": "array",
23193
+ "items": {
23194
+ "type": "string",
23195
+ "format": "uuid"
23196
+ }
23197
+ }
23198
+ },
23199
+ "required": ["match", "no_match"]
23200
+ },
22461
23201
  "expectation_samples": {
22462
23202
  "description": "Its saved made-up emails, when this write set or added some.",
22463
23203
  "type": "array",
@@ -22535,6 +23275,16 @@ const operationManifest = [
22535
23275
  "pattern": "^[^\\u0000]*$"
22536
23276
  }
22537
23277
  },
23278
+ "attachment_names": {
23279
+ "maxItems": 10,
23280
+ "type": "array",
23281
+ "items": {
23282
+ "type": "string",
23283
+ "minLength": 1,
23284
+ "maxLength": 255,
23285
+ "pattern": "^[^\\u0000-\\u001f\\u007f]*$"
23286
+ }
23287
+ },
22538
23288
  "automated": { "type": "boolean" },
22539
23289
  "from_mailing_list": { "type": "boolean" },
22540
23290
  "spam_score": {
@@ -22660,6 +23410,10 @@ const operationManifest = [
22660
23410
  "notice": {
22661
23411
  "description": "After a write that saved a version of an active rule keys or webhooks read without checking it first: what it changes, and how to have the next one checked.",
22662
23412
  "type": "string"
23413
+ },
23414
+ "share_notice": {
23415
+ "description": "After a write that ended the rule's share: that it did, given even when affects is not, with whom it was with and the version they accepted when those can be read.",
23416
+ "type": "string"
22663
23417
  }
22664
23418
  },
22665
23419
  "required": [
@@ -24272,6 +25026,29 @@ const operationManifest = [
24272
25026
  }
24273
25027
  }
24274
25028
  },
25029
+ "attachments": {
25030
+ "type": "array",
25031
+ "items": {
25032
+ "type": "object",
25033
+ "description": "Metadata for one attachment. The bytes are not inline; download\nall attachments for a message as a gzipped tarball via\n`/emails/{id}/attachments.tar.gz`. `sha256` lets you verify a\nspecific part after extraction.\n",
25034
+ "properties": {
25035
+ "filename": { "type": ["string", "null"] },
25036
+ "content_type": { "type": ["string", "null"] },
25037
+ "size_bytes": { "type": "integer" },
25038
+ "sha256": { "type": ["string", "null"] },
25039
+ "part_index": {
25040
+ "type": "integer",
25041
+ "description": "Zero-based index of this part within the message."
25042
+ },
25043
+ "tar_path": {
25044
+ "type": "string",
25045
+ "description": "This part's file name inside the message's attachments archive. Absent on attachments stored before it was recorded."
25046
+ }
25047
+ },
25048
+ "required": ["size_bytes"]
25049
+ },
25050
+ "description": "Attachment metadata (file name, type, size), the same items in the same order as `parsed.attachments`. Kept for a credential that reads headers only, where `parsed` is null. Empty when the email has none, its content is withheld (read `status` and `rejection_reason`), or it is not parsed yet or its parse failed (read `parse_status`). No bytes; download a part with `/emails/{id}/attachments/{part_index}`."
25051
+ },
24275
25052
  "imported": {
24276
25053
  "type": ["object", "null"],
24277
25054
  "description": "Historical acquisition; never sender or SMTP delivery proof. Null for live mail. Excluded from live tails and deltas.",
@@ -24330,6 +25107,7 @@ const operationManifest = [
24330
25107
  "from_verified",
24331
25108
  "from_header_email",
24332
25109
  "from_name",
25110
+ "attachments",
24333
25111
  "imported",
24334
25112
  "snippet"
24335
25113
  ]
@@ -24590,6 +25368,94 @@ const operationManifest = [
24590
25368
  "tag": "Emails",
24591
25369
  "tagCommand": "emails"
24592
25370
  },
25371
+ {
25372
+ "binaryResponse": false,
25373
+ "bodyRequired": true,
25374
+ "command": "import-google-mail-message",
25375
+ "description": "Requires the organization email_import entitlement, granted by staff. Only the configured current owner, using a full personal session or verified first-party CLI, may import into the configured primary mailbox. Primitive verifies the transient provider token and fetches RAW content itself. No raw uploads or client provenance are accepted. Sent, draft, spam and trash messages are skipped. Historical mail appears in normal history without live delivery effects. An indeterminate response requires retrying the same provider ID. User provider credentials are never stored or queued.",
25376
+ "hasJsonBody": true,
25377
+ "method": "POST",
25378
+ "operationId": "importGoogleMailMessage",
25379
+ "path": "/mail-imports/google/messages",
25380
+ "pathParams": [],
25381
+ "queryParams": [],
25382
+ "headerParams": [{
25383
+ "description": "Transient provider user access token. Send only in this redacted header, never in a URL or JSON body. Uses the dedicated configured desktop client and readonly/identity scopes.",
25384
+ "enum": null,
25385
+ "name": "X-Primitive-Google-Access-Token",
25386
+ "required": true,
25387
+ "type": "string"
25388
+ }, {
25389
+ "description": "Optional, and not used to deduplicate: this operation stores no result by the key, so a retry with the same key runs the request again. Operations that need a credential refuse a key that is empty, longer than 255 characters or not printable ASCII with 400 `validation_error` and echo a valid one in the Idempotency-Key response header; operations that need none ignore it.",
25390
+ "enum": null,
25391
+ "name": "Idempotency-Key",
25392
+ "required": false,
25393
+ "type": "string"
25394
+ }],
25395
+ "permissions": ["mail:read"],
25396
+ "access": null,
25397
+ "requestSchema": {
25398
+ "type": "object",
25399
+ "properties": { "message_id": {
25400
+ "type": "string",
25401
+ "pattern": "^[A-Za-z0-9_-]{1,128}$"
25402
+ } },
25403
+ "required": ["message_id"],
25404
+ "additionalProperties": false
25405
+ },
25406
+ "responseSchema": { "anyOf": [
25407
+ {
25408
+ "type": "object",
25409
+ "properties": {
25410
+ "status": {
25411
+ "type": "string",
25412
+ "enum": ["imported", "already_present"]
25413
+ },
25414
+ "email_id": {
25415
+ "type": "string",
25416
+ "format": "uuid",
25417
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
25418
+ }
25419
+ },
25420
+ "required": ["status", "email_id"]
25421
+ },
25422
+ {
25423
+ "type": "object",
25424
+ "properties": { "status": {
25425
+ "type": "string",
25426
+ "enum": [
25427
+ "suppressed",
25428
+ "in_progress",
25429
+ "indeterminate"
25430
+ ]
25431
+ } },
25432
+ "required": ["status"]
25433
+ },
25434
+ {
25435
+ "type": "object",
25436
+ "properties": {
25437
+ "status": {
25438
+ "type": "string",
25439
+ "const": "skipped"
25440
+ },
25441
+ "reason": {
25442
+ "type": "string",
25443
+ "enum": [
25444
+ "excluded_label",
25445
+ "out_of_window",
25446
+ "too_large",
25447
+ "provider_missing"
25448
+ ]
25449
+ }
25450
+ },
25451
+ "required": ["status", "reason"]
25452
+ }
25453
+ ] },
25454
+ "sdkName": "importGoogleMailMessage",
25455
+ "summary": "Import one historical Google Workspace message",
25456
+ "tag": "Emails",
25457
+ "tagCommand": "emails"
25458
+ },
24593
25459
  {
24594
25460
  "binaryResponse": false,
24595
25461
  "bodyRequired": false,
@@ -25306,6 +26172,50 @@ const operationManifest = [
25306
26172
  "tag": "Emails",
25307
26173
  "tagCommand": "emails"
25308
26174
  },
26175
+ {
26176
+ "binaryResponse": false,
26177
+ "bodyRequired": true,
26178
+ "command": "reconcile-google-mail-import",
26179
+ "description": "The same configured owner may recover expired attempts after the email_import entitlement is revoked. Recovery does not require that entitlement. Selects only server-owned manifests for the configured mailbox/account/policy. No provider token, object keys, prefixes or email IDs are accepted. Unsettled uploads remain unresolved and charged; this operation does not promise automatic cleanup after a process dies.",
26180
+ "hasJsonBody": true,
26181
+ "method": "POST",
26182
+ "operationId": "reconcileGoogleMailImport",
26183
+ "path": "/mail-imports/google/reconcile",
26184
+ "pathParams": [],
26185
+ "queryParams": [],
26186
+ "headerParams": [{
26187
+ "description": "Optional, and not used to deduplicate: this operation stores no result by the key, so a retry with the same key runs the request again. Operations that need a credential refuse a key that is empty, longer than 255 characters or not printable ASCII with 400 `validation_error` and echo a valid one in the Idempotency-Key response header; operations that need none ignore it.",
26188
+ "enum": null,
26189
+ "name": "Idempotency-Key",
26190
+ "required": false,
26191
+ "type": "string"
26192
+ }],
26193
+ "permissions": ["mail:read"],
26194
+ "access": null,
26195
+ "requestSchema": {
26196
+ "type": "object",
26197
+ "properties": {},
26198
+ "additionalProperties": false
26199
+ },
26200
+ "responseSchema": {
26201
+ "type": "object",
26202
+ "properties": {
26203
+ "cleaned": {
26204
+ "type": "integer",
26205
+ "minimum": 0
26206
+ },
26207
+ "unresolved": {
26208
+ "type": "integer",
26209
+ "minimum": 0
26210
+ }
26211
+ },
26212
+ "required": ["cleaned", "unresolved"]
26213
+ },
26214
+ "sdkName": "reconcileGoogleMailImport",
26215
+ "summary": "Reconcile scoped historical import attempts",
26216
+ "tag": "Emails",
26217
+ "tagCommand": "emails"
26218
+ },
25309
26219
  {
25310
26220
  "binaryResponse": false,
25311
26221
  "bodyRequired": false,
@@ -45776,6 +46686,33 @@ const operationManifest = [
45776
46686
  "type": "boolean",
45777
46687
  "description": "Send an informational message the receiver need not answer or wake for. It is sent as an `ack` signal (status `received`) about the message in `in_reply_to`, whose note is `body_text` (at most 2000 characters, which may be omitted). Receivers see it as `fyi: true`. Plain text only: it cannot be combined with `body_html`, `attachments`, `payload_attachments` or `scheduled_at`, and on `/send-mail` it requires `in_reply_to`."
45778
46688
  },
46689
+ "unsubscribe": {
46690
+ "type": "object",
46691
+ "additionalProperties": false,
46692
+ "required": ["url"],
46693
+ "description": "One-click unsubscribe for the message. Primitive writes a `List-Unsubscribe` header naming `url` (and `mailto` when given) and, unless `one_click` is false, `List-Unsubscribe-Post: List-Unsubscribe=One-Click` (RFC 8058), and DKIM-signs both. A receiver that offers one-click unsubscribe sends an HTTPS POST to `url` with the form body `List-Unsubscribe=One-Click`; your endpoint records the unsubscribe. Every recipient of the message gets the same `url`, so send one message per recipient when the URL identifies who to unsubscribe. The `headers` map refuses both header names, so this field is the only way to set them, and the headers it adds count toward the 25 entries `headers` may hold. A field whose rendered `List-Unsubscribe` would pass 980 characters is refused. Not accepted on a repeating send.",
46694
+ "properties": {
46695
+ "url": {
46696
+ "type": "string",
46697
+ "minLength": 1,
46698
+ "maxLength": 700,
46699
+ "pattern": "^[Hh][Tt][Tt][Pp][Ss]://(?:[A-Za-z0-9\\-._~:/?#\\[\\]@!$&'()*+;=]|%[0-9A-Fa-f]{2})+$",
46700
+ "description": "Absolute https URL that unsubscribes the recipient, at most 700 characters of URL characters only: printable ASCII with no spaces, double quotes, angle brackets or commas (percent-encode a comma as %2C), `%` only as a percent-encoded byte, `[` and `]` only around an IPv6 address host, a port from 1 to 65535, no `=?` (which mail readers can decode as an encoded word), and no user name or password. The host must be public: not a single-label name, `localhost` or a name under `.localhost`, `.internal`, `.local`, `.home.arpa` or `.localdomain`, or a loopback, link-local, private, shared, reserved, multicast or unspecified IP address, including an IPv6 address that embeds one. The scheme is written in lower case."
46701
+ },
46702
+ "one_click": {
46703
+ "type": "boolean",
46704
+ "default": true,
46705
+ "description": "Whether to also write `List-Unsubscribe-Post: List-Unsubscribe=One-Click`, which tells the receiver it may unsubscribe with a single POST to `url`. Set false when `url` needs the recipient to open a page and confirm."
46706
+ },
46707
+ "mailto": {
46708
+ "type": "string",
46709
+ "minLength": 3,
46710
+ "maxLength": 254,
46711
+ "pattern": "^[A-Za-z0-9!$'*+=_~-]+(?:\\.[A-Za-z0-9!$'*+=_~-]+)*@[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?(?:\\.[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?)+$",
46712
+ "description": "An address to also offer as a `mailto:` unsubscribe, written after `url`. The address alone, without the `mailto:` prefix: at most 64 letters, digits and `.!$'*+=_~-` before the `@`, and a dotted domain after it. An `=` is written as `%3D` in the header."
46713
+ }
46714
+ }
46715
+ },
45779
46716
  "headers": {
45780
46717
  "type": "object",
45781
46718
  "maxProperties": 25,
@@ -46937,6 +47874,33 @@ const operationManifest = [
46937
47874
  }
46938
47875
  }
46939
47876
  },
47877
+ "unsubscribe": {
47878
+ "type": "object",
47879
+ "additionalProperties": false,
47880
+ "required": ["url"],
47881
+ "description": "One-click unsubscribe for the message. Primitive writes a `List-Unsubscribe` header naming `url` (and `mailto` when given) and, unless `one_click` is false, `List-Unsubscribe-Post: List-Unsubscribe=One-Click` (RFC 8058), and DKIM-signs both. A receiver that offers one-click unsubscribe sends an HTTPS POST to `url` with the form body `List-Unsubscribe=One-Click`; your endpoint records the unsubscribe. Every recipient of the message gets the same `url`, so send one message per recipient when the URL identifies who to unsubscribe. The `headers` map refuses both header names, so this field is the only way to set them, and the headers it adds count toward the 25 entries `headers` may hold. A field whose rendered `List-Unsubscribe` would pass 980 characters is refused. Not accepted on a repeating send.",
47882
+ "properties": {
47883
+ "url": {
47884
+ "type": "string",
47885
+ "minLength": 1,
47886
+ "maxLength": 700,
47887
+ "pattern": "^[Hh][Tt][Tt][Pp][Ss]://(?:[A-Za-z0-9\\-._~:/?#\\[\\]@!$&'()*+;=]|%[0-9A-Fa-f]{2})+$",
47888
+ "description": "Absolute https URL that unsubscribes the recipient, at most 700 characters of URL characters only: printable ASCII with no spaces, double quotes, angle brackets or commas (percent-encode a comma as %2C), `%` only as a percent-encoded byte, `[` and `]` only around an IPv6 address host, a port from 1 to 65535, no `=?` (which mail readers can decode as an encoded word), and no user name or password. The host must be public: not a single-label name, `localhost` or a name under `.localhost`, `.internal`, `.local`, `.home.arpa` or `.localdomain`, or a loopback, link-local, private, shared, reserved, multicast or unspecified IP address, including an IPv6 address that embeds one. The scheme is written in lower case."
47889
+ },
47890
+ "one_click": {
47891
+ "type": "boolean",
47892
+ "default": true,
47893
+ "description": "Whether to also write `List-Unsubscribe-Post: List-Unsubscribe=One-Click`, which tells the receiver it may unsubscribe with a single POST to `url`. Set false when `url` needs the recipient to open a page and confirm."
47894
+ },
47895
+ "mailto": {
47896
+ "type": "string",
47897
+ "minLength": 3,
47898
+ "maxLength": 254,
47899
+ "pattern": "^[A-Za-z0-9!$'*+=_~-]+(?:\\.[A-Za-z0-9!$'*+=_~-]+)*@[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?(?:\\.[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?)+$",
47900
+ "description": "An address to also offer as a `mailto:` unsubscribe, written after `url`. The address alone, without the `mailto:` prefix: at most 64 letters, digits and `.!$'*+=_~-` before the `@`, and a dotted domain after it. An `=` is written as `%3D` in the header."
47901
+ }
47902
+ }
47903
+ },
46940
47904
  "headers": {
46941
47905
  "type": "object",
46942
47906
  "maxProperties": 25,
@@ -47417,6 +48381,33 @@ const operationManifest = [
47417
48381
  }
47418
48382
  }
47419
48383
  },
48384
+ "unsubscribe": {
48385
+ "type": "object",
48386
+ "additionalProperties": false,
48387
+ "required": ["url"],
48388
+ "description": "One-click unsubscribe for the message. Primitive writes a `List-Unsubscribe` header naming `url` (and `mailto` when given) and, unless `one_click` is false, `List-Unsubscribe-Post: List-Unsubscribe=One-Click` (RFC 8058), and DKIM-signs both. A receiver that offers one-click unsubscribe sends an HTTPS POST to `url` with the form body `List-Unsubscribe=One-Click`; your endpoint records the unsubscribe. Every recipient of the message gets the same `url`, so send one message per recipient when the URL identifies who to unsubscribe. The `headers` map refuses both header names, so this field is the only way to set them, and the headers it adds count toward the 25 entries `headers` may hold. A field whose rendered `List-Unsubscribe` would pass 980 characters is refused. Not accepted on a repeating send.",
48389
+ "properties": {
48390
+ "url": {
48391
+ "type": "string",
48392
+ "minLength": 1,
48393
+ "maxLength": 700,
48394
+ "pattern": "^[Hh][Tt][Tt][Pp][Ss]://(?:[A-Za-z0-9\\-._~:/?#\\[\\]@!$&'()*+;=]|%[0-9A-Fa-f]{2})+$",
48395
+ "description": "Absolute https URL that unsubscribes the recipient, at most 700 characters of URL characters only: printable ASCII with no spaces, double quotes, angle brackets or commas (percent-encode a comma as %2C), `%` only as a percent-encoded byte, `[` and `]` only around an IPv6 address host, a port from 1 to 65535, no `=?` (which mail readers can decode as an encoded word), and no user name or password. The host must be public: not a single-label name, `localhost` or a name under `.localhost`, `.internal`, `.local`, `.home.arpa` or `.localdomain`, or a loopback, link-local, private, shared, reserved, multicast or unspecified IP address, including an IPv6 address that embeds one. The scheme is written in lower case."
48396
+ },
48397
+ "one_click": {
48398
+ "type": "boolean",
48399
+ "default": true,
48400
+ "description": "Whether to also write `List-Unsubscribe-Post: List-Unsubscribe=One-Click`, which tells the receiver it may unsubscribe with a single POST to `url`. Set false when `url` needs the recipient to open a page and confirm."
48401
+ },
48402
+ "mailto": {
48403
+ "type": "string",
48404
+ "minLength": 3,
48405
+ "maxLength": 254,
48406
+ "pattern": "^[A-Za-z0-9!$'*+=_~-]+(?:\\.[A-Za-z0-9!$'*+=_~-]+)*@[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?(?:\\.[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?)+$",
48407
+ "description": "An address to also offer as a `mailto:` unsubscribe, written after `url`. The address alone, without the `mailto:` prefix: at most 64 letters, digits and `.!$'*+=_~-` before the `@`, and a dotted domain after it. An `=` is written as `%3D` in the header."
48408
+ }
48409
+ }
48410
+ },
47420
48411
  "headers": {
47421
48412
  "type": "object",
47422
48413
  "maxProperties": 25,
@@ -52064,6 +53055,7 @@ const SAMPLE_EMAIL_KEYS = /* @__PURE__ */ new Set([
52064
53055
  "subject",
52065
53056
  "text",
52066
53057
  "attachment_types",
53058
+ "attachment_names",
52067
53059
  "automated",
52068
53060
  "from_mailing_list",
52069
53061
  "spam_score"
@@ -52091,6 +53083,10 @@ function checkSampleEmail(email, at) {
52091
53083
  list("to", 1);
52092
53084
  list("cc", 0);
52093
53085
  list("attachment_types", 0);
53086
+ list("attachment_names", 0);
53087
+ const types = email.attachment_types;
53088
+ const names = email.attachment_names;
53089
+ if (Array.isArray(types) && Array.isArray(names) && types.length > 0 && names.length > 0 && types.length !== names.length) fail("attachment_names pairs with attachment_types by position, so give the same number of each");
52094
53090
  if (email.subject !== void 0 && (typeof email.subject !== "string" || email.subject.length > SAMPLE_SUBJECT_MAX)) fail(`subject must be a string of at most ${SAMPLE_SUBJECT_MAX} characters`);
52095
53091
  if (typeof email.text !== "string" || email.text.length === 0 || email.text.length > SAMPLE_TEXT_MAX) fail(`text must be 1 to ${SAMPLE_TEXT_MAX} characters`);
52096
53092
  for (const key of ["automated", "from_mailing_list"]) if (email[key] !== void 0 && typeof email[key] !== "boolean") fail(`${key} must be true or false`);
@@ -52647,7 +53643,9 @@ function answerText(answer) {
52647
53643
  function conditionLines(summary) {
52648
53644
  const conditions = Array.isArray(summary?.conditions) ? summary.conditions : [];
52649
53645
  if (conditions.length === 0) return [];
52650
- return [`Conditions (${summary?.decided ?? 0} decided):`, ...conditions.map((condition) => ` ${condition.index}. ${condition.text}: held on ${condition.held}, failed on ${condition.failed} (the only failure on ${condition.only_failure})`)];
53646
+ const held = summary?.conditions_held;
53647
+ const together = typeof held === "number" ? `; together they held on ${held}` : "";
53648
+ return [`Conditions (${summary?.decided ?? 0} decided${together}):`, ...conditions.map((condition) => ` ${condition.index}. ${condition.text}: held on ${condition.held}, failed on ${condition.failed} (the only failure on ${condition.only_failure})`)];
52651
53649
  }
52652
53650
  function questionLines(summary, results) {
52653
53651
  const questions = Array.isArray(summary?.questions) ? summary.questions : [];
@@ -52991,6 +53989,10 @@ function authorLine(author) {
52991
53989
  if (name || email) return `Author: ${name ?? email}`;
52992
53990
  return `Author: user ${author.user_id} (name and email not shown to you)`;
52993
53991
  }
53992
+ /** A note the server wrote on a rule answer, as a line, or undefined. */
53993
+ function noteLine(note) {
53994
+ return typeof note === "string" && note.trim() ? note.trim() : void 0;
53995
+ }
52994
53996
  /** The stderr report of a rule written by create-email-rule or update-email-rule. */
52995
53997
  function writtenEmailRuleReport(data, request) {
52996
53998
  if (!isRecord(data)) return { lines: [] };
@@ -53005,11 +54007,17 @@ function writtenEmailRuleReport(data, request) {
53005
54007
  if (restored) lines.push(restored);
53006
54008
  const reach = affectsLine(rule.affects);
53007
54009
  if (reach) lines.push(reach);
54010
+ for (const note of [rule.share_notice, rule.notice]) {
54011
+ const line = noteLine(note);
54012
+ if (line) lines.push(line);
54013
+ }
53008
54014
  const sentExpectations = sentExpectationsIn(request.body);
53009
54015
  const name = writtenSampleNamer(request.body, request.flags, rule.expectation_samples);
53010
54016
  const checked = expectationsCheckLine(rule.expectations_check, ruleId, name);
53011
54017
  if (checked) lines.push(checked);
53012
54018
  else if (sentExpectations) lines.push(`Expectations were not checked on this write. Test them with \`primitive email-rules test-email-rule --rule-id ${ruleId}\`.`);
54019
+ const objections = noteLine(rule.objection_notice);
54020
+ if (objections) lines.push(objections);
53013
54021
  if (request.flags?.["fail-on-expectations"] !== true) return { lines };
53014
54022
  return {
53015
54023
  lines,
@@ -53060,7 +54068,9 @@ function deleteEmailRuleReport(data, request) {
53060
54068
  const answer = data;
53061
54069
  const lines = [];
53062
54070
  const ended = Array.isArray(answer.ended_shares) ? answer.ended_shares.length : 0;
53063
- if (ended > 0) lines.push(`Ended ${ended === 1 ? "1 share" : `${ended} shares`} of this rule (end_reason rule_deleted). ${ended === 1 ? "It keeps its record" : "Each keeps its record"}.`);
54071
+ const shareNotice = noteLine(answer.share_notice);
54072
+ if (shareNotice) lines.push(shareNotice);
54073
+ else if (ended > 0) lines.push(`Ended ${ended === 1 ? "1 share" : `${ended} shares`} of this rule (end_reason rule_deleted). ${ended === 1 ? "It keeps its record" : "Each keeps its record"}.`);
53064
54074
  const keys = Array.isArray(answer.keys) ? answer.keys : [];
53065
54075
  const others = typeof answer.other_keys === "number" && answer.other_keys > 0 ? answer.other_keys : 0;
53066
54076
  const ruleId = typeof request.path.id === "string" ? request.path.id : "<rule-id>";
@@ -53097,16 +54107,37 @@ function readAgain(id) {
53097
54107
  return `Read it again with \`primitive email-rules get-email-rule ${id}\` and send the write again`;
53098
54108
  }
53099
54109
  /**
54110
+ * Who reads an active rule, from a refusal's details.read_by: the server
54111
+ * sends it when it checked the write against the rule's expectations because
54112
+ * API keys or webhooks read the rule, whether or not the write asked.
54113
+ * Undefined without it.
54114
+ */
54115
+ function readByText(details) {
54116
+ const readBy = details.read_by;
54117
+ if (!isRecord(readBy)) return void 0;
54118
+ const { keys, webhooks } = readBy;
54119
+ return typeof keys === "number" && typeof webhooks === "number" ? `${plural$1(keys, "API key", "API keys")} and ${plural$1(webhooks, "webhook", "webhooks")} read what it grants` : "API keys or webhooks may read what it grants (they could not be counted in time)";
54120
+ }
54121
+ /** How to save a write the default check refused, without the check. */
54122
+ function saveUncheckedText(flags) {
54123
+ return flags?.["fail-on-expectations"] === true ? `send it again without --${FAIL_ON_EXPECTATIONS_FLAG} and with --no-if-expectations-pass` : "send it again with --no-if-expectations-pass";
54124
+ }
54125
+ /**
53100
54126
  * The hint for update-email-rule's refusals: an email_rule_conflict by its
53101
54127
  * details.reason (version_moved, revision_moved, expectations_moved,
53102
- * rule_changed), and the expectations guard's expectations_failed,
53103
- * expectations_undecided, expectations_unreadable and no_expectations.
53104
- * Nothing was saved in any of them.
54128
+ * rule_changed, readers_changed), and the expectations guard's
54129
+ * expectations_failed, expectations_undecided, expectations_unreadable and
54130
+ * no_expectations. The guard runs when the write sends if_expectations_pass,
54131
+ * and by default (details.read_by) when it changes what an active rule that
54132
+ * API keys or webhooks read grants. Nothing was saved in any of them.
53105
54133
  */
53106
54134
  function updateEmailRuleErrorHint(code, payload, ruleId, body, flags) {
53107
54135
  const id = typeof ruleId === "string" && ruleId ? ruleId : "<rule-id>";
53108
54136
  const details = errorDetails(payload);
53109
54137
  const guarded = isRecord(body) && body.if_expectations_pass === true;
54138
+ const readBy = readByText(details);
54139
+ const judged = readBy ? "was judged against its expectations before saving, as a write that changes what an active rule grants is by default while API keys or webhooks read it, and nothing was saved" : "was judged against its expectations before saving (if_expectations_pass), and nothing was saved";
54140
+ const unchecked = readBy ? ` The rule is active and ${readBy}; to save the write without the check, ${saveUncheckedText(flags)}.` : "";
53110
54141
  if (code === "email_rule_conflict") switch (details.reason) {
53111
54142
  case "version_moved": return versionMovedHint(payload, ruleId);
53112
54143
  case "revision_moved": {
@@ -53115,6 +54146,7 @@ function updateEmailRuleErrorHint(code, payload, ruleId, body, flags) {
53115
54146
  }
53116
54147
  case "expectations_moved": return `Hint: the rule's saved expectations changed while this write was checked against them, so nothing was saved. ${readAgain(id)}.`;
53117
54148
  case "rule_changed": return guarded ? `Hint: the rule changed after this write was judged against its expectations and before it was saved, so saving it would have gone unchecked; nothing was saved. ${readAgain(id)}.` : `Hint: the rule changed while this write was being saved, so nothing was saved. ${readAgain(id)}.`;
54149
+ case "readers_changed": return "Hint: API keys or webhooks started reading this rule while this write was being saved, and saving it would have changed what they receive without checking it against the rule's expectations, so nothing was saved. Send the write again: it is then checked first.";
53118
54150
  default: return;
53119
54151
  }
53120
54152
  if (code === "expectations_failed" || code === "expectations_undecided") {
@@ -53131,16 +54163,16 @@ function updateEmailRuleErrorHint(code, payload, ruleId, body, flags) {
53131
54163
  const reason = String(details.reason);
53132
54164
  const samplesMayStay = undecidedSamplesMayStay(undecidedSamples.length, reason);
53133
54165
  const byReason = reason !== "none" && Object.hasOwn(UNDECIDED_NEXT_STEP, reason) ? UNDECIDED_NEXT_STEP[reason] : UNDECIDED_NEXT_STEP.none;
53134
- return `Hint: the rule, as this write would leave it, was judged against its expectations before saving (if_expectations_pass), and nothing was saved.${which}${code === "expectations_failed" ? "" : samplesMayStay ? `${undecided.length > 0 ? ` ${byReason}` : ""} ${UNDECIDED_SAMPLES_NEXT_STEP} ${refusedSampleTest(body, id)}` : ` ${byReason}`} The command exits ${updateEmailRuleErrorExitCode(payload) ?? 1}.`;
54166
+ return `Hint: the rule, as this write would leave it, ${judged}.${which}${code === "expectations_failed" ? "" : samplesMayStay ? `${undecided.length > 0 ? ` ${byReason}` : ""} ${UNDECIDED_SAMPLES_NEXT_STEP} ${refusedSampleTest(body, id)}` : ` ${byReason}`}${unchecked} The command exits ${updateEmailRuleErrorExitCode(payload) ?? 1}.`;
53135
54167
  }
53136
54168
  if (code === "expectations_unreadable") {
53137
54169
  const unreadable = Array.isArray(details.unreadable) ? details.unreadable.filter((entry) => entry !== null && entry !== void 0 && entry !== "").map(String) : [];
53138
54170
  const one = unreadable.length === 1;
53139
54171
  const named = unreadable.length > 0 ? `: ${unreadable.join(", ")}` : "";
53140
54172
  const them = one ? "it" : "them";
53141
- return `Hint: the rule, as this write would leave it, was judged against its expectations before saving (if_expectations_pass), and nothing was saved. ${one ? "An expectation names an email" : "Expectations name emails"} this rule cannot read (deleted, or outside its scope or its author's mail)${named}. Sending the write again will not decide ${them}: send --expectations-file without ${them}, or an evaluation_scope that reads ${them}. The command exits 1.`;
54173
+ return `Hint: the rule, as this write would leave it, ${judged}. ${one ? "An expectation names an email" : "Expectations name emails"} this rule cannot read (deleted, or outside its scope or its author's mail)${named}. Sending the write again will not decide ${them}: send --expectations-file without ${them}, or an evaluation_scope that reads ${them}.${unchecked} The command exits 1.`;
53142
54174
  }
53143
- if (code === "no_expectations") return "Hint: nothing was saved. Give the rule expectations with --expectations-file or made-up emails with --expectation-samples-file or --add-expectation-samples-file (in this write or before it), or send the write without if_expectations_pass (--fail-on-expectations or --if-expectations-pass).";
54175
+ if (code === "no_expectations") return readBy ? `Hint: nothing was saved: this write removes the rule's expectations, and the rule is active and ${readBy}, so a write that changes what it grants is checked against them first. Keep some with --expectations-file, --expectation-samples-file or --add-expectation-samples-file, or, to save the write without the check, ${saveUncheckedText(flags)}.` : "Hint: nothing was saved. Give the rule expectations with --expectations-file or made-up emails with --expectation-samples-file or --add-expectation-samples-file (in this write or before it), or send the write without if_expectations_pass (--fail-on-expectations or --if-expectations-pass).";
53144
54176
  }
53145
54177
  /** The reasons a guard's undecided judgment can be decided by sending the write again. */
53146
54178
  const RETRYABLE_REASONS = /* @__PURE__ */ new Set([
@@ -53197,12 +54229,20 @@ function updateEmailRuleErrorExitCode(payload) {
53197
54229
  function undecidedSamplesMayStay(count, reason) {
53198
54230
  return count > 0 && !RETRYABLE_REASONS.has(reason) && reason !== "author_unresolvable";
53199
54231
  }
54232
+ /** Where compile counted breadth, by the evaluation_scope it was sent. */
54233
+ const BREADTH_SCOPE = {
54234
+ own_mailboxes: "in your own mailboxes",
54235
+ author: "in all the mail you can read",
54236
+ selected: "in the inboxes and domains the selected scope names"
54237
+ };
53200
54238
  /** The stderr report of compile-email-rule: how many recent emails it holds for. */
53201
- function compileEmailRuleReport(data) {
54239
+ function compileEmailRuleReport(data, request) {
53202
54240
  if (!isRecord(data)) return { lines: [] };
53203
54241
  const lines = (Array.isArray(data.warnings) ? data.warnings : []).filter((warning) => typeof warning === "string" && warning.trim() !== "").map((warning) => `Warning: ${warning.trim()}`);
53204
54242
  const breadth = data.breadth;
53205
- if (isRecord(breadth) && typeof breadth.checked === "number" && typeof breadth.matched === "number") lines.push(`Breadth: its conditions hold for ${breadth.matched} of ${plural$1(breadth.checked, "recent email", "recent emails")} checked in your own mailboxes, whatever scope you save it with.`);
54243
+ const sent = isRecord(request?.body) && typeof request.body.evaluation_scope === "string" ? request.body.evaluation_scope : void 0;
54244
+ const where = sent === void 0 ? "in your own mailboxes, the default; pass --evaluation-scope to count over the scope you will save it with" : BREADTH_SCOPE[sent] ?? `in evaluation_scope ${sent}`;
54245
+ if (isRecord(breadth) && typeof breadth.checked === "number" && typeof breadth.matched === "number") lines.push(`Breadth: its conditions hold for ${breadth.matched} of ${plural$1(breadth.checked, "recent email", "recent emails")} checked ${where}.`);
53206
54246
  return { lines };
53207
54247
  }
53208
54248
  /** The stderr report of get-email-rule: who wrote it, and its revision. */
@@ -53214,6 +54254,8 @@ function getEmailRuleReport(data) {
53214
54254
  const protection = protectionLine(data);
53215
54255
  if (protection) lines.push(protection);
53216
54256
  if (typeof data.revision === "number") lines.push(`Revision ${data.revision}: pass --if-revision ${data.revision} to update-email-rule so a change made since is never replaced unseen.`);
54257
+ const objections = noteLine(data.objection_notice);
54258
+ if (objections) lines.push(objections);
53217
54259
  return { lines };
53218
54260
  }
53219
54261
  /** The stderr report of list-email-rules: the protective rules that protect nothing yet, or less than they seem. */
@@ -53233,9 +54275,11 @@ function listEmailRulesReport(data) {
53233
54275
  /** create-email-rule's --fail-on-expectations: the exit code follows the check made after saving. */
53234
54276
  const FAIL_ON_EXPECTATIONS_HELP = "Exit 1 when an expectation in the answer's expectations_check failed, and 3 when none failed but one is undecided or the expectations this write sent were not checked (test the rule to decide). A create does not judge made-up emails, so with some it exits 3. Without it the command exits 0 whatever the check says.";
53235
54277
  /** update-email-rule's --fail-on-expectations: the server refuses the write. */
53236
- const UPDATE_FAIL_ON_EXPECTATIONS_HELP = "Refuse the write unless the rule, as this write would leave it, passes its expectations. It sends if_expectations_pass (over any in --body-file or --raw-body), so the server judges a new version, a restored one, a new scope or turning the rule active before saving, on its emails by id and its made-up emails, and saves nothing when one failed (exit 1), one names an email the rule cannot read (exit 1, since sending again never decides it), one is undecided (exit 3, or 1 when the rule cannot run as its author or a made-up email is undecided for no reason the answer gives) or the rule has none (exit 1). It can take as long as a test of the rule; the command waits for it. Judging needs a credential that reads the mail's content. A write the server does not judge (one changing only expectations, say) is saved, and the exit code then follows the answer's expectations_check, as on create. With --json, a refused write's document holds the API's error alone; a saved write's holds the rule.";
54278
+ const UPDATE_FAIL_ON_EXPECTATIONS_HELP = "Refuse the write unless the rule, as this write would leave it, passes its expectations. It sends if_expectations_pass (over any in --body-file or --raw-body), so the server judges a new version, a restored one, a new scope or turning the rule active before saving, on its emails by id and its made-up emails, and saves nothing when one failed (exit 1), one names an email the rule cannot read (exit 1, since sending again never decides it), one is undecided (exit 3, or 1 when the rule cannot run as its author or a made-up email is undecided for no reason the answer gives) or the rule has none (exit 1). It can take as long as a test of the rule; the command waits for it. Judging needs a credential that reads the mail's content. A write the server does not judge (one changing only expectations, say) is saved, and the exit code then follows the answer's expectations_check, as on create. Without it, the server still judges, and refuses the same way, a write that saves a version or changes the scope of an active rule that API keys or webhooks read and that has expectations (the refusal's details.read_by counts them), unless --no-if-expectations-pass is sent. With --json, a refused write's document holds the API's error alone; a saved write's holds the rule.";
54279
+ /** When update-email-rule judges the made-up emails a samples flag sets. */
54280
+ const UPDATE_JUDGES_SAMPLES = `The write judges them before saving with --${FAIL_ON_EXPECTATIONS_FLAG}, when it saves a version or turns the rule active, and without it when it saves a version or changes the scope of an active rule that API keys or webhooks read, unless --no-if-expectations-pass is sent.`;
53237
54281
  /** What a samples file flag reads. */
53238
- const SAMPLES_FILE_SHAPE = "A JSON file of made-up emails the rule must match or not: an array such as [{\"expected\": \"no_match\", \"label\": \"a personal bill\", \"email\": {...}}], with email as test-email-rule-on-sample takes it (text up to 4,000 characters, at most 10 each of to, cc and attachment_types), like the one generate-look-alikes --samples-file writes, or a generate-look-alikes answer saved as it printed it.";
54282
+ const SAMPLES_FILE_SHAPE = "A JSON file of made-up emails the rule must match or not: an array such as [{\"expected\": \"no_match\", \"label\": \"a personal bill\", \"email\": {...}}], with email as test-email-rule-on-sample takes it (text up to 4,000 characters, at most 10 each of to, cc, attachment_types and attachment_names), like the one generate-look-alikes --samples-file writes, or a generate-look-alikes answer saved as it printed it.";
53239
54283
  const EXPECTATION_FLAG_NOTE = "Replaces any expect in --body-file or --raw-body. The answer reports them in expectations (passed, counts, results) and the exit code follows it; see --help-full.";
53240
54284
  /**
53241
54285
  * update-email-rule's --fail-on-expectations sends if_expectations_pass, over
@@ -53313,11 +54357,11 @@ const EMAIL_RULE_OPERATION_EXTENSIONS = {
53313
54357
  flags: {
53314
54358
  "expectations-file": Flags.string({ description: "A JSON file holding the emails the rule must match and must not, such as {\"match\": [\"<email-id>\"], \"no_match\": [\"<email-id>\"]}, replacing its saved expectations; a file holding null removes them. Sets expectations, over any in --body-file or --raw-body; the answer judges them in expectations_check (passed, decided, failed, undecided); the report test-email-rule answers with is named expectations instead." }),
53315
54359
  [SAMPLES_FILE_FLAG]: Flags.string({
53316
- description: `${SAMPLES_FILE_SHAPE} They replace the rule's saved ones, and a file holding [] removes them. Sets expectation_samples, over any in --body-file or --raw-body. Not with --${ADD_SAMPLES_FILE_FLAG}. The write judges them only with --${FAIL_ON_EXPECTATIONS_FLAG}, and only when it saves a version or turns the rule active.`,
54360
+ description: `${SAMPLES_FILE_SHAPE} They replace the rule's saved ones, and a file holding [] removes them. Sets expectation_samples, over any in --body-file or --raw-body. Not with --${ADD_SAMPLES_FILE_FLAG}. ${UPDATE_JUDGES_SAMPLES}`,
53317
54361
  exclusive: [ADD_SAMPLES_FILE_FLAG]
53318
54362
  }),
53319
54363
  [ADD_SAMPLES_FILE_FLAG]: Flags.string({
53320
- description: `${SAMPLES_FILE_SHAPE} They are added to the rule's saved ones, 20 at most in all. Sets add_expectation_samples, over any in --body-file or --raw-body. Not with --${SAMPLES_FILE_FLAG}. The write judges them only with --${FAIL_ON_EXPECTATIONS_FLAG}, and only when it saves a version or turns the rule active.`,
54364
+ description: `${SAMPLES_FILE_SHAPE} They are added to the rule's saved ones, 20 at most in all. Sets add_expectation_samples, over any in --body-file or --raw-body. Not with --${SAMPLES_FILE_FLAG}. ${UPDATE_JUDGES_SAMPLES}`,
53321
54365
  exclusive: [SAMPLES_FILE_FLAG]
53322
54366
  }),
53323
54367
  [PICK_FLAG]: Flags.string({ description: pickFlagHelp([SAMPLES_FILE_FLAG, ADD_SAMPLES_FILE_FLAG]) }),
@@ -53363,7 +54407,9 @@ const EMAIL_RULE_OPERATION_EXTENSIONS = {
53363
54407
  bodyProperties: ["expectation_samples"]
53364
54408
  },
53365
54409
  compileEmailRule: {
53366
- flags: {},
54410
+ flags: scopeSelectionFlags(),
54411
+ bodyFields: scopeSelectionBodyFields,
54412
+ bodyProperties: ["scope_selection"],
53367
54413
  report: compileEmailRuleReport
53368
54414
  },
53369
54415
  endEmailRuleShare: {
@@ -55530,7 +56576,7 @@ function savedConnectedProfiles(configDir, exclude) {
55530
56576
  */
55531
56577
  async function otherProfiles(configDir, session, current) {
55532
56578
  if (session) try {
55533
- const { connectedProfilesForSession } = await import("./machine-session-DkXYR62a.js").then((n) => n.s);
56579
+ const { connectedProfilesForSession } = await import("./machine-session-BMr-zPLx.js").then((n) => n.s);
55534
56580
  return {
55535
56581
  inSession: true,
55536
56582
  profiles: connectedProfilesForSession(configDir, session, current)
@@ -55604,6 +56650,96 @@ async function explainPendingMailNotFound(configDir, emailId, write = (line) =>
55604
56650
  if (outcome.kind === "dropped") write(`Dropped the pending notice for ${id} from profile ${current.profile} after ${outcome.reads} consecutive not_found reads; the email is no longer visible to this profile.\n`);
55605
56651
  } catch {}
55606
56652
  }
56653
+ // src/oclif/rule-list-defaults.ts
56654
+ /** The box the objection list asks for when --box is not given: objections you made and objections to rules you wrote. */
56655
+ const OBJECTION_BOX_DEFAULT = "mine";
56656
+ /** The box asked for instead when a server refuses OBJECTION_BOX_DEFAULT: objections you made. */
56657
+ const OBJECTION_BOX_FALLBACK = "outgoing";
56658
+ /** --box on `email-rule-oversight list-email-rule-objections`, with the CLI's default. */
56659
+ const OBJECTION_BOX_FLAG = {
56660
+ description: "mine (the default): objections you made and objections to rules you wrote, each saying which (is_objector, is_author). outgoing: only those you made. incoming: only those to rules you wrote. all: every objection you can see. On a server that does not take mine, the CLI lists only those you made by default, and says so.",
56661
+ options: [
56662
+ OBJECTION_BOX_DEFAULT,
56663
+ "outgoing",
56664
+ "incoming",
56665
+ "all"
56666
+ ]
56667
+ };
56668
+ /**
56669
+ * The query to send: for the objection list read without --box, the CLI's
56670
+ * default box by name; any other query as it is.
56671
+ */
56672
+ function withDefaultObjectionBox(sdkName, query) {
56673
+ return sdkName === "listEmailRuleObjections" && query.box === void 0 ? {
56674
+ ...query,
56675
+ box: OBJECTION_BOX_DEFAULT
56676
+ } : query;
56677
+ }
56678
+ function errorBody(payload) {
56679
+ if (payload === null || typeof payload !== "object") return {};
56680
+ const inner = payload.error;
56681
+ return inner !== null && typeof inner === "object" ? inner : payload;
56682
+ }
56683
+ /**
56684
+ * True when an API error is a server that predates box=mine refusing the
56685
+ * value: a validation error whose issue for box is an unknown option, not
56686
+ * any other refusal that happens to name box.
56687
+ */
56688
+ function isObjectionBoxRefused(payload) {
56689
+ const body = errorBody(payload);
56690
+ return body.code === "validation_error" && typeof body.message === "string" && /(^|,\s*)box: Invalid (option|enum value)/.test(body.message);
56691
+ }
56692
+ /** The error line for `--box mine` given to a server that refuses it. */
56693
+ function objectionBoxErrorHint(payload, flags) {
56694
+ if (flags?.box !== "mine" || !isObjectionBoxRefused(payload)) return void 0;
56695
+ return "This server does not take --box mine: use --box outgoing for objections you made, and --box incoming for objections to rules you wrote.";
56696
+ }
56697
+ const widen = (flags) => `add \`${flags.join(" ")}\` to widen it`;
56698
+ /** The objection list's line: what its defaults left out, and how to see more. */
56699
+ function objectionsNote(box, status, refused) {
56700
+ if (box && refused) return `By default this server lists only ${status ? "pending objections you made" : "objections you made"}: add \`--box incoming\` for objections to rules you wrote, or \`${["--box all", ...status ? ["--status any"] : []].join(" ")}\` for every one you can see.`;
56701
+ const phrase = box && status ? "pending objections you made and those to rules you wrote" : box ? "objections you made and those to rules you wrote" : status ? "pending objections" : null;
56702
+ if (phrase === null) return void 0;
56703
+ return `By default this lists only ${phrase}: ${widen([...box ? ["--box all"] : [], ...status ? ["--status any"] : []])}.`;
56704
+ }
56705
+ /**
56706
+ * What a rule request, share or objection list read with `query` (the
56707
+ * flags as given) left out by its defaults, and the flags that show more.
56708
+ * Said on any page. Undefined for any other list, or when every default was
56709
+ * overridden.
56710
+ */
56711
+ function ruleListDefaultsNote(sdkName, query, options = {}) {
56712
+ const unset = (name) => query[name] === void 0;
56713
+ const said = (phrase, flags) => phrase === null ? void 0 : `By default this lists only ${phrase}: ${widen(flags)}.`;
56714
+ if (sdkName === "listEmailRuleRequests") {
56715
+ const box = unset("box");
56716
+ const status = unset("status");
56717
+ return said(box && status ? "pending requests made to you" : box ? "requests made to you" : status ? "pending requests" : null, [...box ? ["--box all"] : [], ...status ? ["--status any"] : []]);
56718
+ }
56719
+ if (sdkName === "listEmailRuleShares") {
56720
+ const box = unset("box");
56721
+ const live = unset("live");
56722
+ return said(box && live ? "live shares made with you" : box ? "shares made with you" : live ? "live shares" : null, [...box ? ["--box all"] : [], ...live ? ["--live any"] : []]);
56723
+ }
56724
+ if (sdkName === "listGivenEmailRuleShares") return said(unset("live") ? "live shares of your mail" : null, ["--live any"]);
56725
+ if (sdkName === "listEmailRuleObjections") return objectionsNote(unset("box"), unset("status"), options.objectionBoxRefused === true);
56726
+ }
56727
+ const NOUNS = {
56728
+ listEmailRuleRequests: "requests",
56729
+ listEmailRuleShares: "shares",
56730
+ listGivenEmailRuleShares: "shares",
56731
+ listEmailRuleObjections: "objections"
56732
+ };
56733
+ /**
56734
+ * An empty first page of one of those lists: that nothing matched, then the
56735
+ * line above. Undefined for any other list, when every default was
56736
+ * overridden, or on a later page (--cursor), where the line alone is said.
56737
+ */
56738
+ function emptyRuleListHint(sdkName, query, options = {}) {
56739
+ if (query.cursor !== void 0) return void 0;
56740
+ const note = ruleListDefaultsNote(sdkName, query, options);
56741
+ return note ? `(no results) No ${NOUNS[sdkName]} match. ${note}` : void 0;
56742
+ }
55607
56743
  const RULE_REQUEST_WEBHOOK_CREATE_HINT = "Hint: a webhook for rule request or objection events is made by the person it is for, signed in as themself: after `primitive login`, run this without --api-key, PRIMITIVE_API_KEY or PRIMITIVE_AGENT_PROFILE set, or create it in the dashboard. An API key, another app or an agent cannot make one. If you are already signed in as yourself, try again. It is a route target whatever your access, so it never takes a domain's or the organization's default slot.";
55608
56744
  const RULE_REQUEST_WEBHOOK_HTTP_HINT = "Hint: rule request and objection events go only to an http webhook (kind http).";
55609
56745
  const RULE_REQUEST_WEBHOOK_SUBSCRIBE_HINT = "Hint: rule request and objection events go only to a webhook made for them. If this webhook does not list them yet, it cannot be given them: create a new one with `--event-types` naming them (such as 'email_rule_request.*' or 'email_rule_objection.*'), signed in as yourself. If it does, only its maker, signed in as themself, can change it.";
@@ -56013,6 +57149,7 @@ const OPERATION_PATH_FLAGS = {
56013
57149
  flag: "email-id",
56014
57150
  description: "The id of the email (from `primitive emails list`), not a rule id: lists what every rule you can see decided about this email, and why a rule did not run. --id is accepted too."
56015
57151
  } },
57152
+ listEmailRuleObjections: { box: OBJECTION_BOX_FLAG },
56016
57153
  replyToEmail: { id: {
56017
57154
  flag: "email-id",
56018
57155
  description: EMAIL_ID_NOT_SENT
@@ -56205,7 +57342,7 @@ function flagForParameter(parameter, override) {
56205
57342
  });
56206
57343
  if (parameter.enum && parameter.enum.length > 0) return Flags.string({
56207
57344
  ...common,
56208
- options: parameter.enum
57345
+ options: [...override?.options ?? parameter.enum]
56209
57346
  });
56210
57347
  return Flags.string(common);
56211
57348
  }
@@ -56461,7 +57598,7 @@ function buildFlags(operation) {
56461
57598
  time: Flags.boolean({ description: TIME_FLAG_DESCRIPTION })
56462
57599
  };
56463
57600
  if (!operation.binaryResponse) {
56464
- flags.json = Flags.boolean({ description: "Print exactly one JSON document on stdout, on success and on failure, and nothing on stderr. Stdout keeps its usual shape: the data payload, or with --envelope the full response envelope (data plus meta, including meta.cursor, and empty-result hints in summary). The next-cursor line is not printed; use --envelope to page. A failure prints the error with exit_code. Without --json, the cursor and notices go to stderr." });
57601
+ flags.json = Flags.boolean({ description: "Print exactly one JSON document on stdout, on success and on failure, and nothing on stderr. Stdout keeps its usual shape: the data payload, or with --envelope the full response envelope (data plus meta, including meta.cursor, and, in summary, empty-result hints and what a list's default filters left out). The next-cursor line is not printed; use --envelope to page. A failure prints the error with exit_code. Without --json, the cursor and notices go to stderr." });
56465
57602
  flags.envelope = Flags.boolean({ description: "Print the full response envelope, including pagination metadata such as meta.cursor. Defaults to printing only the data payload for backward compatibility." });
56466
57603
  }
56467
57604
  const positional = positionalPathParameter(operation);
@@ -56640,6 +57777,7 @@ const OPERATION_ERROR_HINTS = {
56640
57777
  createEndpoint: (code, body, payload) => createEndpointRuleRequestHint(code, body, payload),
56641
57778
  updateEndpoint: (code, body, payload) => updateEndpointRuleRequestHint(code, body, payload),
56642
57779
  updateEmailRule: (code, body, payload, path, flags) => updateEmailRuleErrorHint(code, payload, path?.id, body, flags),
57780
+ listEmailRuleObjections: (_code, _body, payload, _path, flags) => objectionBoxErrorHint(payload, flags),
56643
57781
  verifyDomain: (code, _body, payload) => code === "dns_verification_failed" ? domainVerificationFailedHint(payload) : void 0,
56644
57782
  addDomain: (code, body) => {
56645
57783
  if (code === "mail_relay_unavailable") return MAIL_RELAY_UNAVAILABLE_MESSAGE;
@@ -56752,7 +57890,9 @@ function createOperationCommand(operation) {
56752
57890
  const replyStateSurface = replyStateSurfaceForOperation(operation.sdkName, query);
56753
57891
  const automatedSurface = automatedSurfaceForOperation(operation.sdkName, query);
56754
57892
  const fromVerified = fromVerifiedExpectation(operation.sdkName, query);
56755
- const callOperation = (stepUpToken, pageQuery = query) => {
57893
+ let sentQuery = withDefaultObjectionBox(operation.sdkName, query);
57894
+ let objectionBoxRefused = false;
57895
+ const callOperation = (stepUpToken, pageQuery = sentQuery) => {
56756
57896
  const sent = stepUpToken ? {
56757
57897
  ...headers,
56758
57898
  [STEP_UP_HEADER]: stepUpToken
@@ -56797,7 +57937,7 @@ function createOperationCommand(operation) {
56797
57937
  const rows = [];
56798
57938
  let sentCursor = query.cursor;
56799
57939
  let last = await callOperation(void 0, {
56800
- ...query,
57940
+ ...sentQuery,
56801
57941
  limit: Math.min(max, wanted)
56802
57942
  });
56803
57943
  const budget = Math.ceil(wanted / max) + 20;
@@ -56823,7 +57963,7 @@ function createOperationCommand(operation) {
56823
57963
  };
56824
57964
  sentCursor = cursor;
56825
57965
  last = await callOperation(void 0, {
56826
- ...query,
57966
+ ...sentQuery,
56827
57967
  cursor,
56828
57968
  limit: Math.min(max, wanted - rows.length)
56829
57969
  });
@@ -56834,13 +57974,22 @@ function createOperationCommand(operation) {
56834
57974
  const warning = typeof role === "string" ? roleReadsAllMailWarning(role, await readRoles(apiClient.client)) : null;
56835
57975
  if (warning) process.stderr.write(`${warning}\n`);
56836
57976
  }
56837
- const result = paged ? await callPaged() : takesStepUp(operation) ? await callWithApproval() : ATTACHMENT_WAIT_OPERATIONS.has(operation.sdkName) ? await withAttachmentWait(callOperation, {
57977
+ const send = async () => paged ? await callPaged() : takesStepUp(operation) ? await callWithApproval() : ATTACHMENT_WAIT_OPERATIONS.has(operation.sdkName) ? await withAttachmentWait(callOperation, {
56838
57978
  wait: parsedFlags.wait !== false,
56839
57979
  errorCode: (error) => extractErrorCode(extractErrorPayload(error)),
56840
57980
  onFirstWait: () => {
56841
57981
  process.stderr.write(`Attachment content is not ready yet; waiting up to ${ATTACHMENT_WAIT_MAX_MS / 1e3}s. Pass --no-wait to return immediately.\n`);
56842
57982
  }
56843
57983
  }) : await callOperation();
57984
+ let result = await send();
57985
+ if (result.error && sentQuery !== query && isObjectionBoxRefused(extractErrorPayload(result.error))) {
57986
+ sentQuery = {
57987
+ ...query,
57988
+ box: OBJECTION_BOX_FALLBACK
57989
+ };
57990
+ objectionBoxRefused = true;
57991
+ result = await send();
57992
+ }
56844
57993
  if (result.error) {
56845
57994
  const errorPayload = extractErrorPayload(result.error);
56846
57995
  const operationErrorHint = OPERATION_ERROR_HINTS[operation.sdkName]?.(extractErrorCode(errorPayload), body, errorPayload, collectValues(operation.pathParams, parsedFlags, operation.sdkName), parsedFlags);
@@ -56920,18 +58069,26 @@ function createOperationCommand(operation) {
56920
58069
  if (cursor && !jsonOutput) process.stderr.write(`next cursor: ${cursor}\n`);
56921
58070
  if (pagingNote && !jsonOutput) process.stderr.write(`${pagingNote}\n`);
56922
58071
  const summary = [];
58072
+ let ruleListHintSaid = false;
56923
58073
  if (Array.isArray(envelope?.data) && envelope.data.length === 0 && (!jsonOutput || withEnvelope) && (jsonOutput || !metaExplainsEmptyList(envelope?.meta))) {
56924
58074
  const tail = query.since !== void 0;
56925
58075
  const more = envelope?.meta?.cursor ?? null;
58076
+ const ruleListHint = emptyRuleListHint(operation.sdkName, query, { objectionBoxRefused });
58077
+ ruleListHintSaid = ruleListHint !== void 0;
56926
58078
  const hint = operation.sdkName === "listEmails" ? emptyEmailListHint({
56927
58079
  filterFlags: listFilters(query).map((name) => `--${parameterFlagName(operation.sdkName, name)}`),
56928
58080
  ...tail ? { pastFlag: "--since" } : query.cursor !== void 0 ? { pastFlag: "--cursor" } : {},
56929
58081
  nextCursor: tail ? null : more,
56930
58082
  caller: tail || more ? null : await readCallerMailFor(auth, apiClient.client)
56931
- }) : emptyRuleListHint(operation.sdkName, query) ?? emptyDeliveriesHint(operation.sdkName, query) ?? EMPTY_RESULT_HINTS[operation.sdkName];
58083
+ }) : ruleListHint ?? emptyDeliveriesHint(operation.sdkName, query) ?? EMPTY_RESULT_HINTS[operation.sdkName];
56932
58084
  if (hint && jsonOutput) summary.push(hint);
56933
58085
  else if (hint) process.stderr.write(`${hint}\n`);
56934
58086
  }
58087
+ if (Array.isArray(envelope?.data) && (!jsonOutput || withEnvelope)) {
58088
+ const note = ruleListHintSaid ? void 0 : ruleListDefaultsNote(operation.sdkName, query, { objectionBoxRefused });
58089
+ if (note && jsonOutput) summary.push(note);
58090
+ else if (note) process.stderr.write(`${note}\n`);
58091
+ }
56935
58092
  if (!jsonOutput) for (const line of metaNoteLines(envelope?.meta)) process.stderr.write(`${line}\n`);
56936
58093
  if (operation.sdkName === "listSentEmails") {
56937
58094
  const note = sentListOtherSendersNote(envelope?.data, auth.connectedAgent?.agentAddress);
@@ -57007,35 +58164,6 @@ const EMPTY_RESULT_HINTS = {
57007
58164
  listFunctions: "(no results) No Functions configured yet. Start with `primitive functions templates`, then `primitive functions init --template <template>` and `primitive functions deploy --name <name> --file <bundle>`."
57008
58165
  };
57009
58166
  /**
57010
- * An empty rule request, share or objection list, read by the filters the
57011
- * call left at their defaults: each list shows only part of what you can see
57012
- * by default (pending requests made to you; live shares made with you;
57013
- * pending objections you made), so an empty answer says which flags widen
57014
- * it. Undefined for any other list, when every filter was given, or on a
57015
- * later page (--cursor), which is empty only past the end.
57016
- */
57017
- function emptyRuleListHint(sdkName, query) {
57018
- if (query.cursor !== void 0) return void 0;
57019
- const unset = (name) => query[name] === void 0;
57020
- const said = (noun, phrase, flags) => phrase === null ? void 0 : `(no results) No ${noun} match. By default this lists only ${phrase}: add \`${flags.join(" ")}\` to widen it.`;
57021
- if (sdkName === "listEmailRuleRequests") {
57022
- const box = unset("box");
57023
- const status = unset("status");
57024
- return said("requests", box && status ? "pending requests made to you" : box ? "requests made to you" : status ? "pending requests" : null, [...box ? ["--box all"] : [], ...status ? ["--status any"] : []]);
57025
- }
57026
- if (sdkName === "listEmailRuleShares") {
57027
- const box = unset("box");
57028
- const live = unset("live");
57029
- return said("shares", box && live ? "live shares made with you" : box ? "shares made with you" : live ? "live shares" : null, [...box ? ["--box all"] : [], ...live ? ["--live any"] : []]);
57030
- }
57031
- if (sdkName === "listGivenEmailRuleShares") return said("shares", unset("live") ? "live shares of your mail" : null, ["--live any"]);
57032
- if (sdkName === "listEmailRuleObjections") {
57033
- const box = unset("box");
57034
- const status = unset("status");
57035
- return said("objections", box && status ? "pending objections you made" : box ? "objections you made" : status ? "pending objections" : null, [...box ? ["--box all"] : [], ...status ? ["--status any"] : []]);
57036
- }
57037
- }
57038
- /**
57039
58167
  * An empty delivery list narrowed by a filter (--endpoint-id, --status,
57040
58168
  * --event-type and the rest) names the filters given, in place of the general
57041
58169
  * hint, which reads as if nothing was ever delivered, and keeps its point that