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,12 +1,12 @@
1
- import { $ as readEmailInteraction, A as explainPendingMailNotFound, At as cliInvocation, Bt as formatAlreadySentNotice, C as promptLine$2, Ct as sendOutcomeExitCode, D as formatBrowserLoginInstructions, Dt as successfulSendOutcome, E as canOfferCopyHotkey, Et as serializeErrorPayload, F as latestOwnOutbound, Ft as loadSkillLine, G as clearConsumedPendingMail, Gt as classificationFactLines, H as wakeRecipientField, Ht as emptyEmailListHint, I as readThreadContext, It as currentMailSessionKey, J as readPendingMail, Jt as noFactsMessage, K as clearReadPendingMail, Kt as classificationOf, L as sentInThread, Lt as detectAgentRuntime, M as describeWake, N as displayAddress, Nt as generatedAgentName, O as listenForCopyHotkey, Ot as thrownErrorExitCode, P as formatMailWakeLine, Pt as identitySuggestions, Q as interactionNextActions, Qt as ConnectedAgentKeyRequiredError, R as serverMuted, Rt as detectRuntimeSession, S as approveThenRerunHint, St as sendIdentityFields, T as withApproval, Tt as sentHistoryWindowStart, U as wakeRelationship, Ut as mailReach, V as wakeReadCommand, Vt as withFlagSuggestion, W as claimPendingMail, Wt as readCallerMailFor, X as removePendingMail, Xt as ATTACHMENT_WAIT_MAX_MS, Y as recordPendingMail, Yt as ATTACHMENT_WAIT_FLAG_DESCRIPTION, Z as interactionHumanLine, Zt as withAttachmentWait, _ as takesStepUp, _n as setKnownCommands, _t as formatPriorRepliesWarning, a as createOperationCommand, an as selectedOrgFromEnv, at as SEND_OUTCOME_HELP, b as STEP_UP_HEADER$1, bt as priorRepliesThatWentOut, c as formatErrorPayload, cn as credentialsFromUserLogin, ct as buildFollowUpCommand, d as isGrantRefusal, dn as revokeUserLogin, dt as classifySendError, en as createAuthenticatedCliApiClient, et as replyExpectation, f as parameterFlagName, fn as roleKeyLabel, ft as deriveSendIdempotencyKey, g as surfaceUnauthorizedHint, gn as sanitizeForTerminal, gt as formatPriorRepliesCheckSkipped, h as runWithTiming, hn as routeWarningLines, ht as formatDeletedEarlierSendNotice, i as TIME_FLAG_DESCRIPTION, in as resolveCliApiRequestConfig, it as MAX_SEND_WAIT_TIMEOUT_MS, j as bareAddress, jt as connectNextSteps, k as openBrowser, l as hasControlCharacter$1, ln as fetchCliOrgs, lt as buildThrownSendFailureEnvelope, m as refusalDetails, mn as switchCurrentOrg, mt as followUpCommandPrefix, n as API_ERROR_CODES, nn as refreshStoredCliCredentials, o as extractErrorCode, on as CliOrgRefusedError, ot as apiResultHttpStatus, p as readTextFileFlag, pn as roleKeyText, pt as excludeSignalReplies, q as pendingMailPath, qt as isEmailId, r as OPERATION_PATH_FLAGS, rn as refuseOrgSelectionForProfile, rt as IDEMPOTENCY_KEY_FLAG_DESCRIPTION, s as extractErrorPayload, sn as RESTRICTED_ROLE_NOTE, st as assertValidIdempotencyKey, t as API_BASE_URL_FLAG_DESCRIPTION, tn as createCliApiClient, tt as replyInteractionWarning, u as headerFlagName, un as isBuiltInRoleKey, ut as checkPriorReplies, v as writeErrorWithHints, vn as operationManifest, vt as formatSendFailureSummary, w as terminalApprovalIo, wt as sendWaitClampNotice, x as STEP_UP_TOKEN_FLAG_DESCRIPTION, xt as reportSendCommandResult, y as BROWSER_FLAG_DESCRIPTION, yt as formatSendRecordFailureSummary, z as serverRelationship, zt as runtimeSessionVariableList } from "../api-command-CNCsVNk0.js";
2
- import { $ as parseWebhookEvent, $n as simulateRoute, $t as getRepeatingSend, A as lateMailReread, An as listWakeDispatches, At as deleteWakeSchedule, B as ensureSearchReportsReplyState, Bn as replyToEmail, Bt as getConversation, C as waitOutRetryAfter, Cn as listOrganizationPeople, Ct as createWakeAuthorization, D as encodeReceivedAtSearchCursor, Dn as listSentAttachmentArchiveMembers, Dt as deleteMemory, E as cursorFromAcceptedRows, En as listRoutes, F as AWAITING_VALUES, Ft as downloadSentAttachmentByFilename, G as queryUsesAwaiting, Gt as getFunctionRouting, H as formatRepliesCell, Hn as revokeCredential, Ht as getDefaultNetworkAgent, I as REPLY_STATE_UNSUPPORTED_CODE, It as getAccessMode, Jn as semanticSearch, Jt as getKey, Kn as searchEmails, Kt as getFunctionTestRunTrace, L as ReplyStateUnsupportedError, Ln as redeemCreditCode, Lt as getAccount, M as sinceFromFlags, Mn as pollCliLogin, Mt as downloadEmailAttachmentByFilename, N as sleep$3, Nn as pullWebhookEvent, O as fetchEmailSearchPage, On as listSentEmails, Ot as deleteRoute, P as AWAITING_FLAG_DESCRIPTION, Pt as downloadSentAttachmentArchiveMember, Qn as setMemory, Qt as getOwnGrant, R as assertAwaitingFilterRows, Rn as removeDefaultNetworkMember, Rt as getAgentContactPolicy, S as transientFailure, Sn as listMailboxAccess, St as createRoute, T as collectNewAcceptedEmails, Tn as listRoles, U as hasReplyState, Un as rotateKey, Ut as getEmail, V as formatAwaitingCell, Vn as resendAgentSignupVerification, Vt as getCreditBalance, W as isAwaitingRejectedError, Wn as runWakeSchedule, Wt as getFunction, Xn as setFunctionRoute, Xt as getOrgRoutingTopology, Yn as sendEmail, Yt as getMemory, Z as isEmailReceivedEvent, Zn as setFunctionSecret, Zt as getOutboundStatus, _ as describeApiFailure, _n as listEndpoints, _t as cliLogout, a as REPEAT_IDLE_MAX_MINUTES, an as leaveOrganization, ar as unsetFunctionRoute, at as assertAutomatedVerdict, b as retryTransient, bn as listGroups, bt as createFunction, cn as listAgentContacts, cr as updateKey, d as parseRepeatTick, dn as listDefaultNetworkAgents, dr as updateWakeAuthorization, dt as isAutomatedRejectedError, en as getSendFrom, er as startAgentClaim, et as parseFromHeader, f as preparePresenceAliveEmail, fn as listDefaultNetworkMembers, fr as updateWakeSchedule, ft as addDefaultNetworkMember, g as WaitDeadlineReached, gn as listEmails, gt as checkSendability, hn as listEmailRuleResults, hr as whoami, ht as checkDefaultNetworkContactAdmission, i as REPEAT_EVERY_MAX_MINUTES, ir as testFunction, it as AutomatedFilterUnsupportedError, j as quoteDslValue, jn as listWakeSchedules, jt as downloadEmailAttachmentArchiveMember, k as filtersFromFlags, kn as listWakeAuthorizations, kt as deleteWakeAuthorization, l as parseInteractionEnvelope, ln as listAgentNetworks, lr as updateRepeatingSend, m as repeatStopCommand, mn as listEmailAttachmentArchiveMembers, mr as verifyAgentSignup, mt as cancelSentEmailByIdempotencyKey, nn as getThread, nr as startCliLogin, nt as AUTOMATED_FLAG_DESCRIPTION, o as REPEAT_MAX_SENDS_MAX, on as listActivityObjects, or as updateDefaultNetworkMember, ot as automatedRejectedError, p as prepareSignalEmail, pn as listDomains, pr as verifyAgentClaim, pt as cancelSentEmail, qn as searchMemories, qt as getInboxStatus, rn as getWakeSchedule, rr as stopRepeatFromEmail, rt as AUTOMATED_VALUES, s as buildRepeatStopBody, sr as updateFunction, tn as getSentEmail, tr as startAgentSignup, tt as AUTOMATED_FILTER_UNSUPPORTED_CODE, u as parsePresenceEnvelope, ur as updateRoute, ut as hasAutomatedVerdict, vn as listFunctionLogs, vt as completeWebhookEvent, w as SINCE_VALUE_HELP, wn as listRepeatingSends, wt as createWakeSchedule, x as retryingOperation, xn as listKeys, xt as createKey, y as pauseForTransientFailure, yn as listFunctions, yt as createEndpoint, z as awaitingRejectedError, zn as reorderRoutes } from "../repeats-Dj_o6c-X-wjmw2Jbx.js";
3
- import { S as readBundledConnectSkill, _ as NotificationOutcomeUnknownError, a as NotificationRetryError, b as installedConnectSkillFile, c as readConversationStatusContent, d as SESSION_UUID$1, g as NativeSessionNotLoadedError, h as NativeSessionError, i as notificationReceiptPage, l as createListenHandler, m as NativeSessionDisconnectedError, n as notificationSenders, o as isRoutineNotificationContent, p as defaultSessionSocket, r as openSessionNotifications, s as notificationPartReader, t as notificationScope, u as readableDelivery, v as connectSkillTarget, x as installedVersion, y as installConnectSkill } from "../notify-session-WKFsaFt3.js";
1
+ import { $ as readEmailInteraction, A as explainPendingMailNotFound, At as cliInvocation, Bt as formatAlreadySentNotice, C as promptLine$2, Ct as sendOutcomeExitCode, D as formatBrowserLoginInstructions, Dt as successfulSendOutcome, E as canOfferCopyHotkey, Et as serializeErrorPayload, F as latestOwnOutbound, Ft as loadSkillLine, G as clearConsumedPendingMail, Gt as classificationFactLines, H as wakeRecipientField, Ht as emptyEmailListHint, I as readThreadContext, It as currentMailSessionKey, J as readPendingMail, Jt as noFactsMessage, K as clearReadPendingMail, Kt as classificationOf, L as sentInThread, Lt as detectAgentRuntime, M as describeWake, N as displayAddress, Nt as generatedAgentName, O as listenForCopyHotkey, Ot as thrownErrorExitCode, P as formatMailWakeLine, Pt as identitySuggestions, Q as interactionNextActions, Qt as ConnectedAgentKeyRequiredError, R as serverMuted, Rt as detectRuntimeSession, S as approveThenRerunHint, St as sendIdentityFields, T as withApproval, Tt as sentHistoryWindowStart, U as wakeRelationship, Ut as mailReach, V as wakeReadCommand, Vt as withFlagSuggestion, W as claimPendingMail, Wt as readCallerMailFor, X as removePendingMail, Xt as ATTACHMENT_WAIT_MAX_MS, Y as recordPendingMail, Yt as ATTACHMENT_WAIT_FLAG_DESCRIPTION, Z as interactionHumanLine, Zt as withAttachmentWait, _ as takesStepUp, _n as setKnownCommands, _t as formatPriorRepliesWarning, a as createOperationCommand, an as selectedOrgFromEnv, at as SEND_OUTCOME_HELP, b as STEP_UP_HEADER$1, bt as priorRepliesThatWentOut, c as formatErrorPayload, cn as credentialsFromUserLogin, ct as buildFollowUpCommand, d as isGrantRefusal, dn as revokeUserLogin, dt as classifySendError, en as createAuthenticatedCliApiClient, et as replyExpectation, f as parameterFlagName, fn as roleKeyLabel, ft as deriveSendIdempotencyKey, g as surfaceUnauthorizedHint, gn as sanitizeForTerminal, gt as formatPriorRepliesCheckSkipped, h as runWithTiming, hn as routeWarningLines, ht as formatDeletedEarlierSendNotice, i as TIME_FLAG_DESCRIPTION, in as resolveCliApiRequestConfig, it as MAX_SEND_WAIT_TIMEOUT_MS, j as bareAddress, jt as connectNextSteps, k as openBrowser, l as hasControlCharacter$1, ln as fetchCliOrgs, lt as buildThrownSendFailureEnvelope, m as refusalDetails, mn as switchCurrentOrg, mt as followUpCommandPrefix, n as API_ERROR_CODES, nn as refreshStoredCliCredentials, o as extractErrorCode, on as CliOrgRefusedError, ot as apiResultHttpStatus, p as readTextFileFlag, pn as roleKeyText, pt as excludeSignalReplies, q as pendingMailPath, qt as isEmailId, r as OPERATION_PATH_FLAGS, rn as refuseOrgSelectionForProfile, rt as IDEMPOTENCY_KEY_FLAG_DESCRIPTION, s as extractErrorPayload, sn as RESTRICTED_ROLE_NOTE, st as assertValidIdempotencyKey, t as API_BASE_URL_FLAG_DESCRIPTION, tn as createCliApiClient, tt as replyInteractionWarning, u as headerFlagName, un as isBuiltInRoleKey, ut as checkPriorReplies, v as writeErrorWithHints, vn as operationManifest, vt as formatSendFailureSummary, w as terminalApprovalIo, wt as sendWaitClampNotice, x as STEP_UP_TOKEN_FLAG_DESCRIPTION, xt as reportSendCommandResult, y as BROWSER_FLAG_DESCRIPTION, yt as formatSendRecordFailureSummary, z as serverRelationship, zt as runtimeSessionVariableList } from "../api-command-D5Tj9C-K.js";
2
+ import { $ as parseWebhookEvent, $n as simulateRoute, $t as getRepeatingSend, A as lateMailReread, An as listWakeDispatches, At as deleteWakeSchedule, B as ensureSearchReportsReplyState, Bn as replyToEmail, Bt as getConversation, C as waitOutRetryAfter, Cn as listOrganizationPeople, Ct as createWakeAuthorization, D as encodeReceivedAtSearchCursor, Dn as listSentAttachmentArchiveMembers, Dt as deleteMemory, E as cursorFromAcceptedRows, En as listRoutes, F as AWAITING_VALUES, Ft as downloadSentAttachmentByFilename, G as queryUsesAwaiting, Gt as getFunctionRouting, H as formatRepliesCell, Hn as revokeCredential, Ht as getDefaultNetworkAgent, I as REPLY_STATE_UNSUPPORTED_CODE, It as getAccessMode, Jn as semanticSearch, Jt as getKey, Kn as searchEmails, Kt as getFunctionTestRunTrace, L as ReplyStateUnsupportedError, Ln as redeemCreditCode, Lt as getAccount, M as sinceFromFlags, Mn as pollCliLogin, Mt as downloadEmailAttachmentByFilename, N as sleep$3, Nn as pullWebhookEvent, O as fetchEmailSearchPage, On as listSentEmails, Ot as deleteRoute, P as AWAITING_FLAG_DESCRIPTION, Pt as downloadSentAttachmentArchiveMember, Qn as setMemory, Qt as getOwnGrant, R as assertAwaitingFilterRows, Rn as removeDefaultNetworkMember, Rt as getAgentContactPolicy, S as transientFailure, Sn as listMailboxAccess, St as createRoute, T as collectNewAcceptedEmails, Tn as listRoles, U as hasReplyState, Un as rotateKey, Ut as getEmail, V as formatAwaitingCell, Vn as resendAgentSignupVerification, Vt as getCreditBalance, W as isAwaitingRejectedError, Wn as runWakeSchedule, Wt as getFunction, Xn as setFunctionRoute, Xt as getOrgRoutingTopology, Yn as sendEmail, Yt as getMemory, Z as isEmailReceivedEvent, Zn as setFunctionSecret, Zt as getOutboundStatus, _ as describeApiFailure, _n as listEndpoints, _t as cliLogout, a as REPEAT_IDLE_MAX_MINUTES, an as leaveOrganization, ar as unsetFunctionRoute, at as assertAutomatedVerdict, b as retryTransient, bn as listGroups, bt as createFunction, cn as listAgentContacts, cr as updateKey, d as parseRepeatTick, dn as listDefaultNetworkAgents, dr as updateWakeAuthorization, dt as isAutomatedRejectedError, en as getSendFrom, er as startAgentClaim, et as parseFromHeader, f as preparePresenceAliveEmail, fn as listDefaultNetworkMembers, fr as updateWakeSchedule, ft as addDefaultNetworkMember, g as WaitDeadlineReached, gn as listEmails, gt as checkSendability, hn as listEmailRuleResults, hr as whoami, ht as checkDefaultNetworkContactAdmission, i as REPEAT_EVERY_MAX_MINUTES, ir as testFunction, it as AutomatedFilterUnsupportedError, j as quoteDslValue, jn as listWakeSchedules, jt as downloadEmailAttachmentArchiveMember, k as filtersFromFlags, kn as listWakeAuthorizations, kt as deleteWakeAuthorization, l as parseInteractionEnvelope, ln as listAgentNetworks, lr as updateRepeatingSend, m as repeatStopCommand, mn as listEmailAttachmentArchiveMembers, mr as verifyAgentSignup, mt as cancelSentEmailByIdempotencyKey, nn as getThread, nr as startCliLogin, nt as AUTOMATED_FLAG_DESCRIPTION, o as REPEAT_MAX_SENDS_MAX, on as listActivityObjects, or as updateDefaultNetworkMember, ot as automatedRejectedError, p as prepareSignalEmail, pn as listDomains, pr as verifyAgentClaim, pt as cancelSentEmail, qn as searchMemories, qt as getInboxStatus, rn as getWakeSchedule, rr as stopRepeatFromEmail, rt as AUTOMATED_VALUES, s as buildRepeatStopBody, sr as updateFunction, tn as getSentEmail, tr as startAgentSignup, tt as AUTOMATED_FILTER_UNSUPPORTED_CODE, u as parsePresenceEnvelope, ur as updateRoute, ut as hasAutomatedVerdict, vn as listFunctionLogs, vt as completeWebhookEvent, w as SINCE_VALUE_HELP, wn as listRepeatingSends, wt as createWakeSchedule, x as retryingOperation, xn as listKeys, xt as createKey, y as pauseForTransientFailure, yn as listFunctions, yt as createEndpoint, z as awaitingRejectedError, zn as reorderRoutes } from "../repeats-Dj_o6c-X-ykfsraq6.js";
3
+ import { S as readBundledConnectSkill, _ as NotificationOutcomeUnknownError, a as NotificationRetryError, b as installedConnectSkillFile, c as readConversationStatusContent, d as SESSION_UUID$1, g as NativeSessionNotLoadedError, h as NativeSessionError, i as notificationReceiptPage, l as createListenHandler, m as NativeSessionDisconnectedError, n as notificationSenders, o as isRoutineNotificationContent, p as defaultSessionSocket, r as openSessionNotifications, s as notificationPartReader, t as notificationScope, u as readableDelivery, v as connectSkillTarget, x as installedVersion, y as installConnectSkill } from "../notify-session-cIUz_kxR.js";
4
4
  import { A as AGENT_ADDRESS_ENV, C as saveCliCredentials, D as loadActiveChatState, E as deleteChatState, F as agentProfilesDirectory, H as requireDefaultLoginProfile, M as AgentConnectionSetupError, N as agentProfileDirectory, O as loadChatConversationByLocalId, P as agentProfileName, R as loadConnectedAgentProfile, S as resolveCliAuth, T as chatStatePath, W as PrimitiveApiClient, _ as deleteCliCredentials, a as normalizeCliEnvironmentName, b as loadCliCredentials, c as resolveConfigEnvironment, g as credentialsPath, h as credentialsLockPath, i as loadCliConfig, j as AGENT_PROFILE_ENV, k as saveActiveChatState, l as saveCliConfig, m as cliAccessTokenExpiresAt, n as deleteCliConfig, o as redactCliEnvironment, p as acquireCliCredentialsLock, r as emptyCliConfig, s as removeCliEnvironment, u as upsertCliEnvironment, v as deleteCliCredentialsLock, w as saveSignupCredentials, y as detectPrimitiveKeyEnvMisname } from "../cli-config-Ms_0vNjq.js";
