primitive 1.72.1 → 1.73.0

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 { a as REPEAT_IDLE_MAX_MINUTES, b as parseWebhookEvent, d as parseRepeatTick, f as preparePresenceAliveEmail, i as REPEAT_EVERY_MAX_MINUTES, l as parseInteractionEnvelope$1, m as repeatStopCommand, o as REPEAT_MAX_SENDS_MAX, p as prepareSignalEmail, s as buildRepeatStopBody, u as parsePresenceEnvelope, v as isEmailReceivedEvent, x as parseFromHeader } from "../repeats-BL7ZC-_6-CKMKBlx7.js";
2
- import { A as saveActiveChatState, C as resolveCliAuth, D as deleteChatState, E as chatStatePath, F as agentProfileName, G as PrimitiveApiClient, I as agentProfilesDirectory, M as AGENT_PROFILE_ENV, N as AgentConnectionSetupError, O as loadActiveChatState, P as agentProfileDirectory, T as saveSignupCredentials, U as requireDefaultLoginProfile, _ as deleteCliCredentials, a as normalizeCliEnvironmentName, b as hasStoredCliLogin, c as resolveConfigEnvironment, g as credentialsPath, h as credentialsLockPath, i as loadCliConfig, j as AGENT_ADDRESS_ENV, k as loadChatConversationByLocalId, 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 saveCliCredentials, x as loadCliCredentials, y as detectPrimitiveKeyEnvMisname, z as loadConnectedAgentProfile } from "../cli-config--YTRdJ3t.js";
3
- import { $ as MAX_SEND_WAIT_TIMEOUT_MS, $n as listSentAttachmentArchiveMembers, $t as refreshStoredCliCredentials, A as formatMailWakeLine, An as getFunction, Ar as updateFunction, At as loadSkillLine, B as clearConsumedPendingMail, Bn as listAgentContacts, Bt as automatedRejectedError, C as hasReplyState, Cn as getAccount, Cr as startAgentClaim, Ct as thrownErrorExitCode, D as bareAddress, Dn as getCreditBalance, Dr as testFunction, E as explainPendingMailNotFound, En as getConversation, Er as stopRepeatFromEmail, Et as connectNextSteps, F as serverRelationship, Fn as getOrgRoutingTopology, Fr as verifyAgentClaim, Ft as AUTOMATED_FILTER_UNSUPPORTED_CODE, G as removePendingMail, Gn as listDomains, Gt as queryUsesAutomated, H as pendingMailPath, Ht as expectedAutomatedVerdicts, In as getRepeatingSend, Ir as verifyAgentSignup, It as AUTOMATED_FLAG_DESCRIPTION, J as readEmailInteraction, Jn as listEndpoints, Jt as withAttachmentWait, K as interactionHumanLine, Kn as listEmailAttachmentArchiveMembers, Kt as ATTACHMENT_WAIT_FLAG_DESCRIPTION, L as wakeReadCommand, Ln as getSentEmail, Lt as AUTOMATED_VALUES, M as readThreadContext, Mn as getFunctionTestRunTrace, Mr as updateRoute, Mt as formatAlreadySentNotice, N as sentInThread, Nn as getInboxStatus, Nr as updateWakeAuthorization, Nt as writeIdempotentReplayBannerIfReplay, O as describeWake, On as getDefaultNetworkAgent, Or as unsetFunctionRoute, Ot as generatedAgentName, P as serverMuted, Pn as getMemory, Pr as updateWakeSchedule, Pt as withFlagSuggestion, Q as IDEMPOTENCY_KEY_FLAG_DESCRIPTION, Qn as listRoutes, Qt as createCliApiClient, R as wakeRecipientField, Rn as getThread, Rt as AutomatedFilterUnsupportedError, S as formatRepliesCell, Sn as downloadSentAttachmentByFilename, Sr as simulateRoute, St as successfulSendOutcome, T as queryUsesAwaiting, Tr as startCliLogin, Tt as cliInvocation, U as readPendingMail, Un as listDefaultNetworkAgents, Ut as hasAutomatedVerdict, V as clearReadPendingMail, Vn as listAgentNetworks, Vt as ensureSearchReportsAutomated, W as recordPendingMail, Wn as listDefaultNetworkMembers, Wt as isAutomatedRejectedError, X as replyInteractionWarning, Xn as listFunctions, Y as replyExpectation, Yn as listFunctionLogs, Yt as ConnectedAgentKeyRequiredError, Zn as listRepeatingSends, Zt as createAuthenticatedCliApiClient, _ as ReplyStateUnsupportedError, _n as deleteWakeSchedule, _r as semanticSearch, _t as sendIdentityFields, a as extractErrorCode, an as cliLogout, ar as pullWebhookEvent, at as checkPriorReplies, b as ensureSearchReportsReplyState, br as setFunctionSecret, bt as sentHistoryWindowStart, c as hasControlCharacter$1, cn as createFunction, ct as excludeSignalReplies, d as runWithTiming, dn as createWakeSchedule, dr as reorderRoutes, dt as formatPriorRepliesCheckSkipped, en as resolveCliApiRequestConfig, er as listSentEmails, et as SEND_OUTCOME_HELP, f as surfaceUnauthorizedHint, fr as replyToEmail, ft as formatPriorRepliesWarning, g as REPLY_STATE_UNSUPPORTED_CODE, gn as deleteWakeAuthorization, gr as searchMemories, gt as reportSendCommandResult, h as AWAITING_VALUES, hn as deleteRoute, hr as searchEmails, ht as priorRepliesThatWentOut, i as createOperationCommand, in as checkDefaultNetworkContactAdmission, ir as pollCliLogin, it as buildThrownSendFailureEnvelope, j as latestOwnOutbound, jn as getFunctionRouting, jr as updateRepeatingSend, jt as currentMailSessionKey, k as displayAddress, kn as getEmail, kr as updateDefaultNetworkMember, kt as identitySuggestions, l as headerFlagName, ln as createRoute, lr as redeemCreditCode, lt as followUpCommandPrefix, m as AWAITING_FLAG_DESCRIPTION, mn as deleteMemory, mr as runWakeSchedule, mt as formatSendRecordFailureSummary, n as API_ERROR_CODES, nn as cancelSentEmail, nr as listWakeDispatches, nt as assertValidIdempotencyKey, o as extractErrorPayload, on as completeWebhookEvent, ot as classifySendError, p as writeErrorWithHints, pr as resendAgentSignupVerification, pt as formatSendFailureSummary, q as interactionNextActions, qn as listEmails, qt as ATTACHMENT_WAIT_MAX_MS, r as TIME_FLAG_DESCRIPTION, rn as cancelSentEmailByIdempotencyKey, rr as listWakeSchedules, rt as buildFollowUpCommand, s as formatErrorPayload, sn as createEndpoint, st as deriveSendIdempotencyKey, t as API_BASE_URL_FLAG_DESCRIPTION, tn as addDefaultNetworkMember, tr as listWakeAuthorizations, tt as apiResultHttpStatus, u as readTextFileFlag, un as createWakeAuthorization, ur as removeDefaultNetworkMember, ut as formatDeletedEarlierSendNotice, v as assertAwaitingFilterRows, vn as downloadEmailAttachmentArchiveMember, vr as sendEmail, vt as sendOutcomeExitCode, w as isAwaitingRejectedError, wn as getAgentContactPolicy, wr as startAgentSignup, x as formatAwaitingCell, xn as downloadSentAttachmentArchiveMember, xr as setMemory, xt as serializeErrorPayload, y as awaitingRejectedError, yn as downloadEmailAttachmentByFilename, yr as setFunctionRoute, yt as sendWaitClampNotice, z as wakeRelationship, zn as getWakeSchedule, zt as assertAutomatedVerdict } from "../api-command-BrwPbyPP.js";
4
- import { S as resolveListenSubscription, _ 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, x as normalizeListenOrigin, y as listenIdentity } from "../shared-mail-files-MwlVE90c.js";
5
- import { _ as detectAgentRuntime, a as NotificationRetryError, b as installedVersion, c as readConversationStatusContent, d as defaultSessionSocket, f as NativeSessionDisconnectedError, g as connectSkillTarget, h as NotificationOutcomeUnknownError, i as notificationReceiptPage, l as SESSION_UUID$1, m as NativeSessionNotLoadedError, n as notificationSenders, o as isRoutineNotificationContent, p as NativeSessionError, r as openSessionNotifications, s as notificationPartReader, t as notificationScope, v as installConnectSkill, x as readBundledConnectSkill, y as installedConnectSkillFile } from "../notify-session-Byt5sPWW.js";
6
- import { $ as installClaudeWakeHook, A as evaluateContactPolicy, B as contactAddress, C as RECEIVER_MODES, Ct as withOwnerMemberAddress, D as NETWORK_ADMISSION_PENDING_RETRY_MS, E as ContactPolicyReadRetryError, F as disconnectAgent, G as connectAgent, H as runContactRequest, I as AddressNotesApiError, J as refusalAfterReplacement, K as readAgentInvitation, L as addressNoteTarget, M as AgentDisconnectError, N as claimOverRevokedSetup, O as NetworkAdmissionPendingError, P as clearRevokedAddresses, Q as releaseRegistrationsForProfile, R as runAddressNotesRequest, S as runAgentConnect, St as refreshOwnerMemberAddressPeriodically, T as verificationReplySubmitted, U as agentConnectionStatus, V as contactAgentAddress, W as agentInvitationHash, X as savedReceiver, Y as saveConnectionName, Z as MACHINE_RUNTIMES, _ as enrollmentResumes, _t as jsonIndentation, a as endSession, at as describeSessionHookItem, b as invitationProfileName, bt as writeManagedFile, c as pendingSessionDisconnects, ct as findOnPath, d as registerSession, dt as readClaudeSettings, et as recordHookMailCheck, f as retryPendingDisconnects, ft as repairClaudeHooks, g as enrollAgent, gt as inspectManagedBlock, h as staleSessionAgents, ht as MachineFileError, i as connectedProfilesForSession, it as describeSessionHookChange, j as canonicalContactSelector, k as createNotificationContactPolicy, l as psProcessInfo, lt as hasMachineSessionHooks, m as runDetached, mt as writeClaudeSettings, n as OMP_MAIN, nt as claudeConfigDir, o as headlessClaudeRun, ot as ensureHookLauncher, p as revokeStaleSessionAgents, pt as samePath, q as receiverStatusCommand, r as agentConnectionState, rt as currentCliLocation, st as ephemeralCliReason, t as HOOK_END_GRACE_MS, tt as boundSessionProfiles, u as readClaudeHookInput, ut as inspectClaudeHooks, v as connectWarnings, vt as readManagedFile, w as externalReceivingState, x as pollCheckCommand, xt as readHookLauncherWarning, y as defaultAgentProfileName, yt as upsertManagedBlock, z as ContactsApiError } from "../machine-session-Be6j29GE.js";
7
- import { a as scopedChatSenderTrust, i as readBeforeDeadline, n as isPlainChatReply, o as presenceDisposition, r as isScopedChatReply, s as readPresenceProjection, t as isConnectedChatCredential } from "../scoped-chat-DTFkP360.js";
8
- import { c as startBackgroundListen, i as backgroundListenToken, l as stopBackgroundListen, o as runBackgroundListen, r as backgroundListenStatus, u as verifyBackgroundListenTarget } from "../listen-background--0peztKE.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-DeEEZPbQ.js";
1
+ import { $ as AutomatedFilterUnsupportedError, $t as listDomains, A as sleep$3, An as setMemory, At as getAgentContactPolicy, B as hasReplyState, Bn as updateRepeatingSend, Bt as getMemory, C as collectNewAcceptedEmails, Ct as deleteWakeSchedule, D as filtersFromFlags, Dn as sendEmail, Dt as downloadSentAttachmentArchiveMember, E as fetchEmailSearchPage, En as semanticSearch, F as assertAwaitingFilterRows, Fn as stopRepeatFromEmail, Ft as getEmail, Gn as verifyAgentSignup, Gt as getWakeSchedule, H as queryUsesAwaiting, Hn as updateWakeAuthorization, Ht as getRepeatingSend, I as awaitingRejectedError, In as testFunction, It as getFunction, J as parseWebhookEvent, Jt as listAgentContacts, K as isEmailReceivedEvent, L as ensureSearchReportsReplyState, Ln as unsetFunctionRoute, Lt as getFunctionRouting, M as AWAITING_VALUES, Mn as startAgentClaim, Mt as getConversation, N as REPLY_STATE_UNSUPPORTED_CODE, Nn as startAgentSignup, Nt as getCreditBalance, O as quoteDslValue, On as setFunctionRoute, Ot as downloadSentAttachmentByFilename, P as ReplyStateUnsupportedError, Pn as startCliLogin, Pt as getDefaultNetworkAgent, Q as AUTOMATED_VALUES, Qt as listDefaultNetworkMembers, R as formatAwaitingCell, Rn as updateDefaultNetworkMember, Rt as getFunctionTestRunTrace, S as transientFailure, Sn as runWakeSchedule, St as deleteWakeAuthorization, T as encodeReceivedAtSearchCursor, Tn as searchMemories, Tt as downloadEmailAttachmentByFilename, Un as updateWakeSchedule, Ut as getSentEmail, V as isAwaitingRejectedError, Vn as updateRoute, Vt as getOrgRoutingTopology, Wn as verifyAgentClaim, Wt as getThread, X as AUTOMATED_FILTER_UNSUPPORTED_CODE, Y as parseFromHeader, Yt as listAgentNetworks, Z as AUTOMATED_FLAG_DESCRIPTION, Zt as listDefaultNetworkAgents, _ as describeApiFailure, _n as redeemCreditCode, _t as createWakeSchedule, a as REPEAT_IDLE_MAX_MINUTES, an as listRepeatingSends, at as hasAutomatedVerdict, b as retryTransient, bn as replyToEmail, bt as deleteMemory, cn as listSentEmails, ct as cancelSentEmail, d as parseRepeatTick, dn as listWakeSchedules, dt as cliLogout, en as listEmailAttachmentArchiveMembers, et as assertAutomatedVerdict, f as preparePresenceAliveEmail, fn as pollCliLogin, ft as completeWebhookEvent, g as WaitDeadlineReached, gt as createWakeAuthorization, ht as createRoute, i as REPEAT_EVERY_MAX_MINUTES, in as listFunctions, j as AWAITING_FLAG_DESCRIPTION, jn as simulateRoute, k as sinceFromFlags, kn as setFunctionSecret, kt as getAccount, l as parseInteractionEnvelope$1, ln as listWakeAuthorizations, lt as cancelSentEmailByIdempotencyKey, m as repeatStopCommand, mt as createFunction, nn as listEndpoints, o as REPEAT_MAX_SENDS_MAX, on as listRoutes, ot as isAutomatedRejectedError, p as prepareSignalEmail, pn as pullWebhookEvent, pt as createEndpoint, rn as listFunctionLogs, s as buildRepeatStopBody, sn as listSentAttachmentArchiveMembers, st as addDefaultNetworkMember, tn as listEmails, tt as automatedRejectedError, u as parsePresenceEnvelope, un as listWakeDispatches, ut as checkDefaultNetworkContactAdmission, vn as removeDefaultNetworkMember, w as cursorFromAcceptedRows, wn as searchEmails, wt as downloadEmailAttachmentArchiveMember, x as retryingOperation, xn as resendAgentSignupVerification, xt as deleteRoute, y as pauseForTransientFailure, yn as reorderRoutes, z as formatRepliesCell, zn as updateFunction, zt as getInboxStatus } from "../repeats-BL7ZC-_6-B_ESsWTH.js";
2
+ import { A as saveActiveChatState, C as resolveCliAuth, D as deleteChatState, E as chatStatePath, F as agentProfileName, G as PrimitiveApiClient, I as agentProfilesDirectory, M as AGENT_PROFILE_ENV, N as AgentConnectionSetupError, O as loadActiveChatState, P as agentProfileDirectory, T as saveSignupCredentials, U as requireDefaultLoginProfile, _ as deleteCliCredentials, a as normalizeCliEnvironmentName, b as hasStoredCliLogin, c as resolveConfigEnvironment, g as credentialsPath, h as credentialsLockPath, i as loadCliConfig, j as AGENT_ADDRESS_ENV, k as loadChatConversationByLocalId, 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 saveCliCredentials, x as loadCliCredentials, y as detectPrimitiveKeyEnvMisname, z as loadConnectedAgentProfile } from "../cli-config-C0Y_Ppol.js";
3
+ 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-CZfm7E2k.js";
4
+ import { $ as formatDeletedEarlierSendNotice, A as clearReadPendingMail, At as createCliApiClient, C as serverRelationship, Ct as withFlagSuggestion, D as wakeRelationship, Dt as ConnectedAgentKeyRequiredError, E as wakeRecipientField, Et as withAttachmentWait, F as interactionHumanLine, G as assertValidIdempotencyKey, H as MAX_SEND_WAIT_TIMEOUT_MS, I as interactionNextActions, J as checkPriorReplies, K as buildFollowUpCommand, L as readEmailInteraction, M as readPendingMail, Mt as resolveCliApiRequestConfig, N as recordPendingMail, O as claimPendingMail, P as removePendingMail, Q as followUpCommandPrefix, R as replyExpectation, S as serverMuted, St as writeIdempotentReplayBannerIfReplay, T as wakeReadCommand, Tt as ATTACHMENT_WAIT_MAX_MS, U as SEND_OUTCOME_HELP, V as IDEMPOTENCY_KEY_FLAG_DESCRIPTION, W as apiResultHttpStatus, X as deriveSendIdempotencyKey, Y as classifySendError, Z as excludeSignalReplies, _ as displayAddress, _t as generatedAgentName, a as extractErrorCode, at as reportSendCommandResult, b as readThreadContext, bt as currentMailSessionKey, c as hasControlCharacter$1, ct as sendWaitClampNotice, d as runWithTiming, dt as successfulSendOutcome, et as formatPriorRepliesCheckSkipped, f as surfaceUnauthorizedHint, ft as thrownErrorExitCode, g as describeWake, h as bareAddress, ht as connectNextSteps, i as createOperationCommand, it as priorRepliesThatWentOut, j as pendingMailPath, jt as refreshStoredCliCredentials, k as clearConsumedPendingMail, kt as createAuthenticatedCliApiClient, l as headerFlagName, lt as sentHistoryWindowStart, m as explainPendingMailNotFound, mt as cliInvocation, n as API_ERROR_CODES, nt as formatSendFailureSummary, o as extractErrorPayload, ot as sendIdentityFields, p as writeErrorWithHints, q as buildThrownSendFailureEnvelope, r as TIME_FLAG_DESCRIPTION, rt as formatSendRecordFailureSummary, s as formatErrorPayload, st as sendOutcomeExitCode, t as API_BASE_URL_FLAG_DESCRIPTION, tt as formatPriorRepliesWarning, u as readTextFileFlag, ut as serializeErrorPayload, v as formatMailWakeLine, vt as identitySuggestions, wt as ATTACHMENT_WAIT_FLAG_DESCRIPTION, x as sentInThread, xt as formatAlreadySentNotice, y as latestOwnOutbound, yt as loadSkillLine, z as replyInteractionWarning } from "../api-command-fKP3NYa7.js";
5
+ import { _ as detectAgentRuntime, a as NotificationRetryError, b as installedVersion, c as readConversationStatusContent, d as defaultSessionSocket, f as NativeSessionDisconnectedError, g as connectSkillTarget, h as NotificationOutcomeUnknownError, i as notificationReceiptPage, l as SESSION_UUID$1, m as NativeSessionNotLoadedError, n as notificationSenders, o as isRoutineNotificationContent, p as NativeSessionError, r as openSessionNotifications, s as notificationPartReader, t as notificationScope, v as installConnectSkill, x as readBundledConnectSkill, y as installedConnectSkillFile } from "../notify-session-DJAb9SGm.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-B6V5-grn.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-DAiOb622.js";
8
+ import { c as startBackgroundListen, i as backgroundListenToken, l as stopBackgroundListen, o as runBackgroundListen, r as backgroundListenStatus, u as verifyBackgroundListenTarget } from "../listen-background-cD6n8VYO.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-Cte4mAL3.js";
10
10
  import { autoSignalEligible, dispatchAutoRead, dispatchAutoWorking, haltAutoWorking, isSentSignal, readWorkingLease, restoreAutoWorking } from "./auto-signals.js";