5
5
  import { C as resolveListenSubscription, S as normalizeListenOrigin, _ as acquireListenLock, a as mailLockBusy, c as mailTime, d as readMailJson, f as removeMailFile, g as ListenStateError, h as writeMailJson, i as mailId, l as privateMailDirectory, m as withMailLock, o as mailObject, u as privateMailPermissions, y as listenIdentity } from "../shared-mail-files-BAQSGxxz.js";
6
- import { $ as saveConnectionName, A as ContactPolicyReadRetryError, B as AddressNotesApiError, C as RECEIVER_MODES, Ct as upsertManagedBlock, D as registrationSummary, Dt as refreshOwnerMemberAddressPeriodically, E as failedSessionRegistration, Et as addSessionReceiver, F as canonicalContactSelector, G as contactAgentAddress, H as runAddressNotesRequest, I as AgentDisconnectError, J as agentInvitationHash, K as runContactRequest, L as claimOverRevokedSetup, M as NetworkAdmissionPendingError, N as createNotificationContactPolicy, O as registrationSummaryLine, Ot as withOwnerMemberAddress, P as evaluateContactPolicy, Q as refusalAfterReplacement, R as clearRevokedAddresses, S as runAgentConnect, St as readManagedFile, T as verificationReplySubmitted, Tt as readHookLauncherWarning, U as ContactsApiError, V as addressNoteTarget, W as contactAddress, X as readAgentInvitation, Y as connectAgent, Z as receiverStatusCommand, _ as enrollmentResumes, _t as samePath, a as endSession, at as boundSessionProfiles, b as invitationProfileName, bt as inspectManagedBlock, c as pendingSessionDisconnects, ct as describeSessionHookChange, d as registerSession, dt as ephemeralCliReason, et as savedReceiver, f as retryPendingDisconnects, ft as findOnPath, g as enrollAgent, gt as repairClaudeHooks, h as staleSessionAgents, ht as readClaudeSettings, i as connectedProfilesForSession, it as recordHookMailCheck, j as NETWORK_ADMISSION_PENDING_RETRY_MS, k as waitForRegistrations, l as psProcessInfo, lt as describeSessionHookItem, m as runDetached, mt as inspectClaudeHooks, n as OMP_MAIN, nt as releaseRegistrationsForProfile, o as headlessClaudeRun, ot as claudeConfigDir, p as revokeStaleSessionAgents, pt as hasMachineSessionHooks, q as agentConnectionStatus, r as agentConnectionState, rt as installClaudeWakeHook, st as currentCliLocation, t as HOOK_END_GRACE_MS, tt as MACHINE_RUNTIMES, u as readClaudeHookInput, ut as ensureHookLauncher, v as connectWarnings, vt as writeClaudeSettings, w as externalReceivingState, wt as writeManagedFile, x as pollCheckCommand, xt as jsonIndentation, y as defaultAgentProfileName, yt as MachineFileError, z as disconnectAgent } from "../machine-session-DkXYR62a.js";
7
- import { a as readBeforeDeadline, c as readPresenceProjection, i as readApiBeforeDeadline, n as isPlainChatReply, o as scopedChatSenderTrust, r as isScopedChatReply, s as presenceDisposition, t as isConnectedChatCredential } from "../scoped-chat-B1Fi6_qM.js";
6
+ import { $ as saveConnectionName, A as ContactPolicyReadRetryError, B as AddressNotesApiError, C as RECEIVER_MODES, Ct as upsertManagedBlock, D as registrationSummary, Dt as refreshOwnerMemberAddressPeriodically, E as failedSessionRegistration, Et as addSessionReceiver, F as canonicalContactSelector, G as contactAgentAddress, H as runAddressNotesRequest, I as AgentDisconnectError, J as agentInvitationHash, K as runContactRequest, L as claimOverRevokedSetup, M as NetworkAdmissionPendingError, N as createNotificationContactPolicy, O as registrationSummaryLine, Ot as withOwnerMemberAddress, P as evaluateContactPolicy, Q as refusalAfterReplacement, R as clearRevokedAddresses, S as runAgentConnect, St as readManagedFile, T as verificationReplySubmitted, Tt as readHookLauncherWarning, U as ContactsApiError, V as addressNoteTarget, W as contactAddress, X as readAgentInvitation, Y as connectAgent, Z as receiverStatusCommand, _ as enrollmentResumes, _t as samePath, a as endSession, at as boundSessionProfiles, b as invitationProfileName, bt as inspectManagedBlock, c as pendingSessionDisconnects, ct as describeSessionHookChange, d as registerSession, dt as ephemeralCliReason, et as savedReceiver, f as retryPendingDisconnects, ft as findOnPath, g as enrollAgent, gt as repairClaudeHooks, h as staleSessionAgents, ht as readClaudeSettings, i as connectedProfilesForSession, it as recordHookMailCheck, j as NETWORK_ADMISSION_PENDING_RETRY_MS, k as waitForRegistrations, l as psProcessInfo, lt as describeSessionHookItem, m as runDetached, mt as inspectClaudeHooks, n as OMP_MAIN, nt as releaseRegistrationsForProfile, o as headlessClaudeRun, ot as claudeConfigDir, p as revokeStaleSessionAgents, pt as hasMachineSessionHooks, q as agentConnectionStatus, r as agentConnectionState, rt as installClaudeWakeHook, st as currentCliLocation, t as HOOK_END_GRACE_MS, tt as MACHINE_RUNTIMES, u as readClaudeHookInput, ut as ensureHookLauncher, v as connectWarnings, vt as writeClaudeSettings, w as externalReceivingState, wt as writeManagedFile, x as pollCheckCommand, xt as jsonIndentation, y as defaultAgentProfileName, yt as MachineFileError, z as disconnectAgent } from "../machine-session-BMr-zPLx.js";
7
+ import { a as readBeforeDeadline, c as readPresenceProjection, i as readApiBeforeDeadline, n as isPlainChatReply, o as scopedChatSenderTrust, r as isScopedChatReply, s as presenceDisposition, t as isConnectedChatCredential } from "../scoped-chat-DVSsLSRw.js";
8
8
  import { autoSignalEligible, dispatchAutoRead, dispatchAutoWorking, haltAutoWorking, isSentSignal, readWorkingLease, restoreAutoWorking } from "./auto-signals.js";
9
- import { a as ensureSharedMailSubscription, c as isConnectedAgentKey, d as reserveSharedMailSubscription, f as followEmailConversation, g as EventReceiverError, h as EventConnection, i as sharedMailScope, l as createSharedMailWaiter, m as otherParticipants, n as reconcileChatSend, p as readConversationFollow, r as openSharedMailReceiver, s as AGENT_CONNECTION_REQUIRED_MESSAGE, t as sendSignal, u as openSharedMailStore } from "../signal-command-BdJVZXGl.js";
9
+ import { a as ensureSharedMailSubscription, c as isConnectedAgentKey, d as reserveSharedMailSubscription, f as followEmailConversation, g as EventReceiverError, h as EventConnection, i as sharedMailScope, l as createSharedMailWaiter, m as otherParticipants, n as reconcileChatSend, p as readConversationFollow, r as openSharedMailReceiver, s as AGENT_CONNECTION_REQUIRED_MESSAGE, t as sendSignal, u as openSharedMailStore } from "../signal-command-gpH2AhIi.js";
10
10
  import { a as thrownErrorBody, i as runStreamingJson, n as guardJsonOutputCommands, r as jsonOutputRequested, t as JSON_OUTPUT_FLAG } from "../json-output-ch756TXV.js";
11
11
  import { a as backgroundListenStatus, c as runBackgroundListen, d as stopBackgroundListen, f as verifyBackgroundListenTarget, o as backgroundListenToken, r as backgroundListenConfiguration, u as startBackgroundListen } from "../listen-background-DyBYca28.js";
12
12
  import { ORG_SELECTION_ENV } from "./global-org-flag.js";
@@ -2502,7 +2502,12 @@ const openapiDocument = {
2502
2502
  "name": "outbound_only",
2503
2503
  "in": "query",
2504
2504
  "schema": { "type": "boolean" },
2505
- "description": "When true, include only outbound DNS records. Verified domains default to outbound-only; pending claims default to all required records."
2505
+ "description": "When true, include only outbound DNS records. Cannot be combined with inbound_only=true. By default, include all records."
2506
+ }, {
2507
+ "name": "inbound_only",
2508
+ "in": "query",
2509
+ "schema": { "type": "boolean" },
2510
+ "description": "When true, include only inbound MX and ownership TXT records. Cannot be combined with outbound_only=true."
2506
2511
  }],