11
11
  import { n as jsonOutputRequested, r as runStreamingJson, t as guardJsonOutputCommands } from "../json-output-Ce10AsSb.js";
12
12
  import { Args, Command, Errors, Flags, ux } from "@oclif/core";
@@ -40006,7 +40006,7 @@ const RETRYABLE_STATUS = /* @__PURE__ */ new Set([
40006
40006
  503,
40007
40007
  504
40008
40008
  ]);
40009
- function sleep$3(ms) {
40009
+ function sleep$2(ms) {
40010
40010
  return new Promise((resolve) => setTimeout(resolve, ms));
40011
40011
  }
40012
40012
  /**
@@ -40028,7 +40028,7 @@ async function retryingFetch(url, init, label, maxRetries = DEFAULT_MAX_RETRIES)
40028
40028
  throw new Error(`${label}: network error after ${attempt} retries: ${networkError?.message ?? networkError}`);
40029
40029
  }
40030
40030
  if (res) await res.text().catch(() => {});
40031
- await sleep$3(Math.min(1e3 * 2 ** attempt, 15e3) + Math.floor(Math.random() * 250));
40031
+ await sleep$2(Math.min(1e3 * 2 ** attempt, 15e3) + Math.floor(Math.random() * 250));
40032
40032
  }
40033
40033
  }
40034
40034
  async function initiate(opts, manifest) {
@@ -40371,7 +40371,7 @@ function withClearedNote(message, cleared) {
40371
40371
  return `${message} Before that, this run cleared ${cleared.map((row) => `${row.address} (profile ${row.profile})`).join(", ")} on this machine because Primitive confirmed ${cleared.length === 1 ? "its credential was" : "their credentials were"} already revoked; ${cleared.length === 1 ? "it stays" : "they stay"} disconnected.`;
40372
40372
  }
40373
40373
  var AgentConnectCommand = class AgentConnectCommand extends Command {
40374
- static description = `Connect this coding session to Primitive in one call. With --session, the command checks this CLI's capabilities, installs or refreshes the matching primitive-connect skill for the detected runtime (Claude Code or Codex) from files bundled in this CLI, claims the owner's private setup invitation from piped stdin, answers one authenticated setup challenge, enables owner notifications, starts receiving, seeds a private AGENT_INFO note from --name and --info when absent, writes a private AGENT_RESUME note holding the command that resumes the bound session ("claude --resume <session>" or "codex resume <session>") once verified (or deletes an existing one when no resumable session is bound), and prints one JSON result. The receiver defaults to external hooks in Claude Code and the native background listener elsewhere. When the native default cannot work because this machine has no local session socket (for example Codex older than 0.158.0), the command connects with poll receiving instead and reports receiving.fallbackReason and receiving.fallbackDetail. Without a session (no --session, or an empty one) the receiver is poll: for runtimes with no local session ID or hooks, such as a cloud-hosted conversation whose commands run in a separate sandbox, the invitation is claimed and verified the same way, nothing is installed, and the result's receiving.checkCommand is the command the agent runs to check for new mail at the start of each turn and after it sends. Native receiving starts or reuses a supervised background listener and waits briefly for its first successful mail check; external receiving installs the exact Claude session's fail-open Stop hook and resume SessionStart hook after the verification reply; a real idle mail event must still verify wake. The profile defaults to session-<session>, or to connection-<invitation hash prefix> without a session. --resume continues saved progress without reading stdin or replaying a claim or uncertain verification send. After the reply is submitted it waits up to a minute for the server to confirm the connection and reports verification.state verified, or reply_submitted while confirmation is still pending. Verification is separate from receiver health. Both official production (https://api.primitive.dev/v1) and staging (https://api.primitive-staging-1.com/v1) invitations pin their API origin. Never pass an invitation as a command argument. One address per session: an address whose credential Primitive confirms was already revoked (for example, revoked in the app before the owner reconnected it) no longer counts; it is disconnected locally, reported in clearedRevoked, and its saved setup is moved aside so the new invitation can be claimed into the same profile. Otherwise, if this session already has a connected Primitive address, including one saved in the profile being connected, the command claims nothing, leaves stdin unread, and exits 3 with status already_connected. Its detail names how to continue that profile's own connection when that is the only one: --resume for a setup with saved progress, or --keep-existing to refresh a claim-only profile from the same invitation. Otherwise ask the user whether to keep the existing address or disconnect it first, then rerun with --keep-existing or --replace-existing. Never choose for the user. Select the saved identity with PRIMITIVE_AGENT_PROFILE. Use --status --json with --profile, with PRIMITIVE_AGENT_PROFILE set, or with --session (the address connected for that session) to inspect saved identity and local receiver health offline; it exits 1 when nothing is configured. A status check before connecting is optional: connect itself claims nothing and exits 3 when the session already has an address. A completed connection's result carries nextSteps, in order: report to the owner in two short sentences, make one offer to rename a generated name and record where the agent runs, and load the primitive-connect skill before handling mail. When the claim reported one, the result also carries the connection's name and nameIsDefault.`;
40374
+ static description = `Connect this coding session to Primitive in one call. With --session, the command checks this CLI's capabilities, installs or refreshes the matching primitive-connect skill for the detected runtime (Claude Code or Codex) from files bundled in this CLI, claims the owner's private setup invitation from piped stdin, answers one authenticated setup challenge, enables owner notifications, starts receiving, seeds a private AGENT_INFO note from --name and --info when absent, writes a private AGENT_RESUME note holding the command that resumes the bound session ("claude --resume <session>" or "codex resume <session>") once verified (or deletes an existing one when no resumable session is bound), and prints one JSON result. The receiver defaults to external hooks in Claude Code and the native background listener elsewhere. When the native default cannot work because this machine has no local session socket (for example Codex older than 0.158.0), the command connects with poll receiving instead and reports receiving.fallbackReason and receiving.fallbackDetail. Without a session (no --session, or an empty one) the receiver is poll: for runtimes with no local session ID or hooks, such as a cloud-hosted conversation whose commands run in a separate sandbox, the invitation is claimed and verified the same way, nothing is installed, and the result's receiving.checkCommand is the command the agent runs to check for new mail at the start of each turn and after it sends. Native receiving starts or reuses a supervised background listener and waits briefly for its first successful mail check; external receiving installs the exact Claude session's fail-open Stop hook and resume SessionStart hook after the verification reply; a real idle mail event must still verify wake. The profile defaults to session-<session>, or to connection-<invitation hash prefix> without a session. --resume continues saved progress without reading stdin or replaying a claim or uncertain verification send. After the reply is submitted it waits up to a minute for the server to confirm the connection and reports verification.state verified, or reply_submitted while confirmation is still pending. Verification is separate from receiver health. Both official production (https://api.primitive.dev/v1) and staging (https://api.primitive-staging-1.com/v1) invitations pin their API origin. Never pass an invitation as a command argument. One address per session: an address whose credential Primitive confirms was already revoked (for example, revoked in the app before the owner reconnected it) no longer counts; it is disconnected locally, reported in clearedRevoked, and its saved setup is moved aside so the new invitation can be claimed into the same profile. A profile whose earlier setup or enrollment never saved a credential is not an address: a pasted invitation is claimed into it (its unfinished state is moved aside), and the result's replacedUnfinished says whether that finished the same pending address. Otherwise, if this session already has a connected Primitive address, including one saved in the profile being connected, the command claims nothing, leaves stdin unread, and exits 3 with status already_connected. Its detail names how to continue that profile's own connection when that is the only one: --resume for a setup with saved progress, or --keep-existing to refresh a claim-only profile from the same invitation. Otherwise ask the user whether to keep the existing address or disconnect it first, then rerun with --keep-existing or --replace-existing. Never choose for the user. Select the saved identity with PRIMITIVE_AGENT_PROFILE. Use --status --json with --profile, with PRIMITIVE_AGENT_PROFILE set, or with --session (the address connected for that session) to inspect saved identity and local receiver health offline; it exits 1 when nothing is configured, and reports the session's last registration failure as registration when one was recorded. A status check before connecting is optional: connect itself claims nothing and exits 3 when the session already has an address. A completed connection's result carries nextSteps, in order: report to the owner in two short sentences, make one offer to rename a generated name and record where the agent runs, and load the primitive-connect skill before handling mail. When the claim reported one, the result also carries the connection's name and nameIsDefault.`;
40375
40375
  static summary = "Connect and verify an agent address";
40376
40376
  static examples = [
40377
40377
  "<%= config.bin %> agent connect --session \"$CODEX_THREAD_ID\" --name Research --info \"Reviews pull requests\" --json < private-invitation.txt",
@@ -40444,12 +40444,14 @@ var AgentConnectCommand = class AgentConnectCommand extends Command {
40444
40444
  });
40445
40445
  if (picked.profile === null && picked.session === null) throw new AgentConnectionSetupError(`Pass --profile <name>, --session <id> or set ${AGENT_PROFILE_ENV}.`);
40446
40446
  if (picked.profile === null) {
40447
- const detail = statusProfileMissingDetail(picked.bound);
40447
+ const registration = picked.bound.length === 0 && picked.session ? registrationSummary(this.config.configDir, defaultAgentProfileName(picked.session)) : null;
40448
+ const detail = registration ? `${statusProfileMissingDetail(picked.bound)} ${registrationSummaryLine(registration)}` : statusProfileMissingDetail(picked.bound);
40448
40449
  this.log(flags.json ? JSON.stringify({
40449
40450
  status: "not_configured",
40450
40451
  profileName: null,
40451
40452
  session: picked.session,
40452
40453
  ...picked.bound.length > 1 ? { profiles: picked.bound } : {},
40454
+ ...registration ? { registration } : {},
40453
40455
  detail
40454
40456
  }) : detail);
40455
40457
  process.exitCode = 1;
@@ -40457,20 +40459,25 @@ var AgentConnectCommand = class AgentConnectCommand extends Command {
40457
40459
  }
40458
40460
  const profileName = picked.profile;
40459
40461
  const result = agentConnectionStatus(this.config.configDir, profileName);
40462
+ const registration = registrationSummary(this.config.configDir, profileName);
40460
40463
  if (result.status !== "configured") {
40461
- const detail = `Agent profile ${profileName} is not configured. Run \`primitive agent connect\` with the owner's invitation to connect it.`;
40464
+ const detail = registration ? `Agent profile ${profileName} is not configured. ${registrationSummaryLine(registration)}` : `Agent profile ${profileName} is not configured. Run \`primitive agent connect\` with the owner's invitation to connect it.`;
40462
40465
  this.log(flags.json ? JSON.stringify({
40463
40466
  ...result,
40467
+ ...registration ? { registration } : {},
40464
40468
  detail
40465
40469
  }) : detail);
40466
40470
  process.exitCode = 1;
40467
40471
  return;
40468
40472
  }
40469
- if (flags.json) this.log(JSON.stringify(result));
40473
+ if (flags.json) this.log(JSON.stringify(registration?.lastFailure ? {
40474
+ ...result,
40475
+ registration
40476
+ } : result));
40470
40477
  else {
40471
40478
  const receiving = result.receiving;
40472
40479
  const why = [receiving.reason, receiving.failureCode !== receiving.reason ? receiving.failureCode : null].filter(Boolean);
40473
- this.log(`Agent profile ${profileName} is configured for ${result.identity.agentAddress}. Local receiving: ${receiving.state}${why.length ? ` (${why.join(", ")})` : ""}.${receiving.detail ? ` ${receiving.detail}` : ""}${receiving.lastFiredAt ? ` Receive hook last ran at ${receiving.lastFiredAt}.` : ""}${receiving.lastSuccessfulMailCheckAt ? ` Last completed mail check at ${receiving.lastSuccessfulMailCheckAt}.` : ""}`);
40480
+ this.log(`Agent profile ${profileName} is configured for ${result.identity.agentAddress}. Local receiving: ${receiving.state}${why.length ? ` (${why.join(", ")})` : ""}.${receiving.detail ? ` ${receiving.detail}` : ""}${receiving.lastFiredAt ? ` Receive hook last ran at ${receiving.lastFiredAt}.` : ""}${receiving.lastSuccessfulMailCheckAt ? ` Last completed mail check at ${receiving.lastSuccessfulMailCheckAt}.` : ""}${registration?.lastFailure ? ` ${registrationSummaryLine(registration)}` : ""}`);
40474
40481
  }
40475
40482
  return;
40476
40483
  }
@@ -40855,7 +40862,7 @@ function invocation(entry) {
40855
40862
  }
40856
40863
  var AgentEnrollCommand = class AgentEnrollCommand extends Command {
40857
40864
  static summary = "Give this coding session an address in your organization";
40858
- static description = `On this trusted machine, use the saved member OAuth login to create one address for the exact loaded session, claim its one-use invitation privately, answer the email challenge, and poll the owner's connection list for confirmed pairing. Native receiving starts when supported. With --receiver external in the exact Claude session, install a fail-open Stop hook and resume SessionStart hook in that runtime's settings after the verification reply; idle wake remains unverified until tested with real mail. With --contact-requests, the login conditionally enables first-contact intake for this exact address after verification, preserving existing policy rules. An explicit disable or uncertain policy update is reported separately without losing pairing or receiver setup. The server allocates a readable address. An uncertain creation resumes the same saved request; recovered results do not include another invitation. Use --continue-setup once to explicitly continue a recovered pending connection. An uncertain continuation or claim is held for owner recovery, never repeated automatically. Requires a verified Primitive-managed domain. This command does not accept API keys, a connection profile, or an invitation argument. One address per session: if this session already has another connected Primitive address, nothing is created and the command exits 3 with status already_connected; ask the user whether to keep the existing address or disconnect it first, then rerun with --keep-existing or --replace-existing. Never choose for the user.`;
40865
+ static description = `On this trusted machine, use the saved member OAuth login to create one address for the exact loaded session, claim its one-use invitation privately, answer the email challenge, and poll the owner's connection list for confirmed pairing. Native receiving starts when supported. With --receiver external in the exact Claude session, install a fail-open Stop hook and resume SessionStart hook in that runtime's settings after the verification reply; idle wake remains unverified until tested with real mail. With --contact-requests, the login conditionally enables first-contact intake for this exact address after verification, preserving existing policy rules. An explicit disable or uncertain policy update is reported separately without losing pairing or receiver setup. The server allocates a readable address. An uncertain creation resumes the same saved request; recovered results do not include another invitation. Use --continue-setup once to explicitly continue a recovered pending connection. An uncertain continuation is held for owner recovery, never repeated automatically. When a claim left no saved credential (it was never sent, was refused, or its answer was lost), a rerun signed in as the agent's owner in the same organization asks Primitive for one fresh invitation for the same address and claims it; without that login the refusal names the step that finishes it from the app. Each attempt is recorded, without secrets, in the profile's registration log, which agent connect --status reports. Requires a verified Primitive-managed domain. This command does not accept API keys, a connection profile, or an invitation argument. One address per session: if this session already has another connected Primitive address, nothing is created and the command exits 3 with status already_connected; ask the user whether to keep the existing address or disconnect it first, then rerun with --keep-existing or --replace-existing. Never choose for the user.`;
40859
40866
  static examples = ["<%= config.bin %> agent enroll --session 11111111-1111-4111-8111-111111111111 --name Research --contact-requests --json", "<%= config.bin %> agent enroll --session 11111111-1111-4111-8111-111111111111 --receiver external --name Research --json"];
40860
40867
  static flags = {
40861
40868
  session: Flags.string({
@@ -41002,7 +41009,7 @@ var AgentEnrollCommand = class AgentEnrollCommand extends Command {
41002
41009
  }
41003
41010
  if (externalHook === "unavailable" || flags["contact-requests"] && result.contactRequestPolicy !== "enabled" || result.connection.status !== "connected" || flags.receiver !== "external" && flags.receiver !== "poll" && result.receiving.state !== "healthy") process.exitCode = 2;
41004
41011
  } catch (error) {
41005
- throw new Errors.CLIError(error instanceof AgentConnectionSetupError ? error.message : "Enrollment paused. Preserve this session's private profile and inspect the pending agent in the app before retrying. No second address was requested automatically.", { exit: 1 });
41012
+ throw new Errors.CLIError(error instanceof AgentConnectionSetupError ? error.message : "Enrollment stopped on an unexpected error. Rerun the same command to resume this session's saved enrollment; it never requests a second address.", { exit: 1 });
41006
41013
  }
41007
41014
  }
41008
41015
  };
@@ -42601,7 +42608,7 @@ function searchFailure(response) {
42601
42608
  }
42602
42609
  /** Inspect an exact email ID obtained from a targeted query or event journal. */
42603
42610
  async function inspectTargetedReply(params) {
42604
- const result = await readBeforeDeadline(params.deadline, (signal) => getEmail({
42611
+ const result = await readApiBeforeDeadline(params.deadline, (signal) => getEmail({
42605
42612
  client: params.apiClient.client,
42606
42613
  path: { id: params.id },
42607
42614
  signal,
@@ -42609,7 +42616,8 @@ async function inspectTargetedReply(params) {
42609
42616
  }));
42610
42617
  if (result === null) return null;
42611
42618
  const email = result.data?.data;
42612
- if (result.error || !email || email.id !== params.id) throw invalid$2(`Could not inspect reply candidate ${params.id}.`);
42619
+ if (result.error) throw invalid$2(`Could not inspect reply candidate ${params.id}: ${describeApiFailure(result)}.`);
42620
+ if (!email || email.id !== params.id) throw invalid$2(`Could not inspect reply candidate ${params.id}.`);
42613
42621
  const presence = presenceDisposition(email);
42614
42622
  if (presence !== "ordinary") return {
42615
42623
  kind: presence === "pending" ? "pending" : "unrelated",
@@ -42685,7 +42693,7 @@ async function inspectTargetedReply(params) {
42685
42693
  /** One targeted recovery page. The event owner decides when recovery is needed. */
42686
42694
  async function readTargetedReplyPage(params) {
42687
42695
  if (!params.sentId || !params.from || !params.recipient) throw invalid$2("Targeted reply recovery requires the exact sent email, receiving address, and peer.");
42688
- const result = await readBeforeDeadline(params.deadline, (signal) => searchEmails({
42696
+ const result = await readApiBeforeDeadline(params.deadline, (signal) => searchEmails({
42689
42697
  client: params.apiClient.client,
42690
42698
  signal,
42691
42699
  query: {
@@ -42715,6 +42723,11 @@ async function readTargetedReplyPage(params) {
42715
42723
  }
42716
42724
  //#endregion
42717
42725
  //#region src/oclif/connected-reply-wait.ts
42726
+ /**
42727
+ * Slack for clock differences between this machine, which records when a
42728
+ * wait was created, and the server, which records when mail was received.
42729
+ */
42730
+ const REPLY_CLOCK_SKEW_MS = 6e5;
42718
42731
  function recoveryEventId(id) {
42719
42732
  const h = createHash("sha256").update(`reply-recovery:${id}`).digest("hex");
42720
42733
  return `${h.slice(0, 8)}-${h.slice(8, 12)}-${h.slice(12, 16)}-${h.slice(16, 20)}-${h.slice(20, 32)}`;
@@ -42802,6 +42815,20 @@ async function openConnectedReplyWait(options) {
42802
42815
  let closed = false;
42803
42816
  let closing;
42804
42817
  const timedOut = () => options.deadline != null && Date.now() >= options.deadline;
42818
+ let earliestReply;
42819
+ /**
42820
+ * The earliest receipt time a reply to this wait's send can have: the wait
42821
+ * is registered before the send, so mail received well before it is
42822
+ * retained history, not a reply.
42823
+ */
42824
+ async function replyFloor() {
42825
+ if (earliestReply !== void 0) return earliestReply;
42826
+ const intent = await store.readWait(requestId);
42827
+ const created = Date.parse(intent?.createdAt ?? "");
42828
+ const earlier = [options.sentAt, options.since].map((value) => Date.parse(value ?? "")).filter(Number.isFinite);
42829
+ earliestReply = Number.isFinite(created) ? Math.min(created, ...earlier) - REPLY_CLOCK_SKEW_MS : Number.NEGATIVE_INFINITY;
42830
+ return earliestReply;
42831
+ }
42805
42832
  async function release() {
42806
42833
  if (released) return;
42807
42834
  await (await openSharedMailStore({
@@ -42892,6 +42919,7 @@ async function openConnectedReplyWait(options) {
42892
42919
  requestId = bound.requestId;
42893
42920
  sentId = bound.sentEmailId ?? void 0;
42894
42921
  recoveryNeeded = true;
42922
+ earliestReply = void 0;
42895
42923
  },
42896
42924
  uncertain: () => store.markWaitUncertain(requestId),
42897
42925
  async cancelBeforeSend() {
@@ -42981,7 +43009,9 @@ async function openConnectedReplyWait(options) {
42981
43009
  limit: options.pageSize,
42982
43010
  cursor: localCursor
42983
43011
  });
43012
+ const floor = await replyFloor();
42984
43013
  for (const row of local.emails) {
43014
+ if (!row.details && Date.parse(row.receivedAt) < floor) continue;
42985
43015
  if (row.details && row.details.authorization !== "pending" && (row.details.peer !== options.recipient || row.details.replyToSentEmailId !== sentId)) continue;
42986
43016
  const reply = await inspect(row.emailId);
42987
43017
  if (reply) return reply;
@@ -43658,132 +43688,6 @@ function warnIfSharedProfile(params) {
43658
43688
  const warning = sharedProfileWarning(params);
43659
43689
  if (warning) process.stderr.write(`Warning: ${warning}\n`);
43660
43690
  }
43661
- //#endregion
43662
- //#region src/oclif/commands/emails-poll.ts
43663
- function quoteDslValue(value) {
43664
- if (/^[^\s"]+$/.test(value)) return value;
43665
- return `"${value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`;
43666
- }
43667
- function combineQ(q, domain) {
43668
- const parts = [q?.trim(), domain ? `domain:${quoteDslValue(domain.trim())}` : void 0].filter((part) => Boolean(part));
43669
- return parts.length > 0 ? parts.join(" ") : void 0;
43670
- }
43671
- function normalizeIsoDate(value, label) {
43672
- const parsed = new Date(value);
43673
- if (Number.isNaN(parsed.getTime())) throw new Error(`${label} must be a valid date or ISO-8601 timestamp.`);
43674
- return parsed.toISOString();
43675
- }
43676
- function filtersFromFlags(flags) {
43677
- if (flags.automated !== void 0 && !AUTOMATED_VALUES.includes(flags.automated)) throw new Error("--automated must be true or false.");
43678
- return {
43679
- automated: flags.automated === void 0 ? void 0 : flags.automated === "true",
43680
- awaiting: flags.awaiting,
43681
- body: flags.body,
43682
- domain: flags.domain,
43683
- domainId: flags["domain-id"],
43684
- from: flags.from,
43685
- hasAttachment: flags["has-attachment"],
43686
- q: flags.q,
43687
- replyToSentEmailId: flags["reply-to-sent-email-id"],
43688
- spamScoreGte: flags["spam-score-gte"],
43689
- spamScoreLt: flags["spam-score-lt"],
43690
- subject: flags.subject,
43691
- to: flags.to
43692
- };
43693
- }
43694
- function sinceFromFlags(flags) {
43695
- if (flags.since) return normalizeIsoDate(flags.since, "--since");
43696
- return flags["include-existing"] ? void 0 : (/* @__PURE__ */ new Date()).toISOString();
43697
- }
43698
- function buildEmailSearchQuery(params) {
43699
- const query = {
43700
- include_facets: "false",
43701
- limit: params.pageSize,
43702
- snippet: "false",
43703
- sort: "received_at_asc"
43704
- };
43705
- const q = combineQ(params.filters.q, params.filters.domain);
43706
- if (q) query.q = q;
43707
- if (params.filters.awaiting) query.awaiting = params.filters.awaiting;
43708
- if (params.filters.automated !== void 0) query.automated = params.filters.automated ? "true" : "false";
43709
- if (params.filters.body) query.body = params.filters.body;
43710
- if (params.filters.domainId) query.domain_id = params.filters.domainId;
43711
- if (params.filters.from) query.from = params.filters.from;
43712
- if (params.filters.hasAttachment !== void 0) query.has_attachment = params.filters.hasAttachment ? "true" : "false";
43713
- if (params.filters.spamScoreGte !== void 0) query.spam_score_gte = params.filters.spamScoreGte;
43714
- if (params.filters.spamScoreLt !== void 0) query.spam_score_lt = params.filters.spamScoreLt;
43715
- if (params.filters.replyToSentEmailId) query.reply_to_sent_email_id = params.filters.replyToSentEmailId;
43716
- if (params.filters.subject) query.subject = params.filters.subject;
43717
- if (params.filters.to) query.to = params.filters.to;
43718
- if (params.since) query.date_from = params.since;
43719
- if (params.cursor) query.cursor = params.cursor;
43720
- return query;
43721
- }
43722
- function encodeReceivedAtSearchCursor(email) {
43723
- const raw = `r|${new Date(email.received_at).toISOString()}|${email.id}`;
43724
- return Buffer.from(raw, "utf8").toString("base64url");
43725
- }
43726
- function cursorFromRows(rows) {
43727
- const last = rows.at(-1);
43728
- return last ? encodeReceivedAtSearchCursor(last) : null;
43729
- }
43730
- function cursorFromAcceptedRows(rows) {
43731
- for (let i = rows.length - 1; i >= 0; i--) {
43732
- const row = rows[i];
43733
- if (row.status === "accepted" || row.status === "completed") return encodeReceivedAtSearchCursor(row);
43734
- }
43735
- return null;
43736
- }
43737
- function collectNewAcceptedEmails(rows, seenIds) {
43738
- const fresh = [];
43739
- for (const row of rows) {
43740
- if (row.status !== "accepted" && row.status !== "completed") continue;
43741
- if (seenIds.has(row.id)) continue;
43742
- seenIds.add(row.id);
43743
- fresh.push(row);
43744
- }
43745
- return fresh;
43746
- }
43747
- async function fetchEmailSearchPage(params) {
43748
- const result = await searchEmails({
43749
- client: params.apiClient.client,
43750
- query: buildEmailSearchQuery({
43751
- cursor: params.cursor,
43752
- filters: params.filters,
43753
- pageSize: params.pageSize,
43754
- since: params.since
43755
- }),
43756
- responseStyle: "fields"
43757
- });
43758
- const wantsReplyState = Boolean(params.filters.awaiting) || queryUsesAwaiting(params.filters.q);
43759
- const wantsAutomated = params.filters.automated !== void 0 || queryUsesAutomated(params.filters.q);
43760
- if (result.error) {
43761
- if (wantsReplyState && isAwaitingRejectedError(result.error)) throw awaitingRejectedError("GET /emails/search");
43762
- if (wantsAutomated && isAutomatedRejectedError(result.error)) throw automatedRejectedError("GET /emails/search");
43763
- return {
43764
- ok: false,
43765
- error: result.error
43766
- };
43767
- }
43768
- const envelope = result.data;
43769
- const rows = envelope?.data ?? [];
43770
- if (wantsReplyState) {
43771
- assertAwaitingFilterRows(rows, "GET /emails/search");
43772
- if (rows.length === 0) await ensureSearchReportsReplyState(params.apiClient);
43773
- }
43774
- if (wantsAutomated) {
43775
- assertAutomatedVerdict(rows, "GET /emails/search", expectedAutomatedVerdicts(params.filters.automated, params.filters.q));
43776
- if (rows.length === 0) await ensureSearchReportsAutomated(params.apiClient);
43777
- }
43778
- return {
43779
- ok: true,
43780
- cursor: envelope?.meta.cursor ?? cursorFromRows(rows),
43781
- rows
43782
- };
43783
- }
43784
- function sleep$2(ms) {
43785
- return new Promise((resolve) => setTimeout(resolve, ms));
43786
- }
43787
43691
  function cliError$6(message) {
43788
43692
  return new Errors.CLIError(message, { exit: 1 });
43789
43693
  }
@@ -45399,10 +45303,23 @@ async function waitForReply(params) {
45399
45303
  deadline: totalDeadline
45400
45304
  });
45401
45305
  let strictFilterUnsupported = false;
45306
+ let notBefore = 0;
45307
+ const holdRetryAfter = (failure) => {
45308
+ if (failure.retryAfterMs !== void 0) notBefore = Math.max(notBefore, Date.now() + failure.retryAfterMs);
45309
+ };
45402
45310
  for (const phase of phases) {
45403
45311
  if (phase.label === "strict" && strictFilterUnsupported) continue;
45312
+ if (notBefore > Date.now()) {
45313
+ const remaining = totalDeadline === null ? Number.POSITIVE_INFINITY : totalDeadline - Date.now();
45314
+ if (remaining <= notBefore - Date.now()) {
45315
+ await sleep$3(Math.max(0, remaining));
45316
+ return null;
45317
+ }
45318
+ await sleep$3(notBefore - Date.now());
45319
+ }
45404
45320
  const seenIds = /* @__PURE__ */ new Set();
45405
45321
  let cursor = null;
45322
+ let failures = 0;
45406
45323
  while (true) {
45407
45324
  if (phase.deadline !== null && Date.now() >= phase.deadline) break;
45408
45325
  const page = await fetchEmailSearchPage({
@@ -45413,14 +45330,25 @@ async function waitForReply(params) {
45413
45330
  since: params.sentAtIso
45414
45331
  });
45415
45332
  if (!page.ok) {
45333
+ const failure = transientFailure(page);
45334
+ if (failure) {
45335
+ if (!await pauseForTransientFailure(failure, failures, {
45336
+ deadline: phase.deadline,
45337
+ notice,
45338
+ onTransientFailure: holdRetryAfter
45339
+ })) break;
45340
+ failures += 1;
45341
+ continue;
45342
+ }
45416
45343
  const payload = extractErrorPayload(page.error);
45417
- writeErrorWithHints(payload);
45344
+ writeErrorWithHints(payload, page.response);
45418
45345
  surfaceUnauthorizedHint({
45419
45346
  ...params.authFailureContext,
45420
45347
  payload
45421
45348
  });
45422
45349
  throw new Errors.CLIError("Failed to poll for reply.", { exit: 1 });
45423
45350
  }
45351
+ failures = 0;
45424
45352
  let lastAccepted;
45425
45353
  for (let i = page.rows.length - 1; i >= 0; i--) {
45426
45354
  const row = page.rows[i];
@@ -45432,14 +45360,19 @@ async function waitForReply(params) {
45432
45360
  if (lastAccepted) cursor = encodeReceivedAtSearchCursor(lastAccepted);
45433
45361
  const matches = collectNewAcceptedEmails(page.rows, seenIds);
45434
45362
  for (const match of matches) {
45435
- const full = await getEmail({
45363
+ const full = await retryTransient(() => getEmail({
45436
45364
  client: params.apiClient.client,
45437
45365
  path: { id: match.id },
45438
45366
  responseStyle: "fields"
45367
+ }), {
45368
+ deadline: phase.deadline,
45369
+ notice,
45370
+ onTransientFailure: holdRetryAfter
45439
45371
  });
45372
+ if (full === null) break;
45440
45373
  if (full.error) {
45441
45374
  const payload = extractErrorPayload(full.error);
45442
- writeErrorWithHints(payload);
45375
+ writeErrorWithHints(payload, full.response);
45443
45376
  surfaceUnauthorizedHint({
45444
45377
  ...params.authFailureContext,
45445
45378
  payload
@@ -45463,7 +45396,7 @@ async function waitForReply(params) {
45463
45396
  if (lastAccepted !== void 0) continue;
45464
45397
  if (phase.deadline !== null && Date.now() >= phase.deadline) break;
45465
45398
  if (totalDeadline !== null && Date.now() >= totalDeadline) return null;
45466
- await sleep$2(params.interval * 1e3);
45399
+ await sleep$3(params.interval * 1e3);
45467
45400
  }
45468
45401
  }
45469
45402
  return null;
@@ -47286,7 +47219,7 @@ async function clearPendingAfterRead(configDir, emailId, known) {
47286
47219
  } : null);
47287
47220
  } catch {}
47288
47221
  }
47289
- const NO_SIGNAL_DESCRIPTION = "With --context, do not report working to the sender, and stop a working report an earlier read of this email started; nothing is sent. By default, reading mail from the verified owner or a same-organization member (not another agent) that a receiver surfaced to this session reports working in the background until you answer (also disabled by PRIMITIVE_NO_AUTO_SIGNALS=1).";
47222
+ const NO_SIGNAL_DESCRIPTION = "Do not report working to the sender, and stop a working report an earlier read of this email started; nothing is sent. Only a --context read reports working; on any other read this flag just stops the earlier report. By default, reading mail from the verified owner or a same-organization member (not another agent) that a receiver surfaced to this session reports working in the background until you answer (also disabled by PRIMITIVE_NO_AUTO_SIGNALS=1).";
47290
47223
  /**
47291
47224
  * The line a brief ends with once it has started reporting working: the
47292
47225
  * agent only knows whether it will act after reading, so the way out has to
@@ -47438,10 +47371,7 @@ function createEmailsGetCommand(base) {
47438
47371
  description: LINKS_DESCRIPTION,
47439
47372
  dependsOn: ["compact"]
47440
47373
  }),
47441
- "no-signal": Flags.boolean({
47442
- description: NO_SIGNAL_DESCRIPTION,
47443
- dependsOn: ["context"]
47444
- })
47374
+ "no-signal": Flags.boolean({ description: NO_SIGNAL_DESCRIPTION })
47445
47375
  };
47446
47376
  async run() {
47447
47377
  if (this.argv.includes("--brief")) {
@@ -47459,11 +47389,13 @@ function createEmailsGetCommand(base) {
47459
47389
  await runBrief(this, parsed);
47460
47390
  return;
47461
47391
  }
47392
+ if (parsed["no-signal"]) await haltAutoWorking(this.config.configDir, { emailIds: [parsed.id] }, "not_acting");
47462
47393
  if (parsed.links !== void 0 && !validLinksValue(parsed.links)) throw new Errors.CLIError("--links must be `all` or a comma list of link numbers, for example 1,2,3.", { exit: 2 });
47463
47394
  if (parsed.compact) {
47464
47395
  await runCompact(this, parsed);
47465
47396
  return;
47466
47397
  }
47398
+ this.argv = this.argv.filter((arg) => arg !== "--no-signal");
47467
47399
  const before = process.exitCode;
47468
47400
  await base.prototype.run.call(this);
47469
47401
  if (process.exitCode === before || process.exitCode === 0) await clearPendingAfterRead(this.config.configDir, parsed.id);
@@ -47623,7 +47555,7 @@ async function resolveScopedEmailWait(params) {
47623
47555
  const requestedTo = to === void 0 ? void 0 : exactAddress(to, "--to");
47624
47556
  if (Object.values(unsupported).some((value) => value !== void 0 && value !== false)) throw invalid$1("Connected email waits support exact --from, --to, and --reply-to-sent-email-id matching only; search, body, subject, domain, attachment, and spam filters are unavailable.");
47625
47557
  const sentId = replyToSentEmailId.toLowerCase();
47626
- const result = await readBeforeDeadline(params.deadline, (signal) => getSentEmail({
47558
+ const result = await readApiBeforeDeadline(params.deadline, (signal) => getSentEmail({
47627
47559
  signal,
47628
47560
  client: params.apiClient.client,
47629
47561
  path: { id: sentId },
@@ -47631,7 +47563,8 @@ async function resolveScopedEmailWait(params) {
47631
47563
  }));
47632
47564
  if (result === null) return null;
47633
47565
  const sent = result.data?.data;
47634
- if (result.error || !sent || sent.id !== sentId) throw invalid$1("Could not read that sent email with the connected credential. Inspect the existing send before retrying; do not send it again.");
47566
+ if (result.error) throw invalid$1(`Could not read that sent email with the connected credential: ${describeApiFailure(result)}. Inspect the existing send before retrying; do not send it again.`);
47567
+ if (!sent || sent.id !== sentId) throw invalid$1("Could not read that sent email with the connected credential. Inspect the existing send before retrying; do not send it again.");
47635
47568
  const ownAddress = exactAddress(sent.from_address, "The sent email's from_address");
47636
47569
  if (sent.from_header != null && sent.from_header !== "") {
47637
47570
  const header = typeof sent.from_header === "string" ? parseFromHeader(sent.from_header) : null;
@@ -47641,7 +47574,8 @@ async function resolveScopedEmailWait(params) {
47641
47574
  return {
47642
47575
  from: ownAddress,
47643
47576
  recipient,
47644
- sentId
47577
+ sentId,
47578
+ ...typeof sent.created_at === "string" ? { sentAt: sent.created_at } : {}
47645
47579
  };
47646
47580
  }
47647
47581
  //#endregion
@@ -47666,7 +47600,10 @@ var EmailsWaitCommand = class EmailsWaitCommand extends Command {
47666
47600
  Connected waits share an address event subscription and recover replies with
47667
47601
  exact-parent search. They never scan inbox history. Additional content
47668
47602
  filters. The command never sends mail. On timeout it exits 1; run the same
47669
- wait again to recover a reply to the existing send without resending it.`;
47603
+ wait again to recover a reply to the existing send without resending it.
47604
+ A rate limit (HTTP 429, honouring Retry-After), a 502, 503 or 504, or a
47605
+ network error during the wait is retried with backoff until --timeout,
47606
+ with one note on stderr per retry.`;
47670
47607
  static summary = "Wait for matching inbound emails";
47671
47608
  static examples = [
47672
47609
  "<%= config.bin %> emails wait --reply-to-sent-email-id <sent-id> --from peer@example.com",
@@ -47777,6 +47714,7 @@ var EmailsWaitCommand = class EmailsWaitCommand extends Command {
47777
47714
  const idWidth = pickIdWidth(Boolean(process.stdout.isTTY));
47778
47715
  const seenIds = /* @__PURE__ */ new Set();
47779
47716
  let cursor = null;
47717
+ let failures = 0;
47780
47718
  let matched = 0;
47781
47719
  let headerPrinted = false;
47782
47720
  const printEmail = (email) => {
@@ -47835,8 +47773,14 @@ var EmailsWaitCommand = class EmailsWaitCommand extends Command {
47835
47773
  throw error;
47836
47774
  }
47837
47775
  if (!page.ok) {
47776
+ const failure = transientFailure(page);
47777
+ if (failure) {
47778
+ if (!await pauseForTransientFailure(failure, failures, { deadline })) break;
47779
+ failures += 1;
47780
+ continue;
47781
+ }
47838
47782
  const payload = extractErrorPayload(page.error);
47839
- writeErrorWithHints(payload);
47783
+ writeErrorWithHints(payload, page.response);
47840
47784
  surfaceUnauthorizedHint({
47841
47785
  auth,
47842
47786
  baseUrlOverridden,
@@ -47846,6 +47790,7 @@ var EmailsWaitCommand = class EmailsWaitCommand extends Command {
47846
47790
  process.exitCode = 1;
47847
47791
  return;
47848
47792
  }
47793
+ failures = 0;
47849
47794
  const nextCursor = cursorFromAcceptedRows(page.rows);
47850
47795
  const cursorAdvanced = Boolean(nextCursor && nextCursor !== cursor);
47851
47796
  if (nextCursor) cursor = nextCursor;
@@ -47855,7 +47800,7 @@ var EmailsWaitCommand = class EmailsWaitCommand extends Command {
47855
47800
  }
47856
47801
  if (cursorAdvanced) continue;
47857
47802
  if (deadline !== null && Date.now() >= deadline) break;
47858
- await sleep$2(flags.interval * 1e3);
47803
+ await sleep$3(flags.interval * 1e3);
47859
47804
  }
47860
47805
  const message = `Timed out waiting for ${flags.number} matching email${flags.number === 1 ? "" : "s"}; received ${matched}.`;
47861
47806
  this.timedOut = {
@@ -47949,6 +47894,7 @@ var EmailsWatchCommand = class EmailsWatchCommand extends Command {
47949
47894
  const idWidth = pickIdWidth(Boolean(process.stdout.isTTY));
47950
47895
  const seenIds = /* @__PURE__ */ new Set();
47951
47896
  let cursor = null;
47897
+ let failures = 0;
47952
47898
  let printed = 0;
47953
47899
  let headerPrinted = false;
47954
47900
  while (deadline === null || Date.now() < deadline) {
@@ -47966,8 +47912,14 @@ var EmailsWatchCommand = class EmailsWatchCommand extends Command {
47966
47912
  throw error;
47967
47913
  }
47968
47914
  if (!page.ok) {
47915
+ const failure = transientFailure(page);
47916
+ if (failure) {
47917
+ if (!await pauseForTransientFailure(failure, failures, { deadline })) break;
47918
+ failures += 1;
47919
+ continue;
47920
+ }
47969
47921
  const payload = extractErrorPayload(page.error);
47970
- writeErrorWithHints(payload);
47922
+ writeErrorWithHints(payload, page.response);
47971
47923
  surfaceUnauthorizedHint({
47972
47924
  auth,
47973
47925
  baseUrlOverridden,
@@ -47977,6 +47929,7 @@ var EmailsWatchCommand = class EmailsWatchCommand extends Command {
47977
47929
  process.exitCode = 1;
47978
47930
  return;
47979
47931
  }
47932
+ failures = 0;
47980
47933
  const nextCursor = cursorFromAcceptedRows(page.rows);
47981
47934
  const cursorAdvanced = Boolean(nextCursor && nextCursor !== cursor);
47982
47935
  if (nextCursor) cursor = nextCursor;
@@ -47994,7 +47947,7 @@ var EmailsWatchCommand = class EmailsWatchCommand extends Command {
47994
47947
  }
47995
47948
  if (cursorAdvanced) continue;
47996
47949
  if (deadline !== null && Date.now() >= deadline) break;
47997
- await sleep$2(flags.interval * 1e3);
47950
+ await sleep$3(flags.interval * 1e3);
47998
47951
  }
47999
47952
  }
48000
47953
  };
@@ -49156,7 +49109,7 @@ const PRIMITIVE_TEAM_AUTHOR = {
49156
49109
  url: "https://primitive.dev"
49157
49110
  };
49158
49111
  const SDK_VERSION_RANGE = "^2.0.0";
49159
- const CLI_VERSION_RANGE = "^1.72.1";
49112
+ const CLI_VERSION_RANGE = "^1.73.0";
49160
49113
  const ESBUILD_VERSION_RANGE = "^0.27.0";
49161
49114
  function renderHandler() {
49162
49115
  return `// env.PRIMITIVE_API_KEY, env.PRIMITIVE_WEBHOOK_SECRET, and
@@ -50021,7 +49974,7 @@ var FunctionsLogsCommand = class FunctionsLogsCommand extends Command {
50021
49974
  return;
50022
49975
  }
50023
49976
  completedInitialFollowPoll = true;
50024
- await sleep$2(flags["poll-interval"] * 1e3);
49977
+ await sleep$3(flags["poll-interval"] * 1e3);
50025
49978
  }
50026
49979
  });
50027
49980
  }
@@ -50932,7 +50885,7 @@ var FunctionsTestFunctionCommand = class FunctionsTestFunctionCommand extends Co
50932
50885
  trace = fetched;
50933
50886
  break;
50934
50887
  }
50935
- await sleep$2(pollIntervalMs);
50888
+ await sleep$3(pollIntervalMs);
50936
50889
  }
50937
50890
  if (!trace) {
50938
50891
  const finalTrace = ((await getFunctionTestRunTrace({
@@ -51097,6 +51050,32 @@ const DEFAULT_API = {
51097
51050
  getEmail,
51098
51051
  listEmails
51099
51052
  };
51053
+ /**
51054
+ * The API for a wait: a rate limit, gateway failure or network error backs
51055
+ * off and reads again until the deadline (null: no deadline), then throws
51056
+ * WaitDeadlineReached. These are all reads, so a retry repeats nothing.
51057
+ */
51058
+ function waitingInboxApi(deadline, api = DEFAULT_API) {
51059
+ const options = { deadline };
51060
+ return {
51061
+ ...api,
51062
+ getConversation: retryingOperation(api.getConversation, options),
51063
+ getEmail: retryingOperation(api.getEmail, options),
51064
+ listEmails: retryingOperation(api.listEmails, options, (input) => {
51065
+ const query = input.query;
51066
+ if (deadline === null || query?.wait === void 0) return input;
51067
+ const remainingMs = deadline - Date.now();
51068
+ if (remainingMs <= 0) return null;
51069
+ return {
51070
+ ...input,
51071
+ query: {
51072
+ ...query,
51073
+ wait: Math.min(query.wait, Math.floor(remainingMs / 1e3))
51074
+ }
51075
+ };
51076
+ })
51077
+ };
51078
+ }
51100
51079
  async function listPage(api, apiClient, query) {
51101
51080
  let result = await api.listEmails({
51102
51081
  client: apiClient.client,
@@ -51416,7 +51395,7 @@ var InboxNextCommand = class InboxNextCommand extends Command {
51416
51395
 
51417
51396
  NOT A WORK QUEUE. Nothing is claimed or locked. Two agents running \`inbox next\` on the same inbox get the same email until one of them replies, and both may answer it. Run one agent per inbox, or coordinate outside Primitive.
51418
51397
 
51419
- --wait blocks until something awaits you. It takes the inbox's newest position before checking, then long-polls from that position, re-checking reply state whenever mail arrives and at least every 30 seconds, so nothing that arrives between the check and the wait is missed.
51398
+ --wait blocks until something awaits you. It takes the inbox's newest position before checking, then long-polls from that position, re-checking reply state whenever mail arrives and at least every 30 seconds, so nothing that arrives between the check and the wait is missed. A rate limit (HTTP 429, honouring Retry-After), a 502, 503 or 504, or a network error during the wait is retried with backoff until --timeout, with one note on stderr per retry; if it lasts until then, the wait exits 5 as if nothing arrived.
51420
51399
 
51421
51400
  --json prints one stable envelope (version 1): \`outcome\` ("email" | "empty" | "error"), \`email\` (id, thread_id, message_id, received_at, from, from_email, to, subject, awaiting, reply_count, last_replied_at, body_text, from_known_address, auth { spf, dmarc }), \`automated\` ({ automated, reasons[], automation_headers_known }, the server's verdict), \`conversation\` (thread_id, subject, message_count, truncated, messages[] with role user|assistant), \`reply_command\`, \`interaction\` ({ hint, kind, fyi, category, plain_reply_completes, no_reply_needed }, decided by the server from a DKIM-authenticated interaction part; null when not reported), \`next_actions\` (the commands that answer the email, best first: each has kind, command, argv, description, placeholders, requires_message; empty when no reply is needed or this CLI cannot answer the interaction), \`automated_awaiting\` ({ total, capped }: automated mail also awaiting a reply, on the empty outcome; null otherwise), and \`error\` ({ code, message }) on failure.
51422
51401
 
@@ -51481,12 +51460,17 @@ var InboxNextCommand = class InboxNextCommand extends Command {
51481
51460
  process.exitCode = INBOX_NEXT_EXIT_CODES.error;
51482
51461
  };
51483
51462
  const deadline = flags.wait && flags.timeout > 0 ? Date.now() + flags.timeout * 1e3 : null;
51463
+ const api = flags.wait ? waitingInboxApi(deadline) : void 0;
51484
51464
  try {
51485
- let since = flags.wait ? await baselineCursor({ apiClient }) : null;
51465
+ let since = flags.wait ? await baselineCursor({
51466
+ apiClient,
51467
+ api
51468
+ }) : null;
51486
51469
  let announcedWait = false;
51487
51470
  for (;;) {
51488
51471
  const result = await findNextAwaiting({
51489
51472
  apiClient,
51473
+ api,
51490
51474
  includeAutomated: flags["include-automated"]
51491
51475
  });
51492
51476
  if (result.outcome === "email" || !flags.wait || since === null) {
@@ -51510,12 +51494,20 @@ var InboxNextCommand = class InboxNextCommand extends Command {
51510
51494
  const pollStartedAt = Date.now();
51511
51495
  since = await waitForActivity({
51512
51496
  apiClient,
51497
+ api,
51513
51498
  since,
51514
51499
  seconds: Math.floor(remainingMs / 1e3)
51515
51500
  });
51516
51501
  if (since === before && Date.now() - pollStartedAt < 1e3) await sleep$1(1e3);
51517
51502
  }
51518
51503
  } catch (error) {
51504
+ if (error instanceof WaitDeadlineReached) {
51505
+ await this.printResult({
51506
+ outcome: "empty",
51507
+ automated_awaiting: null
51508
+ }, bin, flags, apiClient);
51509
+ return;
51510
+ }
51519
51511
  if (error instanceof ReplyStateUnsupportedError || error instanceof AutomatedFilterUnsupportedError) {
51520
51512
  fail(error.code, error.message);
51521
51513
  return;
@@ -53242,7 +53234,9 @@ async function runStandaloneListen(options) {
53242
53234
  const random = options.random ?? Math.random;
53243
53235
  const sleep = options.sleep ?? listenSleep;
53244
53236
  const stderr = options.stderr ?? process.stderr;
53245
- const signal = options.signal;
53237
+ const hard = options.signal;
53238
+ const receiving = options.stopReceiving ? AbortSignal.any([hard, options.stopReceiving]) : hard;
53239
+ let signal = receiving;
53246
53240
  const mode = options.mode ?? "stdout";
53247
53241
  const events = options.events;
53248
53242
  if (options.number !== void 0 && (!Number.isSafeInteger(options.number) || options.number < 1)) throw new ListenError("--number must be a positive integer.");
@@ -53399,6 +53393,7 @@ async function runStandaloneListen(options) {
53399
53393
  continue;
53400
53394
  }
53401
53395
  signal.throwIfAborted();
53396
+ signal = hard;
53402
53397
  let handled;
53403
53398
  try {
53404
53399
  handled = await options.handler(delivery, signal);
@@ -53440,6 +53435,7 @@ async function runStandaloneListen(options) {
53440
53435
  if (!(error instanceof RequestFailure) || error.status !== 409 || error.code !== "stale_delivery") throw error;
53441
53436
  stderr.write("Delivery ownership expired before confirmation; it may be delivered again.\n");
53442
53437
  }
53438
+ signal = receiving;
53443
53439
  }
53444
53440
  } catch (error) {
53445
53441
  if (!signal.aborted) throw error;
@@ -53794,14 +53790,16 @@ async function createWakeMail(options) {
53794
53790
  kind: "mail",
53795
53791
  context
53796
53792
  })) return outcome(false);
53797
- if (admission.kind === "request") pendingRequest = {
53798
- sender,
53799
- emailId: detail.id,
53800
- eventId,
53801
- decidedSenders: [...policy.members()],
53802
- context
53803
- };
53804
- else {
53793
+ if (admission.kind === "request") {
53794
+ if (pendingRequest) completePending();
53795
+ pendingRequest = {
53796
+ sender,
53797
+ emailId: detail.id,
53798
+ eventId,
53799
+ decidedSenders: [...policy.members()],
53800
+ context
53801
+ };
53802
+ } else {
53805
53803
  const wake = {
53806
53804
  wakeId: detail.id,
53807
53805
  senderRelation: admission.senderRelation,
@@ -53856,6 +53854,11 @@ const RESUME_LOCK_RETRY_MS = 4e3;
53856
53854
  * newer mail) waits for that newer mail before waking for the held one.
53857
53855
  */
53858
53856
  const HELD_WAKE_SETTLE_MS = 5e3;
53857
+ /**
53858
+ * After a wake, how long the listener keeps taking mail that is already
53859
+ * queued, so mail that arrived together is announced together.
53860
+ */
53861
+ const WAKE_DRAIN_MS = 1500;
53859
53862
  const MAIL_CHECK_RECORD_MS = 5e3;
53860
53863
  const RESUME_LOCK_RETRY_STEP_MS = 250;
53861
53864
  function isListenLockContention(error) {
@@ -54246,9 +54249,12 @@ var ListenCommand = class ListenCommand extends Command {
54246
54249
  });
54247
54250
  let timedOut = false;
54248
54251
  let lastMailCheckRecord = Number.NEGATIVE_INFINITY;
54252
+ const receiveWindow = new AbortController();
54253
+ const sharedNotify = Boolean(target && flags["notify-session"] && requestConfig);
54249
54254
  const timer = flags.timeout === void 0 ? void 0 : setTimeout(() => {
54250
54255
  timedOut = true;
54251
- controller.abort();
54256
+ receiveWindow.abort();
54257
+ if (sharedNotify) controller.abort();
54252
54258
  }, flags.timeout * 1e3);
54253
54259
  const cancel = () => controller.abort();
54254
54260
  process.on("SIGINT", cancel);
@@ -54292,6 +54298,7 @@ var ListenCommand = class ListenCommand extends Command {
54292
54298
  socketPath
54293
54299
  } : void 0,
54294
54300
  handler: wake?.handler ?? handler,
54301
+ stopReceiving: receiveWindow.signal,
54295
54302
  stderr: flags.wake ? new Writable({ write(_chunk, _encoding, done) {
54296
54303
  done();
54297
54304
  } }) : void 0,
@@ -54319,7 +54326,7 @@ var ListenCommand = class ListenCommand extends Command {
54319
54326
  for (;;) try {
54320
54327
  await runListen(settle ? {
54321
54328
  ...options,
54322
- signal: AbortSignal.any([controller.signal, settle])
54329
+ stopReceiving: AbortSignal.any([receiveWindow.signal, settle])
54323
54330
  } : options);
54324
54331
  break;
54325
54332
  } catch (error) {
@@ -54331,7 +54338,15 @@ var ListenCommand = class ListenCommand extends Command {
54331
54338
  }
54332
54339
  wake?.completed();
54333
54340
  if (settle?.aborted && !controller.signal.aborted) wake?.wakeHeld?.();
54334
- } while (wake && !wake.wakeId() && !wake.status() && !controller.signal.aborted);
54341
+ } while (wake && !wake.wakeId() && !wake.status() && !controller.signal.aborted && !receiveWindow.signal.aborted);
54342
+ if (wake && hookSessionId && (wake.wakeId() || wake.status()) && !controller.signal.aborted) try {
54343
+ await runListen({
54344
+ ...options,
54345
+ number: void 0,
54346
+ stopReceiving: AbortSignal.any([receiveWindow.signal, AbortSignal.timeout(WAKE_DRAIN_MS)])
54347
+ });
54348
+ wake.completed();
54349
+ } catch {}
54335
54350
  } else {
54336
54351
  const notify = options.notifySession;
54337
54352
  let expectedCwd;
@@ -54411,7 +54426,7 @@ var ListenCommand = class ListenCommand extends Command {
54411
54426
  configDir: this.config.configDir,
54412
54427
  ...auto
54413
54428
  });
54414
- } else if (controller.signal.aborted) process.exitCode = timedOut && flags.wake ? 0 : timedOut ? 2 : 130;
54429
+ } else if (controller.signal.aborted || timedOut) process.exitCode = timedOut && flags.wake ? 0 : timedOut ? 2 : 130;
54415
54430
  }
54416
54431
  };
54417
54432
  //#endregion
@@ -54673,7 +54688,7 @@ var ListenInitCommand = class ListenInitCommand extends Command {
54673
54688
  const UUID$3 = /^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$/i;
54674
54689
  var ListenPendingCommand = class ListenPendingCommand extends Command {
54675
54690
  static summary = "List mail a session's wake listener accepted but not yet read";
54676
- static description = `Prints the durable pending notices for one Claude Code session of the selected connected profile. A notice is written before its wake event is acknowledged and is removed when the session reads that exact email with \`primitive emails get --id <id>\`. Notices carry only server-derived metadata (sender, thread, whether this profile sent in the thread, newer-mail count), never subject or body. Status notices (kind status) name a peer signal on a message this session sent and have nothing to read; clear them with --clear after delivering them. Unread mail notices are never dropped: at 50 notices the list reports full and newer mail stays queued, unacknowledged, until some are read. Reading never takes the writer lock, so it works while a listener holds it.`;
54691
+ static description = `Prints the durable pending notices for one Claude Code session of the selected connected profile. A notice is written before its wake event is acknowledged and is removed when the session reads that exact email with \`primitive emails get --id <id>\`. Notices carry only server-derived metadata (sender, thread, whether this profile sent in the thread, newer-mail count), never subject or body. Status notices (kind status) name a peer signal on a message this session sent and have nothing to read; clear them with --clear after delivering them. --claim marks exact ids as announced to the session and prints the ids this call claimed as \`claimed\`; receive hooks use it so each email is announced at most once. Past 50 mail notices the oldest announced one gives way; mail the session has not been shown is never dropped, so when all 50 are unannounced the list reports full and newer mail stays queued, unacknowledged. Reading never takes the writer lock, so it works while a listener holds it.`;
54677
54692
  static examples = ["PRIMITIVE_AGENT_PROFILE=work <%= config.bin %> listen pending --session <claude-session-id>", "PRIMITIVE_AGENT_PROFILE=work <%= config.bin %> listen pending --session <claude-session-id> --clear <email-id>"];
54678
54693
  static flags = {
54679
54694
  session: Flags.string({ description: "Claude Code session ID (defaults to CLAUDE_CODE_SESSION_ID in a Claude session)" }),
@@ -54681,6 +54696,11 @@ var ListenPendingCommand = class ListenPendingCommand extends Command {
54681
54696
  multiple: true,
54682
54697
  description: "Remove these exact email IDs after delivering them (repeatable)"
54683
54698
  }),
54699
+ claim: Flags.string({
54700
+ multiple: true,
54701
+ exclusive: ["clear"],
54702
+ description: "Mark these exact email IDs as announced to the session and report which ones this call claimed (repeatable)"
54703
+ }),
54684
54704
  json: Flags.boolean({ description: "Print JSON (already the default)" })
54685
54705
  };
54686
54706
  async run() {
@@ -54693,6 +54713,9 @@ var ListenPendingCommand = class ListenPendingCommand extends Command {
54693
54713
  if (!session || !UUID$3.test(session)) this.error("Pass --session with the Claude Code session UUID.");
54694
54714
  const clear = flags.clear ?? [];
54695
54715
  if (clear.some((id) => !UUID$3.test(id))) this.error("--clear takes exact email UUIDs.");
54716
+ const claim = flags.claim ?? [];
54717
+ if (claim.some((id) => !UUID$3.test(id))) this.error("--claim takes exact email UUIDs.");
54718
+ const claimed = claim.length ? await claimPendingMail(this.config.configDir, profileName, session, claim) : void 0;
54696
54719
  const notices = clear.length ? await removePendingMail(this.config.configDir, profileName, session, clear) : readPendingMail(this.config.configDir, profileName, session);
54697
54720
  this.log(JSON.stringify({
54698
54721
  session_id: session.toLowerCase(),
@@ -54701,6 +54724,7 @@ var ListenPendingCommand = class ListenPendingCommand extends Command {
54701
54724
  read_command: wakeReadCommand("<id>", profileName),
54702
54725
  path: pendingMailPath(this.config.configDir, profileName, session),
54703
54726
  full: notices.length >= 50,
54727
+ ...claimed ? { claimed } : {},
54704
54728
  notices
54705
54729
  }, null, 2));
54706
54730
  }
@@ -54853,6 +54877,8 @@ function listenForCopyHotkey(params) {
54853
54877
  //#endregion
54854
54878
  //#region src/oclif/commands/login.ts
54855
54879
  const MAX_CLI_LOGIN_POLL_INTERVAL_SECONDS = 60;
54880
+ /** How long a login waits for an in-flight agent registration on this machine. */
54881
+ const REGISTRATION_WAIT_MS = 15e3;
54856
54882
  function cliError$3(message) {
54857
54883
  return new Errors.CLIError(message, { exit: 1 });
54858
54884
  }
@@ -54988,6 +55014,7 @@ var LoginCommand$1 = class extends Command {
54988
55014
  await this.runBrowserLogin(flags, this.retryCommand());
54989
55015
  }
54990
55016
  async runBrowserLogin(flags, retryCommand = this.retryCommand()) {
55017
+ await waitForRegistrations(this.config.configDir, REGISTRATION_WAIT_MS, { onWait: () => process.stderr.write("Waiting a few seconds for this machine's agent registration to finish before changing the login.\n") });
54991
55018
  let releaseCredentialsLock;
54992
55019
  try {
54993
55020
  releaseCredentialsLock = acquireCliCredentialsLock(this.config.configDir);
@@ -56275,7 +56302,7 @@ const TITLES = {
56275
56302
  "claude.settings_valid": "Claude Code settings file",
56276
56303
  "claude.hook.session_start": "Claude SessionStart hook",
56277
56304
  "claude.hook.session_end": "Claude SessionEnd hook",
56278
- "claude.hook.stop": "Claude per-session receive hooks",
56305
+ "claude.hook.stop": "Claude receive hooks",
56279
56306
  "claude.instructions": "Claude Code instructions",
56280
56307
  "codex.hook.session_start": "Codex SessionStart hook",
56281
56308
  "codex.instructions": "Codex instructions",
@@ -56711,7 +56738,11 @@ async function runMachineDoctor(options) {
56711
56738
  throw new MachineFileError(`The hook launcher ${cli.launcher?.path ?? ""} could not be written.`);
56712
56739
  }
56713
56740
  if (!repaired.changed.size) return id === "claude.hook.stop";
56714
- writeClaudeSettings({
56741
+ for (const item of repaired.receivers) addSessionReceiver(item.configDir, item.session, {
56742
+ profile: item.profile,
56743
+ address: item.address
56744
+ });
56745
+ if (JSON.stringify(repaired.settings) !== JSON.stringify(settingsRead.settings)) writeClaudeSettings({
56715
56746
  claudeDir: paths.claudeDir,
56716
56747
  read: settingsRead.read,
56717
56748
  settings: repaired.settings,
@@ -59593,7 +59624,7 @@ async function pollForSettlementInteraction(params) {
59593
59624
  }
59594
59625
  if (receipt) return receipt;
59595
59626
  if (deadline !== null && Date.now() >= deadline) break;
59596
- await sleep$2(params.intervalSeconds * 1e3);
59627
+ await sleep$3(params.intervalSeconds * 1e3);
59597
59628
  }
59598
59629
  return null;
59599
59630
  }
@@ -63270,8 +63301,8 @@ function setupChallengeIds(configDir, agent) {
63270
63301
  const id = savedSetupChallengeId(agentProfileDirectory(configDir, agent.profileName));
63271
63302
  return id ? [id] : [];
63272
63303
  }
63273
- async function listRows(apiClient, query) {
63274
- const result = await listEmails({
63304
+ async function listRows(api, apiClient, query) {
63305
+ const result = await api.listEmails({
63275
63306
  client: apiClient.client,
63276
63307
  query,
63277
63308
  responseStyle: "fields"
@@ -63283,8 +63314,8 @@ async function listRows(apiClient, query) {
63283
63314
  cursor: envelope?.meta?.cursor ?? null
63284
63315
  };
63285
63316
  }
63286
- async function readDetail(apiClient, id) {
63287
- const result = await getEmail({
63317
+ async function readDetail(api, apiClient, id) {
63318
+ const result = await api.getEmail({
63288
63319
  client: apiClient.client,
63289
63320
  path: { id },
63290
63321
  responseStyle: "fields"
@@ -63297,13 +63328,13 @@ async function readDetail(apiClient, id) {
63297
63328
  const detail = result.data?.data;
63298
63329
  return detail !== null && typeof detail === "object" ? detail : null;
63299
63330
  }
63300
- async function firstMatch(apiClient, rows, filters, seen) {
63331
+ async function firstMatch(api, apiClient, rows, filters, seen) {
63301
63332
  for (const row of rows) {
63302
63333
  const id = str(row.id);
63303
63334
  if (!id || seen.has(id)) continue;
63304
63335
  seen.add(id);
63305
63336
  if (!rowMayMatch(row, filters)) continue;
63306
- const detail = await readDetail(apiClient, id);
63337
+ const detail = await readDetail(api, apiClient, id);
63307
63338
  if (detail && detailMatches(detail, filters)) return detail;
63308
63339
  }
63309
63340
  return null;
@@ -63318,32 +63349,49 @@ function arrivedSince(row, threshold) {
63318
63349
  * the deadline.
63319
63350
  */
63320
63351
  async function waitForEmail(params) {
63352
+ const { deadline } = params;
63353
+ const api = waitingInboxApi(deadline, {
63354
+ getConversation,
63355
+ getEmail,
63356
+ listEmails
63357
+ });
63358
+ try {
63359
+ return await tailForEmail(api, params);
63360
+ } catch (error) {
63361
+ if (error instanceof WaitDeadlineReached) return null;
63362
+ throw error;
63363
+ }
63364
+ }
63365
+ async function tailForEmail(api, params) {
63321
63366
  const { apiClient, filters, deadline } = params;
63322
63367
  const seen = new Set(params.skipIds ?? []);
63323
- let since = await baselineCursor({ apiClient });
63324
- const recent = await listRows(apiClient, { limit: EXISTING_PAGE_SIZE });
63325
- const early = await firstMatch(apiClient, recent.rows.filter((row) => arrivedSince(row, params.startedAt)).reverse(), filters, seen);
63368
+ let since = await baselineCursor({
63369
+ apiClient,
63370
+ api
63371
+ });
63372
+ const recent = await listRows(api, apiClient, { limit: EXISTING_PAGE_SIZE });
63373
+ const early = await firstMatch(api, apiClient, recent.rows.filter((row) => arrivedSince(row, params.startedAt)).reverse(), filters, seen);
63326
63374
  if (early) return early;
63327
63375
  if (params.includeExisting) {
63328
- const found = await firstMatch(apiClient, recent.rows, filters, seen);
63376
+ const found = await firstMatch(api, apiClient, recent.rows, filters, seen);
63329
63377
  if (found) return found;
63330
63378
  }
63331
63379
  for (;;) {
63332
63380
  const remainingMs = deadline === null ? MAX_LONG_POLL_SECONDS * 1e3 : deadline - Date.now();
63333
63381
  if (remainingMs <= 0) return null;
63334
63382
  const startedAt = Date.now();
63335
- const page = await listRows(apiClient, {
63383
+ const page = await listRows(api, apiClient, {
63336
63384
  limit: TAIL_PAGE_SIZE,
63337
63385
  since,
63338
63386
  wait: Math.max(0, Math.min(MAX_LONG_POLL_SECONDS, Math.floor(remainingMs / 1e3)))
63339
63387
  });
63340
- const found = await firstMatch(apiClient, page.rows, filters, seen);
63388
+ const found = await firstMatch(api, apiClient, page.rows, filters, seen);
63341
63389
  if (found) return found;
63342
63390
  if (page.rows.length > 0 && page.cursor) {
63343
63391
  since = page.cursor;
63344
63392
  continue;
63345
63393
  }
63346
- if (Date.now() - startedAt < 1e3) await sleep$2(Math.max(0, Math.min(1e3, remainingMs)));
63394
+ if (Date.now() - startedAt < 1e3) await sleep$3(Math.max(0, Math.min(1e3, remainingMs)));
63347
63395
  }
63348
63396
  }
63349
63397
  function describeFilters(filters) {
@@ -63365,6 +63413,8 @@ Only mail that arrives after the command starts matches, unless --include-existi
63365
63413
 
63366
63414
  --code prints only the verification or one-time code, with spaces or dashes between its groups removed. --link prints only the most likely verification, sign-in, confirm, magic or reset link, with an obvious click-tracking wrapper removed. Without either, the email is printed: sender, subject, time, its ID and the start of its text, ready for \`primitive reply --id <id>\`. --json prints one object with id, thread_id, from, to, subject, received_at, text and, when asked, code and link (null when none was found).
63367
63415
 
63416
+ A rate limit (HTTP 429, honouring Retry-After), a 502, 503 or 504, or a network error during the wait is retried with backoff until --timeout, with one note on stderr per retry; if it lasts until then, the wait times out (exit 5).
63417
+
63368
63418
  Exit codes:
63369
63419
  - 0: a matching email arrived and was printed.
63370
63420
  - 1: error (API failure or authentication).
@@ -64118,10 +64168,10 @@ var WakeSchedulesUpdateCommand = class WakeSchedulesUpdateCommand extends Comman
64118
64168
  };
64119
64169
  //#endregion
64120
64170
  //#region src/oclif/commands/whoami.ts
64121
- function formatWhoamiSummary(account, managedInboxDomain) {
64171
+ function formatWhoamiSummary(account, managedInboxDomain, orgName = null) {
64122
64172
  const lines = [
64123
64173
  `Authenticated as ${account.email}`,
64124
- `Account id: ${account.id}`,
64174
+ orgName ? `Organization: ${orgName} (${account.id})` : `Organization id: ${account.id}`,
64125
64175
  `Plan: ${account.plan}`
64126
64176
  ];
64127
64177
  if (managedInboxDomain) lines.push(`Managed inbox: any-local-part@${managedInboxDomain}`);
@@ -64210,14 +64260,25 @@ var WhoamiCommand = class WhoamiCommand extends Command {
64210
64260
  });
64211
64261
  if (!domainsResult.error) managedInboxDomain = (domainsResult.data?.data ?? []).find((row) => row.verified && row.managed_zone !== null)?.domain ?? null;
64212
64262
  } catch {}
64263
+ const orgName = auth.credentials?.org_id === account.id ? auth.credentials.org_name ?? null : null;
64264
+ const session = guardedSession(void 0, process.env);
64265
+ let registration = null;
64266
+ try {
64267
+ registration = session ? failedSessionRegistration(this.config.configDir, session) : null;
64268
+ } catch {
64269
+ registration = null;
64270
+ }
64213
64271
  if (flags.json) {
64214
64272
  this.log(JSON.stringify({
64215
64273
  ...account,
64216
- managed_inbox_domain: managedInboxDomain
64274
+ managed_inbox_domain: managedInboxDomain,
64275
+ org_name: orgName,
64276
+ ...registration ? { session_registration: registration } : {}
64217
64277
  }, null, 2));
64218
64278
  return;
64219
64279
  }
64220
- this.log(formatWhoamiSummary(account, managedInboxDomain));
64280
+ this.log(formatWhoamiSummary(account, managedInboxDomain, orgName));
64281
+ if (registration) this.log(registrationSummaryLine(registration));
64221
64282
  });
64222
64283
  }
64223
64284
  };