2507
2512
  "responses": {
2508
2513
  "200": {
@@ -21780,7 +21785,7 @@ const openapiDocument = {
21780
21785
  "description": "created (the default), asked or concerning.",
21781
21786
  "schema": {
21782
21787
  "default": "created",
21783
- "description": "created (the default): what you created. asked: what other members asked of you, open or answered: rule requests made to you, and objections to rules you wrote; kind may then name only email_rule_request and email_rule_objection. concerning: what other members did that concerns your own mail: a rule that started covering one of your mailboxes, or saved a new version while covering it (email_rule_coverage, the only kind it takes). asked and concerning are for a person's own view only.",
21788
+ "description": "created (the default): what you created. asked: what other members asked of you, open or answered: rule requests made to you, and objections to rules you wrote; kind may then name only email_rule_request and email_rule_objection. concerning: what other members did that concerns your own mail: an active rule that started covering one of your mailboxes, or saved a new version while covering it (email_rule_coverage, the only kind it takes). A rule in draft or observe is not told of; GET /v1/email-rules/covering-me lists it. asked and concerning are for a person's own view only.",
21784
21789
  "type": "string",
21785
21790
  "enum": [
21786
21791
  "created",
@@ -21997,7 +22002,7 @@ const openapiDocument = {
21997
22002
  "/email-rules/compile": { "post": {
21998
22003
  "operationId": "compileEmailRule",
21999
22004
  "summary": "Compile a rule description",
22000
- "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).",
22005
+ "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).",
22001
22006
  "tags": ["Email Rules"],
22002
22007
  "security": [{ "BearerAuth": [] }],
22003
22008
  "requestBody": {
@@ -22052,7 +22057,11 @@ const openapiDocument = {
22052
22057
  }
22053
22058
  },
22054
22059
  "403": {
22055
- "description": "feature_not_enabled: this organization lacks the email rules feature; permission refusals answer forbidden or grant_forbidden.",
22060
+ "description": "feature_not_enabled: this organization lacks the email rules feature; permission refusals answer forbidden or grant_forbidden. email_rule_scope_not_readable: scope_selection names something you cannot read.",
22061
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
22062
+ },
22063
+ "409": {
22064
+ "description": "email_rule_author_unresolvable: with evaluation_scope selected, you cannot act as a rule's author right now (details.reason left, revoked, suspended, membership_ended or no_mail_read).",
22056
22065
  "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
22057
22066
  },
22058
22067
  "422": {
@@ -22149,7 +22158,7 @@ const openapiDocument = {
22149
22158
  }
22150
22159
  },
22151
22160
  "403": {
22152
- "description": "feature_not_enabled: this organization lacks the email rules feature; permission refusals answer forbidden or grant_forbidden. grant_forbidden with details.reason mail_depth: your access to mail shows headers only, and a rule decides on what emails say. email_rule_scope_not_readable: scope_selection names something you cannot read.",
22161
+ "description": "feature_not_enabled: this organization lacks the email rules feature; permission refusals answer forbidden or grant_forbidden. grant_forbidden with details.reason mail_depth: your access to mail shows headers only, and a rule decides on what emails say. email_rule_scope_not_readable: scope_selection names something you cannot read. forbidden with details.reason covering_view_only: you read this rule only in the covering view, since it decided on your mail before and covers none of your mailboxes now (details.covering_view).",
22153
22162
  "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
22154
22163
  },
22155
22164
  "404": {
@@ -22246,15 +22255,15 @@ const openapiDocument = {
22246
22255
  }
22247
22256
  },
22248
22257
  "403": {
22249
- "description": "feature_not_enabled: this organization lacks the email rules feature; permission refusals answer forbidden or grant_forbidden. email_rule_scope_not_readable: scope_selection names something you cannot read.",
22258
+ "description": "feature_not_enabled: this organization lacks the email rules feature; permission refusals answer forbidden or grant_forbidden. email_rule_scope_not_readable: scope_selection names something you cannot read. forbidden with details.reason covering_view_only: you read this rule only in the covering view, since it decided on your mail before and covers none of your mailboxes now (details.covering_view).",
22250
22259
  "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
22251
22260
  },
22252
22261
  "404": {
22253
- "description": "not_found: rule_id names no rule you can see (details.reason rule_not_found), or request_id no rule request you can see (request_not_found).",
22262
+ "description": "not_found: rule_id names no rule you can see or that covers your mailboxes (details.reason rule_not_found), or request_id no rule request you can see (request_not_found).",
22254
22263
  "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
22255
22264
  },
22256
22265
  "409": {
22257
- "description": "email_rule_author_unresolvable: the rule cannot run as its author (for an unsaved tree or a request, you). email_rule_request_not_pending: request_id names a request already decided.",
22266
+ "description": "email_rule_author_unresolvable: the rule cannot run as its author (for an unsaved tree, a request or a rule covering you, you). email_rule_request_not_pending: request_id names a request already decided.",
22258
22267
  "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
22259
22268
  },
22260
22269
  "422": {
@@ -22305,7 +22314,7 @@ const openapiDocument = {
22305
22314
  "/email-rules/test-sample": { "post": {
22306
22315
  "operationId": "testEmailRuleOnSample",
22307
22316
  "summary": "Test a rule against a made-up email",
22308
- "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).",
22317
+ "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).",
22309
22318
  "tags": ["Email Rules"],
22310
22319
  "security": [{ "BearerAuth": [] }],
22311
22320
  "requestBody": {
@@ -22351,15 +22360,15 @@ const openapiDocument = {
22351
22360
  }
22352
22361
  },
22353
22362
  "403": {
22354
- "description": "feature_not_enabled: this organization lacks the email rules feature; permission refusals answer forbidden or grant_forbidden. email_rule_scope_not_readable: scope_selection names something you cannot read.",
22363
+ "description": "feature_not_enabled: this organization lacks the email rules feature; permission refusals answer forbidden or grant_forbidden. email_rule_scope_not_readable: scope_selection names something you cannot read. forbidden with details.reason covering_view_only: you read this rule only in the covering view, since it decided on your mail before and covers none of your mailboxes now (details.covering_view).",
22355
22364
  "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
22356
22365
  },
22357
22366
  "404": {
22358
- "description": "not_found: rule_id names no rule you can see (details.reason rule_not_found).",
22367
+ "description": "not_found: rule_id names no rule you can see or that covers your mailboxes (details.reason rule_not_found).",
22359
22368
  "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
22360
22369
  },
22361
22370
  "409": {
22362
- "description": "email_rule_author_unresolvable: the rule cannot run as its author (for an unsaved tree, you), so it would decide nothing for real. details.reason is left, revoked, suspended, membership_ended, no_mail_read, no_own_mailbox, no_shareable_mailbox or no_selected_mailbox.",
22371
+ "description": "email_rule_author_unresolvable: the rule cannot run as its author (for an unsaved tree or a rule covering you, you), so it would decide nothing for real. details.reason is left, revoked, suspended, membership_ended, no_mail_read, no_own_mailbox, no_shareable_mailbox or no_selected_mailbox.",
22363
22372
  "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
22364
22373
  },
22365
22374
  "429": {
@@ -22692,7 +22701,7 @@ const openapiDocument = {
22692
22701
  }
22693
22702
  },
22694
22703
  "403": {
22695
- "description": "feature_not_enabled: this organization lacks the email rules feature; permission refusals answer forbidden or grant_forbidden. forbidden with details.reason covering_view_only (your dashboard session or the Primitive CLI only): you may read this rule only because it covers your mailbox; details.covering_view is where (getEmailRuleCoveringMe).",
22704
+ "description": "feature_not_enabled: this organization lacks the email rules feature; permission refusals answer forbidden or grant_forbidden. forbidden with details.reason covering_view_only (your dashboard session or the Primitive CLI only): you may read this rule only because it covers your mailbox or decided on your mail; details.covering_view is where (getEmailRuleCoveringMe).",
22696
22705
  "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
22697
22706
  },
22698
22707
  "404": {
@@ -22837,7 +22846,7 @@ const openapiDocument = {
22837
22846
  "delete": {
22838
22847
  "operationId": "deleteEmailRule",
22839
22848
  "summary": "Delete a rule",
22840
- "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).",
22849
+ "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).",
22841
22850
  "tags": ["Email Rules"],
22842
22851
  "security": [{ "BearerAuth": [] }],
22843
22852
  "parameters": [{
@@ -23030,7 +23039,7 @@ const openapiDocument = {
23030
23039
  }
23031
23040
  },
23032
23041
  "403": {
23033
- "description": "feature_not_enabled: this organization lacks the email rules feature; permission refusals answer forbidden or grant_forbidden. grant_forbidden with details.reason mail_depth: your access to mail shows headers only, and what a rule decided is read from what emails say.",
23042
+ "description": "feature_not_enabled: this organization lacks the email rules feature; permission refusals answer forbidden or grant_forbidden. grant_forbidden with details.reason mail_depth: your access to mail shows headers only, and what a rule decided is read from what emails say. forbidden with details.reason covering_view_only (your dashboard session or the Primitive CLI only): you may read this rule only because it covers your mailbox or decided on your mail; details.covering_view is where (listEmailRuleDecisionsOnMyMail).",
23034
23043
  "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
23035
23044
  },
23036
23045
  "404": {
@@ -23200,7 +23209,7 @@ const openapiDocument = {
23200
23209
  "required": false,
23201
23210
  "description": "Read only these version numbers, comma-separated, at most 100. Not with limit or cursor.",
23202
23211
  "schema": {
23203
- "description": "Read only these version numbers, comma-separated. Without it, every version, newest first, a page at a time.",
23212
+ "description": "Read only these version numbers, comma-separated. Without it, the versions listed, newest first, a page at a time.",
23204
23213
  "type": "string",
23205
23214
  "pattern": "^[1-9]\\d{0,8}(,[1-9]\\d{0,8}){0,99}$"
23206
23215
  }
@@ -23260,7 +23269,7 @@ const openapiDocument = {
23260
23269
  }
23261
23270
  },
23262
23271
  "403": {
23263
- "description": "feature_not_enabled: this organization lacks the email rules feature; permission refusals answer forbidden or grant_forbidden.",
23272
+ "description": "feature_not_enabled: this organization lacks the email rules feature; permission refusals answer forbidden or grant_forbidden. forbidden with details.reason covering_view_only (your dashboard session or the Primitive CLI only): you may read this rule only because it covers your mailbox or decided on your mail; details.covering_view is where (listEmailRuleVersionsCoveringMe while it covers you).",
23264
23273
  "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
23265
23274
  },
23266
23275
  "404": {
@@ -25154,6 +25163,134 @@ const openapiDocument = {
25154
25163
  },
25155
25164
  "x-primitive-permission": ["mail:read"]
25156
25165
  } },
25166
+ "/email-rules/covering-me/{id}/versions": { "get": {
25167
+ "operationId": "listEmailRuleVersionsCoveringMe",
25168
+ "summary": "Read versions of a rule over your mail",
25169
+ "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.",
25170
+ "tags": ["Email Rule Oversight"],
25171
+ "security": [{ "BearerAuth": [] }],
25172
+ "parameters": [
25173
+ {
25174
+ "name": "id",
25175
+ "in": "path",
25176
+ "required": true,
25177
+ "description": "The rule id.",
25178
+ "schema": {
25179
+ "type": "string",
25180
+ "format": "uuid"
25181
+ }
25182
+ },
25183
+ {
25184
+ "name": "limit",
25185
+ "in": "query",
25186
+ "required": false,
25187
+ "description": "Versions per page when versions is not given: 1 to 100, default 50.",
25188
+ "schema": {
25189
+ "type": "integer",
25190
+ "minimum": 1,
25191
+ "maximum": 100
25192
+ }
25193
+ },
25194
+ {
25195
+ "name": "cursor",
25196
+ "in": "query",
25197
+ "required": false,
25198
+ "description": "meta.cursor from the preceding page. Omit for the first page. Not with versions.",
25199
+ "schema": {
25200
+ "type": "string",
25201
+ "maxLength": 200
25202
+ }
25203
+ },
25204
+ {
25205
+ "name": "versions",
25206
+ "in": "query",
25207
+ "required": false,
25208
+ "description": "Read only these version numbers, comma-separated, at most 100. Not with limit or cursor.",
25209
+ "schema": {
25210
+ "description": "Read only these version numbers, comma-separated. Without it, the versions listed, newest first, a page at a time.",
25211
+ "type": "string",
25212
+ "pattern": "^[1-9]\\d{0,8}(,[1-9]\\d{0,8}){0,99}$"
25213
+ }
25214
+ }
25215
+ ],
25216
+ "responses": {
25217
+ "200": {
25218
+ "description": "Read versions of a rule over your mail",
25219
+ "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
25220
+ "type": "object",
25221
+ "required": ["data"],
25222
+ "properties": {
25223
+ "data": { "$ref": "#/components/schemas/ListEmailRuleVersionsCoveringMeResult" },
25224
+ "meta": {
25225
+ "$ref": "#/components/schemas/CursorPageMeta",
25226
+ "description": "Absent when versions is given."
25227
+ }
25228
+ }
25229
+ }] } } },
25230
+ "headers": {
25231
+ "ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit" },
25232
+ "ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining" },
25233
+ "ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset" },
25234
+ "ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy" }
25235
+ }
25236
+ },
25237
+ "400": {
25238
+ "description": "validation_error: a cursor not returned in meta.cursor, or versions with limit or cursor.",
25239
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
25240
+ },
25241
+ "401": {
25242
+ "description": "Invalid or missing API key",
25243
+ "content": { "application/json": {
25244
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
25245
+ "example": {
25246
+ "success": false,
25247
+ "error": {
25248
+ "code": "unauthorized",
25249
+ "message": "Invalid or missing API key"
25250
+ }
25251
+ }
25252
+ } },
25253
+ "headers": {
25254
+ "ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit-unauthenticated" },
25255
+ "ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining-unauthenticated" },
25256
+ "ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset-unauthenticated" },
25257
+ "ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy-unauthenticated" }
25258
+ }
25259
+ },
25260
+ "403": {
25261
+ "description": "feature_not_enabled: this organization lacks the email rules feature; permission refusals answer forbidden or grant_forbidden; details.reason first_party_required means this credential is not your dashboard session or the Primitive CLI. forbidden with details.reason no_longer_covers: it decided on your mail before but covers none of your mailboxes now; details.covering_view (getEmailRuleCoveringMe) shows the version that last decided on your mail.",
25262
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
25263
+ },
25264
+ "404": {
25265
+ "description": "not_found: no rule with this id covers your mailboxes or decided on your mail.",
25266
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
25267
+ },
25268
+ "429": {
25269
+ "description": "Rate limit exceeded. The `ratelimit-*` headers describe the limiter that rejected this request, with its own limit and window, not the API budget that successful responses report. A limiter that reports only a wait sends `Retry-After` alone.",
25270
+ "headers": {
25271
+ "Retry-After": {
25272
+ "schema": { "type": "integer" },
25273
+ "description": "Seconds to wait before retrying"
25274
+ },
25275
+ "ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit-429" },
25276
+ "ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining-429" },
25277
+ "ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset" },
25278
+ "ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy-429" }
25279
+ },
25280
+ "content": { "application/json": {
25281
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
25282
+ "example": {
25283
+ "success": false,
25284
+ "error": {
25285
+ "code": "rate_limit_exceeded",
25286
+ "message": "Rate limit exceeded"
25287
+ }
25288
+ }
25289
+ } }
25290
+ }
25291
+ },
25292
+ "x-primitive-permission": ["mail:read"]
25293
+ } },
25157
25294
  "/email-rule-objections": {
25158
25295
  "post": {
25159
25296
  "operationId": "createEmailRuleObjection",
@@ -25259,7 +25396,7 @@ const openapiDocument = {
25259
25396
  "get": {
25260
25397
  "operationId": "listEmailRuleObjections",
25261
25398
  "summary": "List objections",
25262
- "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.",
25399
+ "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.",
25263
25400
  "tags": ["Email Rule Oversight"],
25264
25401
  "security": [{ "BearerAuth": [] }],
25265
25402
  "parameters": [
@@ -25267,12 +25404,13 @@ const openapiDocument = {
25267
25404
  "name": "box",
25268
25405
  "in": "query",
25269
25406
  "required": false,
25270
- "description": "outgoing (the default): objections you made. incoming: objections to rules you wrote. all: every objection you can see.",
25407
+ "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.",
25271
25408
  "schema": {
25272
- "default": "outgoing",
25273
- "description": "outgoing: objections you made; incoming: objections to rules you wrote; all: every objection you can see (owners and admins see the organization's).",
25409
+ "default": "mine",
25410
+ "description": "mine: objections you made and objections to rules you wrote (is_objector or is_author says which); outgoing: only those you made; incoming: only those to rules you wrote; each in your current membership. all: every objection you can see (owners and admins see the organization's).",
25274
25411
  "type": "string",
25275
25412
  "enum": [
25413
+ "mine",
25276
25414
  "outgoing",
25277
25415
  "incoming",
25278
25416
  "all"
@@ -26048,25 +26186,233 @@ const openapiDocument = {
26048
26186
  "ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy-unauthenticated" }
26049
26187
  }
26050
26188
  },
26051
- "402": {
26052
- "description": "plan_required: renaming the inbox needs the Power plan.",
26053
- "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
26054
- },
26189
+ "402": {
26190
+ "description": "plan_required: renaming the inbox needs the Power plan.",
26191
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
26192
+ },
26193
+ "403": {
26194
+ "description": "Authenticated caller lacks permission for the operation",
26195
+ "content": { "application/json": {
26196
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
26197
+ "example": {
26198
+ "success": false,
26199
+ "error": {
26200
+ "code": "forbidden",
26201
+ "message": "Insufficient permissions"
26202
+ }
26203
+ }
26204
+ } }
26205
+ },
26206
+ "409": {
26207
+ "description": "conflict: the name is already taken, or another change to the organization's inbox committed meanwhile (retry).",
26208
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
26209
+ },
26210
+ "429": {
26211
+ "description": "Rate limit exceeded. The `ratelimit-*` headers describe the limiter that rejected this request, with its own limit and window, not the API budget that successful responses report. A limiter that reports only a wait sends `Retry-After` alone.",
26212
+ "headers": {
26213
+ "Retry-After": {
26214
+ "schema": { "type": "integer" },
26215
+ "description": "Seconds to wait before retrying"
26216
+ },
26217
+ "ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit-429" },
26218
+ "ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining-429" },
26219
+ "ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset" },
26220
+ "ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy-429" }
26221
+ },
26222
+ "content": { "application/json": {
26223
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
26224
+ "example": {
26225
+ "success": false,
26226
+ "error": {
26227
+ "code": "rate_limit_exceeded",
26228
+ "message": "Rate limit exceeded"
26229
+ }
26230
+ }
26231
+ } }
26232
+ }
26233
+ },
26234
+ "x-primitive-permission": ["domains:manage"],
26235
+ "parameters": [{
26236
+ "name": "Idempotency-Key",
26237
+ "in": "header",
26238
+ "required": false,
26239
+ "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.",
26240
+ "schema": {
26241
+ "type": "string",
26242
+ "minLength": 1,
26243
+ "maxLength": 255
26244
+ }
26245
+ }]
26246
+ } },
26247
+ "/mail-imports/google/messages": { "post": {
26248
+ "operationId": "importGoogleMailMessage",
26249
+ "summary": "Import one historical Google Workspace message",
26250
+ "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.",
26251
+ "tags": ["Emails"],
26252
+ "security": [{ "BearerAuth": [] }],
26253
+ "requestBody": {
26254
+ "required": true,
26255
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ImportGoogleMailMessageRequest" } } }
26256
+ },
26257
+ "responses": {
26258
+ "200": {
26259
+ "description": "Import one historical Google Workspace message",
26260
+ "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
26261
+ "type": "object",
26262
+ "required": ["data"],
26263
+ "properties": { "data": { "$ref": "#/components/schemas/ImportGoogleMailMessageResult" } }
26264
+ }] } } },
26265
+ "headers": {
26266
+ "ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit" },
26267
+ "ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining" },
26268
+ "ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset" },
26269
+ "ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy" }
26270
+ }
26271
+ },
26272
+ "400": {
26273
+ "description": "Invalid request parameters",
26274
+ "content": { "application/json": {
26275
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
26276
+ "example": {
26277
+ "success": false,
26278
+ "error": {
26279
+ "code": "validation_error",
26280
+ "message": "Invalid domain format"
26281
+ }
26282
+ }
26283
+ } }
26284
+ },
26285
+ "401": {
26286
+ "description": "mail_import_provider_auth: reauthorize the provider.",
26287
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
26288
+ },
26289
+ "403": {
26290
+ "description": "feature_disabled: the organization lacks email_import; or mail_import_forbidden: identity or current access differs.",
26291
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
26292
+ },
26293
+ "409": {
26294
+ "description": "mail_import_cap_exceeded or mail_import_storage_limit: the fixed pilot budget is exhausted.",
26295
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
26296
+ },
26297
+ "422": {
26298
+ "description": "Mail import input, content, storage or publication fence could not be accepted.",
26299
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
26300
+ },
26301
+ "429": {
26302
+ "description": "Rate limit exceeded. The `ratelimit-*` headers describe the limiter that rejected this request, with its own limit and window, not the API budget that successful responses report. A limiter that reports only a wait sends `Retry-After` alone.",
26303
+ "headers": {
26304
+ "Retry-After": {
26305
+ "schema": { "type": "integer" },
26306
+ "description": "Seconds to wait before retrying"
26307
+ },
26308
+ "ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit-429" },
26309
+ "ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining-429" },
26310
+ "ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset" },
26311
+ "ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy-429" }
26312
+ },
26313
+ "content": { "application/json": {
26314
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
26315
+ "example": {
26316
+ "success": false,
26317
+ "error": {
26318
+ "code": "rate_limit_exceeded",
26319
+ "message": "Rate limit exceeded"
26320
+ }
26321
+ }
26322
+ } }
26323
+ },
26324
+ "502": {
26325
+ "description": "Provider acquisition failed or exceeded its deadline.",
26326
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
26327
+ },
26328
+ "503": {
26329
+ "description": "mail_import_disabled or mail_import_unavailable; retry the same ID after resolving the cause.",
26330
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
26331
+ }
26332
+ },
26333
+ "parameters": [{
26334
+ "in": "header",
26335
+ "name": "X-Primitive-Google-Access-Token",
26336
+ "required": true,
26337
+ "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.",
26338
+ "schema": {
26339
+ "type": "string",
26340
+ "minLength": 1,
26341
+ "maxLength": 8192,
26342
+ "writeOnly": true
26343
+ }
26344
+ }, {
26345
+ "name": "Idempotency-Key",
26346
+ "in": "header",
26347
+ "required": false,
26348
+ "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.",
26349
+ "schema": {
26350
+ "type": "string",
26351
+ "minLength": 1,
26352
+ "maxLength": 255
26353
+ }
26354
+ }],
26355
+ "x-primitive-permission": ["mail:read"]
26356
+ } },
26357
+ "/mail-imports/google/reconcile": { "post": {
26358
+ "operationId": "reconcileGoogleMailImport",
26359
+ "summary": "Reconcile scoped historical import attempts",
26360
+ "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.",
26361
+ "tags": ["Emails"],
26362
+ "security": [{ "BearerAuth": [] }],
26363
+ "requestBody": {
26364
+ "required": true,
26365
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReconcileGoogleMailImportRequest" } } }
26366
+ },
26367
+ "responses": {
26368
+ "200": {
26369
+ "description": "Reconcile scoped historical import attempts",
26370
+ "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
26371
+ "type": "object",
26372
+ "required": ["data"],
26373
+ "properties": { "data": { "$ref": "#/components/schemas/ReconcileGoogleMailImportResult" } }
26374
+ }] } } },
26375
+ "headers": {
26376
+ "ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit" },
26377
+ "ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining" },
26378
+ "ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset" },
26379
+ "ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy" }
26380
+ }
26381
+ },
26382
+ "400": {
26383
+ "description": "Invalid request parameters",
26384
+ "content": { "application/json": {
26385
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
26386
+ "example": {
26387
+ "success": false,
26388
+ "error": {
26389
+ "code": "validation_error",
26390
+ "message": "Invalid domain format"
26391
+ }
26392
+ }
26393
+ } }
26394
+ },
26395
+ "401": {
26396
+ "description": "Invalid or missing API key",
26397
+ "content": { "application/json": {
26398
+ "schema": { "$ref": "#/components/schemas/ErrorResponse" },
26399
+ "example": {
26400
+ "success": false,
26401
+ "error": {
26402
+ "code": "unauthorized",
26403
+ "message": "Invalid or missing API key"
26404
+ }
26405
+ }
26406
+ } },
26407
+ "headers": {
26408
+ "ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit-unauthenticated" },
26409
+ "ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining-unauthenticated" },
26410
+ "ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset-unauthenticated" },
26411
+ "ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy-unauthenticated" }
26412
+ }
26413
+ },
26055
26414
  "403": {
26056
- "description": "Authenticated caller lacks permission for the operation",
26057
- "content": { "application/json": {
26058
- "schema": { "$ref": "#/components/schemas/ErrorResponse" },
26059
- "example": {
26060
- "success": false,
26061
- "error": {
26062
- "code": "forbidden",
26063
- "message": "Insufficient permissions"
26064
- }
26065
- }
26066
- } }
26067
- },
26068
- "409": {
26069
- "description": "conflict: the name is already taken, or another change to the organization's inbox committed meanwhile (retry).",
26415
+ "description": "mail_import_forbidden: current owner access is required.",
26070
26416
  "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
26071
26417
  },
26072
26418
  "429": {
@@ -26091,9 +26437,13 @@ const openapiDocument = {
26091
26437
  }
26092
26438
  }
26093
26439
  } }
26440
+ },
26441
+ "503": {
26442
+ "description": "mail_import_disabled: no valid policy is configured; or mail_import_unavailable.",
26443
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
26094
26444
  }
26095
26445
  },
26096
- "x-primitive-permission": ["domains:manage"],
26446
+ "x-primitive-permission": ["mail:read"],
26097
26447
  "parameters": [{
26098
26448
  "name": "Idempotency-Key",
26099
26449
  "in": "header",
@@ -40425,6 +40775,22 @@ const openapiDocument = {
40425
40775
  "latest_message_mismatch",
40426
40776
  "latest_message_thread_unresolved",
40427
40777
  "load_test_recipient_not_allowed",
40778
+ "mail_import_cap_exceeded",
40779
+ "mail_import_content_mismatch",
40780
+ "mail_import_deadline",
40781
+ "mail_import_disabled",
40782
+ "mail_import_fenced",
40783
+ "mail_import_forbidden",
40784
+ "mail_import_invalid_input",
40785
+ "mail_import_invalid_provider_response",
40786
+ "mail_import_out_of_window",
40787
+ "mail_import_policy_mismatch",
40788
+ "mail_import_provider_auth",
40789
+ "mail_import_provider_unavailable",
40790
+ "mail_import_storage_failed",
40791
+ "mail_import_storage_limit",
40792
+ "mail_import_too_large",
40793
+ "mail_import_unavailable",
40428
40794
  "mail_relay_unavailable",
40429
40795
  "mail_routing_conflict",
40430
40796
  "mail_topic_edit_conflict",
@@ -43288,6 +43654,11 @@ const openapiDocument = {
43288
43654
  }
43289
43655
  }
43290
43656
  },
43657
+ "attachments": {
43658
+ "type": "array",
43659
+ "items": { "$ref": "#/components/schemas/EmailAttachment" },
43660
+ "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}`."
43661
+ },
43291
43662
  "imported": {
43292
43663
  "type": ["object", "null"],
43293
43664
  "description": "Historical acquisition; never sender or SMTP delivery proof. Null for live mail. Excluded from live tails and deltas.",
@@ -43346,6 +43717,7 @@ const openapiDocument = {
43346
43717
  "from_verified",
43347
43718
  "from_header_email",
43348
43719
  "from_name",
43720
+ "attachments",
43349
43721
  "imported",
43350
43722
  "snippet"
43351
43723
  ]
@@ -44167,6 +44539,33 @@ const openapiDocument = {
44167
44539
  }
44168
44540
  }
44169
44541
  },
44542
+ "unsubscribe": {
44543
+ "type": "object",
44544
+ "additionalProperties": false,
44545
+ "required": ["url"],
44546
+ "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.",
44547
+ "properties": {
44548
+ "url": {
44549
+ "type": "string",
44550
+ "minLength": 1,
44551
+ "maxLength": 700,
44552
+ "pattern": "^[Hh][Tt][Tt][Pp][Ss]://(?:[A-Za-z0-9\\-._~:/?#\\[\\]@!$&'()*+;=]|%[0-9A-Fa-f]{2})+$",
44553
+ "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."
44554
+ },
44555
+ "one_click": {
44556
+ "type": "boolean",
44557
+ "default": true,
44558
+ "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."
44559
+ },
44560
+ "mailto": {
44561
+ "type": "string",
44562
+ "minLength": 3,
44563
+ "maxLength": 254,
44564
+ "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])?)+$",
44565
+ "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."
44566
+ }
44567
+ }
44568
+ },
44170
44569
  "headers": {
44171
44570
  "type": "object",
44172
44571
  "maxProperties": 25,
@@ -45212,6 +45611,33 @@ const openapiDocument = {
45212
45611
  "type": "boolean",
45213
45612
  "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`."
45214
45613
  },
45614
+ "unsubscribe": {
45615
+ "type": "object",
45616
+ "additionalProperties": false,
45617
+ "required": ["url"],
45618
+ "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.",
45619
+ "properties": {
45620
+ "url": {
45621
+ "type": "string",
45622
+ "minLength": 1,
45623
+ "maxLength": 700,
45624
+ "pattern": "^[Hh][Tt][Tt][Pp][Ss]://(?:[A-Za-z0-9\\-._~:/?#\\[\\]@!$&'()*+;=]|%[0-9A-Fa-f]{2})+$",
45625
+ "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."
45626
+ },
45627
+ "one_click": {
45628
+ "type": "boolean",
45629
+ "default": true,
45630
+ "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."
45631
+ },
45632
+ "mailto": {
45633
+ "type": "string",
45634
+ "minLength": 3,
45635
+ "maxLength": 254,
45636
+ "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])?)+$",
45637
+ "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."
45638
+ }
45639
+ }
45640
+ },
45215
45641
  "headers": {
45216
45642
  "type": "object",
45217
45643
  "maxProperties": 25,
@@ -50331,7 +50757,7 @@ const openapiDocument = {
50331
50757
  },
50332
50758
  "state": {
50333
50759
  "type": "string",
50334
- "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."
50760
+ "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."
50335
50761
  },
50336
50762
  "created_at": {
50337
50763
  "type": "string",
@@ -50340,7 +50766,7 @@ const openapiDocument = {
50340
50766
  "ended_at": {
50341
50767
  "type": ["string", "null"],
50342
50768
  "format": "date-time",
50343
- "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."
50769
+ "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."
50344
50770
  },
50345
50771
  "owned_now": {
50346
50772
  "type": "string",
@@ -50368,6 +50794,11 @@ const openapiDocument = {
50368
50794
  "id",
50369
50795
  "name"
50370
50796
  ]
50797
+ },
50798
+ "rule_id": {
50799
+ "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.",
50800
+ "type": "string",
50801
+ "format": "uuid"
50371
50802
  }
50372
50803
  },
50373
50804
  "required": [
@@ -50618,7 +51049,7 @@ const openapiDocument = {
50618
51049
  "checked": {
50619
51050
  "type": "integer",
50620
51051
  "minimum": 0,
50621
- "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."
51052
+ "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."
50622
51053
  },
50623
51054
  "matched": {
50624
51055
  "type": "integer",
@@ -50628,6 +51059,33 @@ const openapiDocument = {
50628
51059
  },
50629
51060
  "required": ["checked", "matched"]
50630
51061
  },
51062
+ "EmailRuleScopeSelection": {
51063
+ "type": "object",
51064
+ "properties": {
51065
+ "addresses": {
51066
+ "maxItems": 100,
51067
+ "type": "array",
51068
+ "items": {
51069
+ "type": "string",
51070
+ "minLength": 3,
51071
+ "maxLength": 320,
51072
+ "pattern": "^[^\\s@]+@[^\\s@]+$"
51073
+ }
51074
+ },
51075
+ "domains": {
51076
+ "maxItems": 50,
51077
+ "type": "array",
51078
+ "items": {
51079
+ "type": "string",
51080
+ "minLength": 1,
51081
+ "maxLength": 253,
51082
+ "pattern": "^[^\\s@]+\\.[^\\s@]+$"
51083
+ }
51084
+ }
51085
+ },
51086
+ "additionalProperties": false,
51087
+ "description": "For a selected rule: inboxes, and domains (each address at them the author reads); each one you can read."
51088
+ },
50631
51089
  "CompileEmailRuleRequest": {
50632
51090
  "type": "object",
50633
51091
  "properties": {
@@ -50645,7 +51103,17 @@ const openapiDocument = {
50645
51103
  "include_sql": {
50646
51104
  "description": "Also return the SQL the rule renders to. Off by default.",
50647
51105
  "type": "boolean"
50648
- }
51106
+ },
51107
+ "evaluation_scope": {
51108
+ "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.",
51109
+ "type": "string",
51110
+ "enum": [
51111
+ "author",
51112
+ "own_mailboxes",
51113
+ "selected"
51114
+ ]
51115
+ },
51116
+ "scope_selection": { "$ref": "#/components/schemas/EmailRuleScopeSelection" }
50649
51117
  },
50650
51118
  "required": ["english"],
50651
51119
  "additionalProperties": false
@@ -50678,7 +51146,7 @@ const openapiDocument = {
50678
51146
  "enum": ["grant", "do_not_share"]
50679
51147
  },
50680
51148
  "breadth": {
50681
- "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.",
51149
+ "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.",
50682
51150
  "anyOf": [{ "$ref": "#/components/schemas/EmailRuleBreadth" }, { "type": "null" }]
50683
51151
  },
50684
51152
  "conditions_breadth": {
@@ -50855,33 +51323,6 @@ const openapiDocument = {
50855
51323
  ],
50856
51324
  "additionalProperties": false
50857
51325
  },
50858
- "EmailRuleScopeSelection": {
50859
- "type": "object",
50860
- "properties": {
50861
- "addresses": {
50862
- "maxItems": 100,
50863
- "type": "array",
50864
- "items": {
50865
- "type": "string",
50866
- "minLength": 3,
50867
- "maxLength": 320,
50868
- "pattern": "^[^\\s@]+@[^\\s@]+$"
50869
- }
50870
- },
50871
- "domains": {
50872
- "maxItems": 50,
50873
- "type": "array",
50874
- "items": {
50875
- "type": "string",
50876
- "minLength": 1,
50877
- "maxLength": 253,
50878
- "pattern": "^[^\\s@]+\\.[^\\s@]+$"
50879
- }
50880
- }
50881
- },
50882
- "additionalProperties": false,
50883
- "description": "For a selected rule: inboxes, and domains (each address at them the author reads); each one you can read."
50884
- },
50885
51326
  "EmailRuleExpectationSampleInput": {
50886
51327
  "type": "object",
50887
51328
  "properties": {
@@ -50968,6 +51409,16 @@ const openapiDocument = {
50968
51409
  "pattern": "^[^\\u0000]*$"
50969
51410
  }
50970
51411
  },
51412
+ "attachment_names": {
51413
+ "maxItems": 10,
51414
+ "type": "array",
51415
+ "items": {
51416
+ "type": "string",
51417
+ "minLength": 1,
51418
+ "maxLength": 255,
51419
+ "pattern": "^[^\\u0000-\\u001f\\u007f]*$"
51420
+ }
51421
+ },
50971
51422
  "automated": { "type": "boolean" },
50972
51423
  "from_mailing_list": { "type": "boolean" },
50973
51424
  "spam_score": {
@@ -51306,6 +51757,11 @@ const openapiDocument = {
51306
51757
  "minimum": 0,
51307
51758
  "description": "Emails decided on their conditions: matched, near_miss and no_match, less any missing a fact the rule reads."
51308
51759
  },
51760
+ "conditions_held": {
51761
+ "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.",
51762
+ "type": "integer",
51763
+ "minimum": 0
51764
+ },
51309
51765
  "conditions": {
51310
51766
  "type": "array",
51311
51767
  "items": {
@@ -51373,7 +51829,7 @@ const openapiDocument = {
51373
51829
  "warnings": {
51374
51830
  "type": "array",
51375
51831
  "items": { "type": "string" },
51376
- "description": "What to look at first, such as what stopped every email when nothing matched."
51832
+ "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."
51377
51833
  }
51378
51834
  },
51379
51835
  "required": [
@@ -51529,6 +51985,10 @@ const openapiDocument = {
51529
51985
  "type": "array",
51530
51986
  "items": { "type": "string" }
51531
51987
  },
51988
+ "attachment_names": {
51989
+ "type": "array",
51990
+ "items": { "type": "string" }
51991
+ },
51532
51992
  "automated": { "type": "boolean" },
51533
51993
  "from_mailing_list": { "type": "boolean" }
51534
51994
  },
@@ -51539,6 +51999,7 @@ const openapiDocument = {
51539
51999
  "subject",
51540
52000
  "text",
51541
52001
  "attachment_types",
52002
+ "attachment_names",
51542
52003
  "automated",
51543
52004
  "from_mailing_list"
51544
52005
  ],
@@ -51614,7 +52075,7 @@ const openapiDocument = {
51614
52075
  },
51615
52076
  "scope_selection": { "$ref": "#/components/schemas/EmailRuleScopeSelection" },
51616
52077
  "rule_id": {
51617
- "description": "A saved rule you can see: its current version and words.",
52078
+ "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.",
51618
52079
  "type": "string",
51619
52080
  "format": "uuid"
51620
52081
  },
@@ -51726,7 +52187,7 @@ const openapiDocument = {
51726
52187
  },
51727
52188
  "scope_selection": { "$ref": "#/components/schemas/EmailRuleScopeSelection" },
51728
52189
  "rule_id": {
51729
- "description": "A saved rule you can see. Its current version is tested.",
52190
+ "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.",
51730
52191
  "type": "string",
51731
52192
  "format": "uuid"
51732
52193
  },
@@ -51797,6 +52258,17 @@ const openapiDocument = {
51797
52258
  "maxLength": 255
51798
52259
  }
51799
52260
  },
52261
+ "attachment_names": {
52262
+ "description": "File names of those attachments, which the classifier and the questions read. With attachment_types, the same number, paired in order.",
52263
+ "maxItems": 20,
52264
+ "type": "array",
52265
+ "items": {
52266
+ "type": "string",
52267
+ "minLength": 1,
52268
+ "maxLength": 255,
52269
+ "pattern": "^[^\\u0000-\\u001f\\u007f]*$"
52270
+ }
52271
+ },
51800
52272
  "automated": {
51801
52273
  "description": "Whether the email was sent automatically, as its headers would show. Defaults to false.",
51802
52274
  "type": "boolean"
@@ -52019,6 +52491,15 @@ const openapiDocument = {
52019
52491
  "type": "boolean",
52020
52492
  "description": "Whether you are its author, in your current membership. Only its author edits it."
52021
52493
  },
52494
+ "pending_objections": {
52495
+ "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.",
52496
+ "type": "integer",
52497
+ "minimum": 0
52498
+ },
52499
+ "objection_notice": {
52500
+ "description": "With pending_objections above 0: that members asked you to turn it off, and how to answer.",
52501
+ "type": "string"
52502
+ },
52022
52503
  "created_at": {
52023
52504
  "type": "string",
52024
52505
  "format": "date-time"
@@ -52036,6 +52517,27 @@ const openapiDocument = {
52036
52517
  "type": "array",
52037
52518
  "items": { "$ref": "#/components/schemas/EmailRuleScopeWarning" }
52038
52519
  },
52520
+ "expectations": {
52521
+ "description": "Its saved expectations, each list by email id, as stored: on every create, and on an update that set or removed them.",
52522
+ "type": "object",
52523
+ "properties": {
52524
+ "match": {
52525
+ "type": "array",
52526
+ "items": {
52527
+ "type": "string",
52528
+ "format": "uuid"
52529
+ }
52530
+ },
52531
+ "no_match": {
52532
+ "type": "array",
52533
+ "items": {
52534
+ "type": "string",
52535
+ "format": "uuid"
52536
+ }
52537
+ }
52538
+ },
52539
+ "required": ["match", "no_match"]
52540
+ },
52039
52541
  "expectation_samples": {
52040
52542
  "description": "Its saved made-up emails, when this write set or added some.",
52041
52543
  "type": "array",
@@ -52137,6 +52639,10 @@ const openapiDocument = {
52137
52639
  "notice": {
52138
52640
  "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.",
52139
52641
  "type": "string"
52642
+ },
52643
+ "share_notice": {
52644
+ "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.",
52645
+ "type": "string"
52140
52646
  }
52141
52647
  },
52142
52648
  "required": [
@@ -52359,7 +52865,7 @@ const openapiDocument = {
52359
52865
  }
52360
52866
  },
52361
52867
  "warnings": {
52362
- "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).",
52868
+ "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).",
52363
52869
  "maxItems": 10,
52364
52870
  "type": "array",
52365
52871
  "items": {
@@ -52450,6 +52956,15 @@ const openapiDocument = {
52450
52956
  "type": "boolean",
52451
52957
  "description": "Whether you are its author, in your current membership. Only its author edits it."
52452
52958
  },
52959
+ "pending_objections": {
52960
+ "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.",
52961
+ "type": "integer",
52962
+ "minimum": 0
52963
+ },
52964
+ "objection_notice": {
52965
+ "description": "With pending_objections above 0: that members asked you to turn it off, and how to answer.",
52966
+ "type": "string"
52967
+ },
52453
52968
  "created_at": {
52454
52969
  "type": "string",
52455
52970
  "format": "date-time"
@@ -52548,6 +53063,15 @@ const openapiDocument = {
52548
53063
  "type": "boolean",
52549
53064
  "description": "Whether you are its author, in your current membership. Only its author edits it."
52550
53065
  },
53066
+ "pending_objections": {
53067
+ "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.",
53068
+ "type": "integer",
53069
+ "minimum": 0
53070
+ },
53071
+ "objection_notice": {
53072
+ "description": "With pending_objections above 0: that members asked you to turn it off, and how to answer.",
53073
+ "type": "string"
53074
+ },
52551
53075
  "created_at": {
52552
53076
  "type": "string",
52553
53077
  "format": "date-time"
@@ -52645,7 +53169,7 @@ const openapiDocument = {
52645
53169
  }
52646
53170
  },
52647
53171
  "warnings": {
52648
- "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).",
53172
+ "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).",
52649
53173
  "maxItems": 10,
52650
53174
  "type": "array",
52651
53175
  "items": {
@@ -52779,6 +53303,10 @@ const openapiDocument = {
52779
53303
  "other_keys": {
52780
53304
  "description": "How many more keys, not revoked, list the rule that you may not read. They are not named.",
52781
53305
  "type": "integer"
53306
+ },
53307
+ "share_notice": {
53308
+ "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.",
53309
+ "type": "string"
52782
53310
  }
52783
53311
  },
52784
53312
  "required": ["deleted"]
@@ -52953,6 +53481,11 @@ const openapiDocument = {
52953
53481
  "count": {
52954
53482
  "type": "integer",
52955
53483
  "exclusiveMinimum": 0
53484
+ },
53485
+ "reads_in_full": {
53486
+ "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.",
53487
+ "type": "integer",
53488
+ "minimum": 0
52956
53489
  }
52957
53490
  },
52958
53491
  "required": ["owner", "count"]
@@ -53000,7 +53533,7 @@ const openapiDocument = {
53000
53533
  "exclusiveMinimum": 0
53001
53534
  },
53002
53535
  "hosts": {
53003
- "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.",
53536
+ "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.",
53004
53537
  "type": "array",
53005
53538
  "items": { "type": "string" }
53006
53539
  },
@@ -53057,7 +53590,7 @@ const openapiDocument = {
53057
53590
  "webhooks",
53058
53591
  "shares"
53059
53592
  ],
53060
- "description": "Who receives what the rule shares now, by person and count; empty unless it is an active grant rule."
53593
+ "description": "Who receives what the rule shares, by person and count. As receivers, empty unless it is an active grant rule."
53061
53594
  },
53062
53595
  "ListEmailRuleResultsResult": {
53063
53596
  "type": "object",
@@ -53519,7 +54052,7 @@ const openapiDocument = {
53519
54052
  }
53520
54053
  },
53521
54054
  "warnings": {
53522
- "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).",
54055
+ "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).",
53523
54056
  "maxItems": 10,
53524
54057
  "type": "array",
53525
54058
  "items": {
@@ -53921,6 +54454,15 @@ const openapiDocument = {
53921
54454
  "type": "boolean",
53922
54455
  "description": "Whether you are its author, in your current membership. Only its author edits it."
53923
54456
  },
54457
+ "pending_objections": {
54458
+ "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.",
54459
+ "type": "integer",
54460
+ "minimum": 0
54461
+ },
54462
+ "objection_notice": {
54463
+ "description": "With pending_objections above 0: that members asked you to turn it off, and how to answer.",
54464
+ "type": "string"
54465
+ },
53924
54466
  "created_at": {
53925
54467
  "type": "string",
53926
54468
  "format": "date-time"
@@ -54141,7 +54683,7 @@ const openapiDocument = {
54141
54683
  }
54142
54684
  },
54143
54685
  "warnings": {
54144
- "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).",
54686
+ "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).",
54145
54687
  "maxItems": 10,
54146
54688
  "type": "array",
54147
54689
  "items": {
@@ -54186,7 +54728,7 @@ const openapiDocument = {
54186
54728
  "rule": { "$ref": "#/components/schemas/EmailRuleWithVersion" },
54187
54729
  "share": { "$ref": "#/components/schemas/EmailRuleShare" },
54188
54730
  "notice": {
54189
- "description": "What is now shared, in words.",
54731
+ "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.",
54190
54732
  "type": "string"
54191
54733
  }
54192
54734
  },
@@ -54551,7 +55093,11 @@ const openapiDocument = {
54551
55093
  "exclusiveMinimum": 0
54552
55094
  },
54553
55095
  "receivers": {
54554
- "description": "Null when it could not be read in time; try again.",
55096
+ "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.",
55097
+ "anyOf": [{ "$ref": "#/components/schemas/EmailRuleReceivers" }, { "type": "null" }]
55098
+ },
55099
+ "receivers_once_active": {
55100
+ "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.",
54555
55101
  "anyOf": [{ "$ref": "#/components/schemas/EmailRuleReceivers" }, { "type": "null" }]
54556
55102
  },
54557
55103
  "created_at": {
@@ -54569,6 +55115,7 @@ const openapiDocument = {
54569
55115
  "covers",
54570
55116
  "current_version",
54571
55117
  "receivers",
55118
+ "receivers_once_active",
54572
55119
  "created_at"
54573
55120
  ]
54574
55121
  },
@@ -54639,7 +55186,11 @@ const openapiDocument = {
54639
55186
  "description": "Null when covers_now is false."
54640
55187
  },
54641
55188
  "receivers": {
54642
- "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.",
55189
+ "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.",
55190
+ "anyOf": [{ "$ref": "#/components/schemas/EmailRuleReceivers" }, { "type": "null" }]
55191
+ },
55192
+ "receivers_once_active": {
55193
+ "description": "As on the list; also null when covers_now is false.",
54643
55194
  "anyOf": [{ "$ref": "#/components/schemas/EmailRuleReceivers" }, { "type": "null" }]
54644
55195
  },
54645
55196
  "created_at": {
@@ -54669,6 +55220,7 @@ const openapiDocument = {
54669
55220
  "covers",
54670
55221
  "current_version",
54671
55222
  "receivers",
55223
+ "receivers_once_active",
54672
55224
  "created_at",
54673
55225
  "covers_now",
54674
55226
  "current"
@@ -54786,6 +55338,10 @@ const openapiDocument = {
54786
55338
  "type": "array",
54787
55339
  "items": { "$ref": "#/components/schemas/EmailRuleDecisionOnMyMail" }
54788
55340
  },
55341
+ "ListEmailRuleVersionsCoveringMeResult": {
55342
+ "type": "array",
55343
+ "items": { "$ref": "#/components/schemas/EmailRuleCoveringMeVersion" }
55344
+ },
54789
55345
  "EmailRuleObjection": {
54790
55346
  "type": "object",
54791
55347
  "properties": {
@@ -54826,8 +55382,14 @@ const openapiDocument = {
54826
55382
  "description": "Who wrote the rule.",
54827
55383
  "$ref": "#/components/schemas/EmailRuleObjectionPerson"
54828
55384
  },
54829
- "is_objector": { "type": "boolean" },
54830
- "is_author": { "type": "boolean" },
55385
+ "is_objector": {
55386
+ "type": "boolean",
55387
+ "description": "Whether you made it, in your current membership."
55388
+ },
55389
+ "is_author": {
55390
+ "type": "boolean",
55391
+ "description": "Whether it is to a rule you wrote, in your current membership."
55392
+ },
54831
55393
  "message": {
54832
55394
  "description": "Why the objector objects; null when none was given, or once withdrawn.",
54833
55395
  "type": ["string", "null"]
@@ -55045,6 +55607,82 @@ const openapiDocument = {
55045
55607
  "outbound_ready"
55046
55608
  ]
55047
55609
  },
55610
+ "ImportGoogleMailMessageRequest": {
55611
+ "type": "object",
55612
+ "properties": { "message_id": {
55613
+ "type": "string",
55614
+ "pattern": "^[A-Za-z0-9_-]{1,128}$"
55615
+ } },
55616
+ "required": ["message_id"],
55617
+ "additionalProperties": false
55618
+ },
55619
+ "ImportGoogleMailMessageResult": { "anyOf": [
55620
+ {
55621
+ "type": "object",
55622
+ "properties": {
55623
+ "status": {
55624
+ "type": "string",
55625
+ "enum": ["imported", "already_present"]
55626
+ },
55627
+ "email_id": {
55628
+ "type": "string",
55629
+ "format": "uuid",
55630
+ "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)$"
55631
+ }
55632
+ },
55633
+ "required": ["status", "email_id"]
55634
+ },
55635
+ {
55636
+ "type": "object",
55637
+ "properties": { "status": {
55638
+ "type": "string",
55639
+ "enum": [
55640
+ "suppressed",
55641
+ "in_progress",
55642
+ "indeterminate"
55643
+ ]
55644
+ } },
55645
+ "required": ["status"]
55646
+ },
55647
+ {
55648
+ "type": "object",
55649
+ "properties": {
55650
+ "status": {
55651
+ "type": "string",
55652
+ "const": "skipped"
55653
+ },
55654
+ "reason": {
55655
+ "type": "string",
55656
+ "enum": [
55657
+ "excluded_label",
55658
+ "out_of_window",
55659
+ "too_large",
55660
+ "provider_missing"
55661
+ ]
55662
+ }
55663
+ },
55664
+ "required": ["status", "reason"]
55665
+ }
55666
+ ] },
55667
+ "ReconcileGoogleMailImportRequest": {
55668
+ "type": "object",
55669
+ "properties": {},
55670
+ "additionalProperties": false
55671
+ },
55672
+ "ReconcileGoogleMailImportResult": {
55673
+ "type": "object",
55674
+ "properties": {
55675
+ "cleaned": {
55676
+ "type": "integer",
55677
+ "minimum": 0
55678
+ },
55679
+ "unresolved": {
55680
+ "type": "integer",
55681
+ "minimum": 0
55682
+ }
55683
+ },
55684
+ "required": ["cleaned", "unresolved"]
55685
+ },
55048
55686
  "ThreadMute": {
55049
55687
  "type": "object",
55050
55688
  "required": [
@@ -59651,6 +60289,27 @@ const openapiDocument = {
59651
60289
  "additionalProperties": {}
59652
60290
  }
59653
60291
  },
60292
+ "rules_added": {
60293
+ "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.",
60294
+ "type": "array",
60295
+ "items": {
60296
+ "type": "object",
60297
+ "properties": {
60298
+ "id": { "type": "string" },
60299
+ "granted_emails": {
60300
+ "type": ["integer", "null"],
60301
+ "minimum": 0,
60302
+ "maximum": 9007199254740991
60303
+ },
60304
+ "more": {
60305
+ "type": "boolean",
60306
+ "const": true
60307
+ }
60308
+ },
60309
+ "required": ["id", "granted_emails"],
60310
+ "additionalProperties": {}
60311
+ }
60312
+ },
59654
60313
  "grant_unguarded": {
59655
60314
  "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).",
59656
60315
  "type": "boolean",
@@ -63416,8 +64075,11 @@ const KEY_WRITE_OPERATION_IDS = /* @__PURE__ */ new Set([
63416
64075
  "credentials:update-key",
63417
64076
  "credentials:revoke-credential"
63418
64077
  ]);
63419
- /** The operations the CLI generates commands for: the manifest without the key writes. */
63420
- const cliOperationManifest = operationManifest.filter((operation) => !KEY_WRITE_OPERATION_IDS.has(`${operation.tagCommand}:${operation.command}`));
64078
+ const CREDENTIAL_HEADER_OPERATION_IDS = /* @__PURE__ */ new Set(["emails:import-google-mail-message"]);
64079
+ /** Every operation id the CLI generates no command for. */
64080
+ const CLI_OMITTED_OPERATION_IDS = /* @__PURE__ */ new Set([...KEY_WRITE_OPERATION_IDS, ...CREDENTIAL_HEADER_OPERATION_IDS]);
64081
+ /** The operations the CLI generates commands for: the manifest without CLI_OMITTED_OPERATION_IDS. */
64082
+ const cliOperationManifest = operationManifest.filter((operation) => !CLI_OMITTED_OPERATION_IDS.has(`${operation.tagCommand}:${operation.command}`));
63421
64083
  // src/oclif/commands/activity.ts
63422
64084
  const API_KEY_FLAG$3 = Flags.string({
63423
64085
  description: "Primitive API key override (defaults to PRIMITIVE_API_KEY or saved OAuth login credentials)",
@@ -63520,33 +64182,38 @@ const COVERING_NOW = `\`primitive email-rule-oversight list-email-rules-covering
63520
64182
  * baseline for a rule that already covered you when notices began), when, the
63521
64183
  * rule's name then, and its author; and, first, each rule that covers you now
63522
64184
  * whose notice is not written yet (pending, dated when the rule last
63523
- * changed). No id: a notice's id is not a rule's, and no command takes it.
64185
+ * changed), then the rule's id (rule_id; a pending row's own id is the
64186
+ * rule's), never the notice's own id, which no command takes.
63524
64187
  * `complete` says the listing is the whole of it (from the first page to the
63525
64188
  * last, nothing withheld). Even then an empty one is no promise that nothing
63526
- * covers you: notices are written by a periodic job and can lag, so it
64189
+ * covers you: notices can lag, so it
63527
64190
  * says how far they go (`asOf`, when the server says) and where to look now.
63528
64191
  */
63529
- function formatConcerningRows(items, complete = false, asOf) {
63530
- if (items.length === 0) return complete ? `${asOf ? `Nothing recorded for you as of ${minute(asOf)} UTC.` : "Nothing recorded for you yet."} A rule that starts covering your mail can take a few minutes to appear here. ${COVERING_NOW}` : "Nothing to show.";
64192
+ function formatConcerningRows(items, complete = false, asOf, pendingComplete) {
64193
+ const unfinished = pendingComplete === false ? "The check for rules that cover you with no notice written yet did not finish, so some may be missing: run this again in a moment." : null;
64194
+ if (items.length === 0) return complete ? `${asOf ? `Nothing recorded for you as of ${minute(asOf)} UTC.` : "Nothing recorded for you yet."} Notices can lag, so a rule that starts covering your mail may not appear here yet. ${COVERING_NOW}` : unfinished ? `${unfinished} ${COVERING_NOW}` : "Nothing to show.";
63531
64195
  const rows = items.map((item) => [
63532
64196
  item.state,
63533
64197
  minute(item.created_at),
63534
64198
  item.name ?? "(unnamed)",
63535
- item.created_through.name ?? item.created_through.id ?? ""
64199
+ item.created_through.name ?? item.created_through.id ?? "",
64200
+ item.rule_id ?? (item.state === "pending" ? item.id : "")
63536
64201
  ]);
63537
64202
  const header = [
63538
64203
  "NOTICE",
63539
64204
  "WHEN (UTC)",
63540
64205
  "RULE",
63541
- "AUTHOR"
64206
+ "AUTHOR",
64207
+ "RULE ID"
63542
64208
  ];
63543
64209
  const widths = header.map((h, i) => Math.max(h.length, ...rows.map((row) => (row[i] ?? "").length)));
63544
- const line = (cells) => cells.map((cell, i) => i === cells.length - 1 ? cell : cell.padEnd(widths[i] ?? 0)).join(" ");
64210
+ const line = (cells) => cells.map((cell, i) => i === cells.length - 1 ? cell : cell.padEnd(widths[i] ?? 0)).join(" ").trimEnd();
63545
64211
  const pending = items.some((item) => item.state === "pending") ? ["", `pending: the rule covers you now and its notice is not written yet. ${COVERING_NOW}`] : [];
63546
64212
  return [
63547
64213
  line(header),
63548
64214
  ...rows.map(line),
63549
- ...pending
64215
+ ...pending,
64216
+ ...unfinished ? ["", pending.length > 0 ? unfinished : `${unfinished} ${COVERING_NOW}`] : []
63550
64217
  ].join("\n");
63551
64218
  }
63552
64219
  /** What was left out, and why: no counts, only the kinds and what would show them. */
@@ -63580,6 +64247,7 @@ async function runActivityList(command, flags, relation) {
63580
64247
  let covers = "";
63581
64248
  let withheld = [];
63582
64249
  let asOf;
64250
+ let pendingComplete;
63583
64251
  let cursor = flags.cursor;
63584
64252
  for (let page = 0; page < (flags.all ? 50 : 1); page += 1) {
63585
64253
  const result = await call$1(listActivityObjects({
@@ -63606,7 +64274,11 @@ async function runActivityList(command, flags, relation) {
63606
64274
  }
63607
64275
  covers = result.data.covers;
63608
64276
  withheld = result.data.withheld;
63609
- if (page === 0) asOf = result.data.as_of;
64277
+ if (page === 0) {
64278
+ const first = result.data;
64279
+ asOf = first.as_of;
64280
+ pendingComplete = first.pending_complete;
64281
+ }
63610
64282
  items.push(...result.data.items);
63611
64283
  cursor = result.data.next_cursor ?? void 0;
63612
64284
  if (!cursor) break;
@@ -63617,12 +64289,13 @@ async function runActivityList(command, flags, relation) {
63617
64289
  items,
63618
64290
  withheld,
63619
64291
  next_cursor: cursor ?? null,
63620
- ...asOf !== void 0 ? { as_of: asOf } : {}
64292
+ ...asOf !== void 0 ? { as_of: asOf } : {},
64293
+ ...pendingComplete !== void 0 ? { pending_complete: pendingComplete } : {}
63621
64294
  }, null, 2));
63622
64295
  return;
63623
64296
  }
63624
- const complete = flags.state === "all" && !flags.cursor && !cursor && withheld.length === 0;
63625
- command.log(relation === "asked" ? formatAskedRows(items, complete) : relation === "concerning" ? formatConcerningRows(items, complete, asOf) : formatActivityRows(covers, items));
64297
+ const complete = flags.state === "all" && !flags.cursor && !cursor && withheld.length === 0 && pendingComplete !== false;
64298
+ command.log(relation === "asked" ? formatAskedRows(items, complete) : relation === "concerning" ? formatConcerningRows(items, complete, asOf, pendingComplete) : formatActivityRows(covers, items));
63626
64299
  const notShown = formatWithheld(withheld);
63627
64300
  if (notShown) command.log(`\n${notShown}`);
63628
64301
  if (cursor) command.log(`\nMore: ${resumeCommand(command.config.bin, flags, cursor, relation)}`);
@@ -63705,11 +64378,11 @@ var ActivityAskedCommand = class ActivityAskedCommand extends Command {
63705
64378
  }
63706
64379
  };
63707
64380
  var ActivityConcerningCommand = class ActivityConcerningCommand extends Command {
63708
- static description = `List what other members did that concerns your own mail, newest first: each time another member's rule started covering one of your mailboxes (started), or saved a new version while covering it (new_version), named as the rule was then, with its author. A rule that already covered you when these notices began is listed once as baseline.
64381
+ static description = `List what other members did that concerns your own mail, newest first: each time another member's rule started covering your mailboxes, that is, it was made or turned active over them or an active rule came to reach you, once per rule, not per mailbox (started), or saved a new version while covering it (new_version), named as the rule was then, with its author. A rule that already covered you when these notices began is listed once as baseline. A rule in draft or observe grants and blocks nothing and gets no notice while it stays there, though \`primitive email-rule-oversight list-email-rules-covering-me\` lists it; turning it active is what is listed, and a rule that covers you again within an hour of its last started or baseline notice gets no new one, though a version it saved meanwhile is listed as new_version. A rule that stops covering you, a rename, and changes to its keys, webhooks or share are not listed.
63709
64382
 
63710
- Notices are written by a job that runs every minute or so and can lag. Until a rule's notice is written, a rule that covers you now is listed first as pending, dated when the rule last changed, and with --json its id is the rule's.
64383
+ Notices can lag. Until a start is written, a rule that now covers you is listed first as pending, dated when the rule last changed, and with --json its id is the rule's. When the check for such rules did not finish, the listing says so and --json carries pending_complete: false; run it again in a moment.
63711
64384
 
63712
- Signed in with \`primitive login\`, you see the notices about your own mail under your current membership. A key, an app or an agent has none. The rules that cover you now, with their ids, are listed by \`primitive email-rule-oversight list-email-rules-covering-me\`; ask a rule's author to turn it off with \`primitive email-rule-oversight create-email-rule-objection --rule-id <rule-id>\`. With --json each notice's id is the notice's, not the rule's.`;
64385
+ Signed in with \`primitive login\`, you see the notices about your own mail under your current membership. A key, an app or an agent has none. The rules that cover you now, with their ids, are listed by \`primitive email-rule-oversight list-email-rules-covering-me\`; ask a rule's author to turn it off with \`primitive email-rule-oversight create-email-rule-objection --rule-id <rule-id>\`. The table's RULE ID, and rule_id with --json, is the rule's id, which \`primitive email-rule-oversight get-email-rule-covering-me <rule-id>\` and create-email-rule-objection --rule-id take; with --json each notice's own id is the notice's, not the rule's.`;
63713
64386
  static summary = "List rules that started covering your mail or changed";
63714
64387
  static examples = ["<%= config.bin %> activity concerning", "<%= config.bin %> activity concerning --all --json"];
63715
64388
  static flags = {
@@ -68088,11 +68761,12 @@ async function sendFromAnswer(apiClient, authFailureContext, purpose) {
68088
68761
  const missing = await missingSendPermission(apiClient);
68089
68762
  if (missing) throw new MissingSendPermissionError(missing);
68090
68763
  }
68091
- const parts = [typeof data.reason === "string" && data.reason.trim() ? data.reason.trim().replace(/\.?$/, ".") : "This credential has no single address to send from, so --from has no default."];
68764
+ const nothingListed = addresses.length === 0 && domains.length === 0;
68765
+ const parts = [typeof data.reason === "string" && data.reason.trim() ? data.reason.trim().replace(/\.?$/, ".") : nothingListed ? "This credential lists no address or domain it can send from, so it cannot send." : "This credential has no single address to send from, so --from has no default."];
68092
68766
  if (addresses.length > 0) parts.push(`Addresses you may send from: ${addresses.join(", ")}.`);
68093
68767
  if (domains.length > 0) parts.push(`${addresses.length > 0 ? "Also any" : "Any"} address at: ${domains.join(", ")}.`);
68094
68768
  parts.push(await claimHint(apiClient));
68095
- parts.push("Pass the address to use with --from <address>.");
68769
+ if (!nothingListed) parts.push("Pass the address to use with --from <address>.");
68096
68770
  throw new Errors.CLIError(parts.filter((part) => part).join(" "), { exit: 1 });
68097
68771
  }
68098
68772
  /** The address of resolveDefaultFrom. */
@@ -70891,7 +71565,7 @@ async function checkAskedOfYou(client, now = Date.now()) {
70891
71565
  const asOf = concerning?.first.as_of;
70892
71566
  return {
70893
71567
  status: "ok",
70894
- message: `nothing waiting for you; ${asOf ? `coverage notices as of ${minute(asOf)} UTC` : "coverage notices can take a few minutes to appear"}`
71568
+ message: `nothing waiting for you; ${asOf ? `coverage notices as of ${minute(asOf)} UTC` : "coverage notices can lag"}`
70895
71569
  };
70896
71570
  }
70897
71571
  const commands = [...waiting.length > 0 ? ["`primitive activity asked --state live`"] : [], ...pending > 0 || notices > 0 || !concerning || coverageUnfinished ? ["`primitive activity concerning`"] : []];
@@ -71022,9 +71696,10 @@ var DoctorCommand = class DoctorCommand extends Command {
71022
71696
  }
71023
71697
  };
71024
71698
  // src/oclif/commands/domains-zone-file.ts
71025
- function zoneFileUrl(baseUrl, domainId, outboundOnly) {
71699
+ function zoneFileUrl(baseUrl, domainId, outboundOnly, inboundOnly = false) {
71026
71700
  const url = new URL(`${baseUrl.replace(/\/$/, "")}/domains/${encodeURIComponent(domainId)}/zone-file`);
71027
71701
  if (outboundOnly) url.searchParams.set("outbound_only", "true");
71702
+ if (inboundOnly) url.searchParams.set("inbound_only", "true");
71028
71703
  return url.toString();
71029
71704
  }
71030
71705
  function contentDispositionFilename(value) {
@@ -71064,7 +71739,8 @@ var DomainsZoneFileCommand = class DomainsZoneFileCommand extends Command {
71064
71739
  "<%= config.bin %> domains zone-file --id <domain-id>",
71065
71740
  "<%= config.bin %> domains zone-file --id <domain-id> --output example.com.zone",
71066
71741
  "<%= config.bin %> domains zone-file --domain example.com --output example.com.zone",
71067
- "<%= config.bin %> domains zone-file --id <domain-id> --outbound-only"
71742
+ "<%= config.bin %> domains zone-file --id <domain-id> --outbound-only",
71743
+ "<%= config.bin %> domains zone-file --id <domain-id> --inbound-only"
71068
71744
  ];
71069
71745
  static flags = {
71070
71746
  "api-key": Flags.string({
@@ -71082,7 +71758,14 @@ var DomainsZoneFileCommand = class DomainsZoneFileCommand extends Command {
71082
71758
  char: "o",
71083
71759
  description: "Write the zone file to this path instead of stdout. Defaults to stdout."
71084
71760
  }),
71085
- "outbound-only": Flags.boolean({ description: "Include only outbound DNS records. Verified domains default to outbound-only at the API; this flag is explicit for agents and scripts." }),
71761
+ "outbound-only": Flags.boolean({
71762
+ description: "Include only the outbound DNS records. Without it or --inbound-only, the file has every record. Not with --inbound-only.",
71763
+ exclusive: ["inbound-only"]
71764
+ }),
71765
+ "inbound-only": Flags.boolean({
71766
+ description: "Include only the inbound records: MX and the ownership TXT record. Not with --outbound-only.",
71767
+ exclusive: ["outbound-only"]
71768
+ }),
71086
71769
  time: Flags.boolean({ description: TIME_FLAG_DESCRIPTION })
71087
71770
  };
71088
71771
  async run() {
@@ -71119,7 +71802,7 @@ var DomainsZoneFileCommand = class DomainsZoneFileCommand extends Command {
71119
71802
  if (!domainId) throw new Errors.CLIError("Could not resolve a domain id.", { exit: 1 });
71120
71803
  let response;
71121
71804
  try {
71122
- response = await fetch(zoneFileUrl(requestConfig.resolvedApiBaseUrl, domainId, flags["outbound-only"]), { headers: {
71805
+ response = await fetch(zoneFileUrl(requestConfig.resolvedApiBaseUrl, domainId, flags["outbound-only"], flags["inbound-only"]), { headers: {
71123
71806
  ...requestConfig.headers ?? {},
71124
71807
  ...auth.apiKey ? { authorization: `Bearer ${auth.apiKey}` } : {}
71125
71808
  } });
@@ -74020,8 +74703,8 @@ const PRIMITIVE_TEAM_AUTHOR = {
74020
74703
  name: "Primitive Team",
74021
74704
  url: "https://primitive.dev"
74022
74705
  };
74023
- const SDK_VERSION_RANGE = "^3.0.0-preview.12";
74024
- const CLI_VERSION_RANGE = "^3.0.0-preview.12";
74706
+ const SDK_VERSION_RANGE = "^3.0.0-preview.13";
74707
+ const CLI_VERSION_RANGE = "^3.0.0-preview.13";
74025
74708
  const ESBUILD_VERSION_RANGE = "^0.27.0";
74026
74709
  function renderHandler() {
74027
74710
  return `// env.PRIMITIVE_API_KEY, env.PRIMITIVE_WEBHOOK_SECRET, and
@@ -77948,7 +78631,7 @@ var KeysUpdateCommand = class KeysUpdateCommand extends Command {
77948
78631
 
77949
78632
  The change runs directly; if your organization requires approval, the command prints the approval link and takes --step-up-token, as for a new key. A key never holds more than you do.
77950
78633
 
77951
- With --json it prints the key as it is now, in the shape keys get prints, with changed, warnings and address_warnings alongside, notice when its permissions or mail changed, rules_removed when a change took rules off, and rules_not_on_key for rules asked to be taken off that it did not have. A permission or rule change that leaves the grant as it is, with no --name, --expires-at or --no-expiry, sends nothing and prints the key with changed: []. If the key cannot be read back after the change, key_error says why and only the change's fields are printed.`;
78634
+ With --json it prints the key as it is now, in the shape keys get prints, with changed, warnings and address_warnings alongside, notice when its permissions or mail changed, rules_added when a change put rules on it (each with granted_emails, how many emails the rule has already shared), rules_removed when a change took rules off, and rules_not_on_key for rules asked to be taken off that it did not have. A permission or rule change that leaves the grant as it is, with no --name, --expires-at or --no-expiry, sends nothing and prints the key with changed: []. If the key cannot be read back after the change, key_error says why and only the change's fields are printed.`;
77952
78635
  static summary = "Change an API key";
77953
78636
  static examples = [
77954
78637
  "<%= config.bin %> keys update 0f0e0d0c-0b0a-4908-8706-050403020100 --add mail:send,mail:reply",