primcli 1.48.0 → 1.50.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,13 +1,13 @@
1
1
  import { A as saveActiveChatState, C as resolveCliAuth, D as deleteChatState, E as chatStatePath, F as agentProfilesDirectory, H as requireDefaultLoginProfile, M as AgentConnectionSetupError, N as agentProfileDirectory, O as loadActiveChatState, P as agentProfileName, R as loadConnectedAgentProfile, T as saveSignupCredentials, W as PrimitiveApiClient, _ as deleteCliCredentials, a as normalizeCliEnvironmentName, b as hasStoredCliLogin, c as resolveConfigEnvironment, g as credentialsPath, h as credentialsLockPath, i as loadCliConfig, j as AGENT_PROFILE_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 } from "../cli-config-DGrZCUfw.js";
2
- import { $ as buildThrownSendFailureEnvelope, $n as stopRepeatFromEmail, $t as getAgentContactPolicy, A as readThreadContext, An as listWakeSchedules, At as queryUsesAutomated, B as recordPendingMail, Bn as resendAgentSignupVerification, Bt as createEndpoint, C as queryUsesAwaiting, Cn as listFunctionLogs, Ct as AutomatedFilterUnsupportedError, D as displayAddress, Dn as listSentEmails, Dt as expectedAutomatedVerdicts, E as describeWake, En as listRoutes, Et as ensureSearchReportsAutomated, F as wakeRecipientField, Ft as resolveCliApiRequestConfig, G as replyExpectation, Gn as sendEmail, H as interactionHumanLine, Hn as searchEmails, Ht as createRoute, I as wakeRelationship, In as redeemCreditCode, It as addDefaultNetworkMember, J as IDEMPOTENCY_KEY_FLAG_DESCRIPTION, Jn as setMemory, Jt as deleteRoute, K as replyInteractionWarning, Kn as setFunctionRoute, L as clearReadPendingMail, Ln as removeDefaultNetworkMember, Lt as checkDefaultNetworkContactAdmission, M as serverMuted, Mn as pullWebhookEvent, Mt as createAuthenticatedCliApiClient, N as serverRelationship, Nt as createCliApiClient, O as formatWakeContext, On as listWakeAuthorizations, Ot as hasAutomatedVerdict, P as wakeReadCommand, Pt as refreshStoredCliCredentials, Q as buildFollowUpCommand, Qn as startCliLogin, Qt as getAccount, R as pendingMailPath, Rn as reorderRoutes, Rt as cliLogout, S as isAwaitingRejectedError, Sn as listEndpoints, St as AUTOMATED_VALUES, T as bareAddress, Tn as listRepeatingSends, Tt as automatedRejectedError, U as interactionNextActions, Un as searchMemories, Ut as createWakeAuthorization, V as removePendingMail, Vn as runWakeSchedule, Vt as createFunction, W as readEmailInteraction, Wn as semanticSearch, Wt as createWakeSchedule, X as apiResultHttpStatus, Xn as startAgentClaim, Xt as deleteWakeSchedule, Y as SEND_OUTCOME_HELP, Yn as simulateRoute, Yt as deleteWakeAuthorization, Z as assertValidIdempotencyKey, Zn as startAgentSignup, _ as awaitingRejectedError, _t as formatAlreadySentNotice, a as extractErrorCode, an as getFunction, ar as updateRoute, at as formatPriorRepliesWarning, b as formatRepliesCell, bn as listDomains, bt as AUTOMATED_FILTER_UNSUPPORTED_CODE, c as readTextFileFlag, cn as getInboxStatus, cr as verifyAgentClaim, ct as priorRepliesThatWentOut, d as writeErrorWithHints, dn as getRepeatingSend, dt as sendOutcomeExitCode, er as testFunction, et as checkPriorReplies, f as AWAITING_FLAG_DESCRIPTION, fn as getSentEmail, ft as sentHistoryWindowStart, g as assertAwaitingFilterRows, gn as listAgentNetworks, gt as currentMailSessionKey, h as ReplyStateUnsupportedError, hn as listAgentContacts, ht as thrownErrorExitCode, i as createOperationCommand, in as getEmail, ir as updateRepeatingSend, it as formatPriorRepliesCheckSkipped, j as sentInThread, jn as pollCliLogin, k as latestOwnOutbound, kn as listWakeDispatches, kt as isAutomatedRejectedError, l as runWithTiming, ln as getMemory, lr as verifyAgentSignup, lt as reportSendCommandResult, m as REPLY_STATE_UNSUPPORTED_CODE, mn as getWakeSchedule, mt as successfulSendOutcome, n as API_ERROR_CODES, nn as getCreditBalance, nr as updateDefaultNetworkMember, nt as deriveSendIdempotencyKey, o as extractErrorPayload, on as getFunctionRouting, or as updateWakeAuthorization, ot as formatSendFailureSummary, p as AWAITING_VALUES, pn as getThread, pt as serializeErrorPayload, q as wakeInteractionSentence, qn as setFunctionSecret, qt as deleteMemory, r as TIME_FLAG_DESCRIPTION, rn as getDefaultNetworkAgent, rr as updateFunction, rt as formatDeletedEarlierSendNotice, s as formatErrorPayload, sn as getFunctionTestRunTrace, sr as updateWakeSchedule, st as formatSendRecordFailureSummary, t as API_BASE_URL_FLAG_DESCRIPTION, tn as getConversation, tr as unsetFunctionRoute, tt as classifySendError, u as surfaceUnauthorizedHint, un as getOrgRoutingTopology, ut as sendIdentityFields, v as ensureSearchReportsReplyState, vn as listDefaultNetworkAgents, vt as writeIdempotentReplayBannerIfReplay, w as explainPendingMailNotFound, wn as listFunctions, wt as assertAutomatedVerdict, x as hasReplyState, xn as listEmails, xt as AUTOMATED_FLAG_DESCRIPTION, y as formatAwaitingCell, yn as listDefaultNetworkMembers, yt as withFlagSuggestion, z as readPendingMail, zn as replyToEmail, zt as completeWebhookEvent } from "../api-command-DzQ8KxD9.js";
2
+ import { $ as replyExpectation, $n as searchMemories, $t as createWakeAuthorization, A as readThreadContext, An as listDomains, At as AUTOMATED_FILTER_UNSUPPORTED_CODE, B as cliInvocation, Bn as listWakeSchedules, Bt as queryUsesAutomated, C as queryUsesAwaiting, Cn as getThread, Ct as serializeErrorPayload, D as displayAddress, Dt as formatAlreadySentNotice, E as describeWake, En as listAgentNetworks, Et as currentMailSessionKey, F as wakeReadCommand, Fn as listRepeatingSends, Ft as automatedRejectedError, G as clearReadPendingMail, Gt as resolveCliApiRequestConfig, Hn as pullWebhookEvent, Ht as createAuthenticatedCliApiClient, I as wakeRecipientField, In as listRoutes, It as ensureSearchReportsAutomated, J as recordPendingMail, Jn as reorderRoutes, Jt as cliLogout, K as pendingMailPath, Kn as redeemCreditCode, Kt as addDefaultNetworkMember, L as wakeRelationship, Ln as listSentEmails, Lt as expectedAutomatedVerdicts, M as serverMuted, Mn as listEndpoints, Mt as AUTOMATED_VALUES, N as serverRelationship, Nn as listFunctionLogs, Nt as AutomatedFilterUnsupportedError, O as formatWakeContext, On as listDefaultNetworkAgents, Ot as writeIdempotentReplayBannerIfReplay, P as skillFirstLine, Pn as listFunctions, Pt as assertAutomatedVerdict, Q as readEmailInteraction, Qn as searchEmails, Qt as createRoute, Rn as listWakeAuthorizations, Rt as hasAutomatedVerdict, S as isAwaitingRejectedError, Sn as getSentEmail, St as sentHistoryWindowStart, T as bareAddress, Tn as listAgentContacts, Tt as thrownErrorExitCode, U as generatedAgentName, Ut as createCliApiClient, V as connectNextSteps, Vn as pollCliLogin, W as identitySuggestions, Wt as refreshStoredCliCredentials, X as interactionHumanLine, Xn as resendAgentSignupVerification, Xt as createEndpoint, Y as removePendingMail, Yn as replyToEmail, Yt as completeWebhookEvent, Z as interactionNextActions, Zn as runWakeSchedule, Zt as createFunction, _ as awaitingRejectedError, _n as getFunctionTestRunTrace, _r as updateWakeSchedule, _t as priorRepliesThatWentOut, a as extractErrorCode, an as deleteWakeAuthorization, ar as simulateRoute, at as apiResultHttpStatus, b as formatRepliesCell, bn as getOrgRoutingTopology, bt as sendOutcomeExitCode, c as readTextFileFlag, cn as getAccount, cr as startCliLogin, ct as buildThrownSendFailureEnvelope, d as writeErrorWithHints, dn as getConversation, dr as unsetFunctionRoute, dt as deriveSendIdempotencyKey, en as createWakeSchedule, er as semanticSearch, et as replyInteractionWarning, f as AWAITING_FLAG_DESCRIPTION, fn as getCreditBalance, fr as updateDefaultNetworkMember, ft as formatDeletedEarlierSendNotice, g as assertAwaitingFilterRows, gn as getFunctionRouting, gr as updateWakeAuthorization, gt as formatSendRecordFailureSummary, h as ReplyStateUnsupportedError, hn as getFunction, hr as updateRoute, ht as formatSendFailureSummary, i as createOperationCommand, in as deleteRoute, ir as setMemory, it as SEND_OUTCOME_HELP, j as sentInThread, jn as listEmails, jt as AUTOMATED_FLAG_DESCRIPTION, k as latestOwnOutbound, kn as listDefaultNetworkMembers, kt as withFlagSuggestion, l as runWithTiming, ln as getAgentContactPolicy, lr as stopRepeatFromEmail, lt as checkPriorReplies, m as REPLY_STATE_UNSUPPORTED_CODE, mn as getEmail, mr as updateRepeatingSend, mt as formatPriorRepliesWarning, n as API_ERROR_CODES, nr as setFunctionRoute, nt as IDEMPOTENCY_KEY_FLAG_DESCRIPTION, o as extractErrorPayload, on as deleteWakeSchedule, or as startAgentClaim, ot as assertValidIdempotencyKey, p as AWAITING_VALUES, pn as getDefaultNetworkAgent, pr as updateFunction, pt as formatPriorRepliesCheckSkipped, q as readPendingMail, qn as removeDefaultNetworkMember, qt as checkDefaultNetworkContactAdmission, r as TIME_FLAG_DESCRIPTION, rn as deleteMemory, rr as setFunctionSecret, rt as MAX_SEND_WAIT_TIMEOUT_MS, s as formatErrorPayload, sr as startAgentSignup, st as buildFollowUpCommand, t as API_BASE_URL_FLAG_DESCRIPTION, tr as sendEmail, tt as wakeInteractionSentence, u as surfaceUnauthorizedHint, ur as testFunction, ut as classifySendError, v as ensureSearchReportsReplyState, vn as getInboxStatus, vr as verifyAgentClaim, vt as reportSendCommandResult, w as explainPendingMailNotFound, wn as getWakeSchedule, wt as successfulSendOutcome, x as hasReplyState, xn as getRepeatingSend, xt as sendWaitClampNotice, y as formatAwaitingCell, yn as getMemory, yr as verifyAgentSignup, yt as sendIdentityFields, z as LOAD_SKILL_LINE, zn as listWakeDispatches, zt as isAutomatedRejectedError } from "../api-command-Ci6eyQ8d.js";
3
3
  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-SPPcis9g.js";
4
- import { $ as describeSessionHookItem, A as NetworkAdmissionPendingError, B as runContactRequest, C as pollCheckCommand, D as verificationReplySubmitted, E as RECEIVER_MODES, F as addressNoteTarget, G as receiverStatusCommand, H as agentInvitationHash, I as runAddressNotesRequest, J as recordHookMailCheck, K as savedReceiver, L as ContactsApiError, M as evaluateContactPolicy, N as canonicalContactSelector, O as ContactPolicyReadRetryError, P as AddressNotesApiError, Q as describeSessionHookChange, R as contactAddress, S as invitationProfileName, T as withOwnerMemberAddress, U as connectAgent, V as agentConnectionStatus, W as readAgentInvitation, X as claudeConfigDir, Y as boundSessionProfiles, Z as currentCliLocation, _ as disconnectAgent, a as endSession, at as samePath, b as identitySuggestions, c as pendingSessionDisconnects, ct as inspectManagedBlock, d as registerSession, dt as upsertManagedBlock, et as ephemeralCliReason, f as retryPendingDisconnects, ft as writeManagedFile, g as AgentDisconnectError, h as enrollmentResumes, i as connectedProfilesForSession, it as repairClaudeHooks, j as createNotificationContactPolicy, k as NETWORK_ADMISSION_PENDING_RETRY_MS, l as psProcessInfo, lt as jsonIndentation, m as enrollAgent, n as OMP_MAIN, nt as inspectClaudeHooks, o as headlessClaudeRun, ot as writeClaudeSettings, p as runDetached, q as installClaudeWakeHook, r as agentConnectionState, rt as readClaudeSettings, st as MachineFileError, t as MACHINE_RUNTIMES, tt as findOnPath, u as readClaudeHookInput, ut as readManagedFile, v as cliInvocation, w as runAgentConnect, x as defaultAgentProfileName, y as generatedAgentName, z as contactAgentAddress } from "../machine-session-BaJ1Xmdm.js";
5
- import { _ as NativeSessionDisconnectedError, a as readBundledConnectSkill, b as NotificationOutcomeUnknownError, c as openSessionNotifications, d as isRoutineNotificationContent, f as notificationPartReader, g as defaultSessionSocket, i as installedVersion, l as notificationReceiptPage, m as SESSION_UUID$1, o as notificationScope, p as readConversationStatusContent, r as installConnectSkill, s as notificationSenders, t as connectSkillTarget, u as NotificationRetryError, v as NativeSessionError, y as NativeSessionNotLoadedError } from "../connect-skill-DHPc9dVN.js";
6
- import { c as startBackgroundListen, i as backgroundListenToken, l as stopBackgroundListen, o as runBackgroundListen, r as backgroundListenStatus, u as verifyBackgroundListenTarget } from "../listen-background-CyLc8VBn.js";
7
- import { a as REPEAT_IDLE_MAX_MINUTES, d as parseRepeatTick, f as preparePresenceAliveEmail, g as isEmailReceivedEvent, 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 parseWebhookEvent, y as parseFromHeader } from "../repeats-D2xtLium-DdiJECLI.js";
8
- import { a as ensureSharedMailSubscription, c as reserveSharedMailSubscription, d as otherParticipants, f as EventConnection, h as pushFile, i as sharedMailScope, l as followEmailConversation, m as pullFile, n as reconcileChatSend, o as createSharedMailWaiter, p as EventReceiverError, r as openSharedMailReceiver, s as openSharedMailStore, t as sendSignal, u as readConversationFollow } from "../signal-command-BbeV2Nd8.js";
9
- 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-DhxtuNXs.js";
10
- import { autoSignalEligible, dispatchAutoRead, dispatchAutoWorking, haltAutoWorking, restoreAutoWorking } from "./auto-signals.js";
4
+ import { $ as describeSessionHookItem, A as evaluateContactPolicy, B as agentInvitationHash, C as RECEIVER_MODES, D as NETWORK_ADMISSION_PENDING_RETRY_MS, E as ContactPolicyReadRetryError, F as ContactsApiError, G as saveConnectionName, H as readAgentInvitation, I as contactAddress, J as recordHookMailCheck, K as savedReceiver, L as contactAgentAddress, M as AddressNotesApiError, N as addressNoteTarget, O as NetworkAdmissionPendingError, P as runAddressNotesRequest, Q as describeSessionHookChange, R as runContactRequest, S as runAgentConnect, T as verificationReplySubmitted, U as receiverStatusCommand, V as connectAgent, W as refusalAfterReplacement, X as claudeConfigDir, Y as boundSessionProfiles, Z as currentCliLocation, _ as disconnectAgent, _t as withOwnerMemberAddress, a as endSession, at as readClaudeSettings, b as invitationProfileName, c as pendingSessionDisconnects, ct as writeClaudeSettings, d as registerSession, dt as jsonIndentation, et as ensureHookLauncher, f as retryPendingDisconnects, ft as readManagedFile, g as AgentDisconnectError, gt as refreshOwnerMemberAddressPeriodically, h as enrollmentResumes, ht as readHookLauncherWarning, i as connectedProfilesForSession, it as inspectClaudeHooks, j as canonicalContactSelector, k as createNotificationContactPolicy, l as psProcessInfo, lt as MachineFileError, m as enrollAgent, mt as writeManagedFile, n as OMP_MAIN, nt as findOnPath, o as headlessClaudeRun, ot as repairClaudeHooks, p as runDetached, pt as upsertManagedBlock, q as installClaudeWakeHook, r as agentConnectionState, rt as hasMachineSessionHooks, st as samePath, t as MACHINE_RUNTIMES, tt as ephemeralCliReason, u as readClaudeHookInput, ut as inspectManagedBlock, v as connectWarnings, w as externalReceivingState, x as pollCheckCommand, y as defaultAgentProfileName, z as agentConnectionStatus } from "../machine-session-CY0j2r7S.js";
5
+ 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-DSLrmgWQ.js";
6
+ import { _ as NativeSessionDisconnectedError, a as readBundledConnectSkill, b as NotificationOutcomeUnknownError, c as openSessionNotifications, d as isRoutineNotificationContent, f as notificationPartReader, g as defaultSessionSocket, i as installedVersion, l as notificationReceiptPage, m as SESSION_UUID$1, o as notificationScope, p as readConversationStatusContent, r as installConnectSkill, s as notificationSenders, t as connectSkillTarget, u as NotificationRetryError, v as NativeSessionError, y as NativeSessionNotLoadedError } from "../connect-skill-xtf3Q5IF.js";
7
+ import { c as startBackgroundListen, i as backgroundListenToken, l as stopBackgroundListen, o as runBackgroundListen, r as backgroundListenStatus, u as verifyBackgroundListenTarget } from "../listen-background-CMfxkeVP.js";
8
+ import { a as REPEAT_IDLE_MAX_MINUTES, d as parseRepeatTick, f as preparePresenceAliveEmail, g as isEmailReceivedEvent, 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 parseWebhookEvent, y as parseFromHeader } from "../repeats-D2xtLium-B8Wq41vG.js";
9
+ import { a as ensureSharedMailSubscription, c as reserveSharedMailSubscription, d as otherParticipants, f as EventConnection, h as pushFile, i as sharedMailScope, l as followEmailConversation, m as pullFile, n as reconcileChatSend, o as createSharedMailWaiter, p as EventReceiverError, r as openSharedMailReceiver, s as openSharedMailStore, t as sendSignal, u as readConversationFollow } from "../signal-command-D9R7d44k.js";
10
+ import { autoSignalEligible, dispatchAutoRead, dispatchAutoWorking, haltAutoWorking, isSentSignal, restoreAutoWorking } from "./auto-signals.js";
11
11
  import { t as guardJsonOutputCommands } from "../json-output-Cf-GFeff.js";
12
12
  import { Args, Command, Errors, Flags, ux } from "@oclif/core";
13
13
  import { chmodSync, closeSync, constants, cpSync, existsSync, fstatSync, fsyncSync, linkSync, lstatSync, mkdirSync, openSync, readFileSync, readSync, readdirSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync } from "node:fs";
@@ -12255,6 +12255,14 @@ const openapiDocument = {
12255
12255
  "user_id",
12256
12256
  "name"
12257
12257
  ]
12258
+ },
12259
+ "fyi": {
12260
+ "type": "boolean",
12261
+ "description": "Outbound messages only. True when the send was an informational signal (a read, working or typing signal, or an acknowledgement) and nothing else, so it is not a reply that takes part in the conversation. Absent on inbound messages. Older servers omit it.\n"
12262
+ },
12263
+ "interaction_hint": {
12264
+ "type": "string",
12265
+ "description": "Outbound messages only. How to place this send in a timeline: `status` (a pure status signal), `card` or `none`. Not declared as a closed enum so that a value added later does not fail decoding; treat an unknown value as `none`. Absent on inbound messages. Older servers omit it.\n"
12258
12266
  }
12259
12267
  },
12260
12268
  "required": ["direction", "id"]
@@ -12360,6 +12368,14 @@ const openapiDocument = {
12360
12368
  "user_id",
12361
12369
  "name"
12362
12370
  ]
12371
+ },
12372
+ "fyi": {
12373
+ "type": "boolean",
12374
+ "description": "Outbound messages only. True when the send was an informational signal (a read, working or typing signal, or an acknowledgement) and nothing else, so it is not a reply that takes part in the conversation. Absent on inbound messages. Older servers omit it.\n"
12375
+ },
12376
+ "interaction_hint": {
12377
+ "type": "string",
12378
+ "description": "Outbound messages only. How to place this send in a timeline: `status` (a pure status signal), `card` or `none`. Not declared as a closed enum so that a value added later does not fail decoding; treat an unknown value as `none`. Absent on inbound messages. Older servers omit it.\n"
12363
12379
  }
12364
12380
  },
12365
12381
  "required": [
@@ -22848,6 +22864,14 @@ const operationManifest = [
22848
22864
  "user_id",
22849
22865
  "name"
22850
22866
  ]
22867
+ },
22868
+ "fyi": {
22869
+ "type": "boolean",
22870
+ "description": "Outbound messages only. True when the send was an informational signal (a read, working or typing signal, or an acknowledgement) and nothing else, so it is not a reply that takes part in the conversation. Absent on inbound messages. Older servers omit it.\n"
22871
+ },
22872
+ "interaction_hint": {
22873
+ "type": "string",
22874
+ "description": "Outbound messages only. How to place this send in a timeline: `status` (a pure status signal), `card` or `none`. Not declared as a closed enum so that a value added later does not fail decoding; treat an unknown value as `none`. Absent on inbound messages. Older servers omit it.\n"
22851
22875
  }
22852
22876
  },
22853
22877
  "required": [
@@ -34266,6 +34290,14 @@ const operationManifest = [
34266
34290
  "user_id",
34267
34291
  "name"
34268
34292
  ]
34293
+ },
34294
+ "fyi": {
34295
+ "type": "boolean",
34296
+ "description": "Outbound messages only. True when the send was an informational signal (a read, working or typing signal, or an acknowledgement) and nothing else, so it is not a reply that takes part in the conversation. Absent on inbound messages. Older servers omit it.\n"
34297
+ },
34298
+ "interaction_hint": {
34299
+ "type": "string",
34300
+ "description": "Outbound messages only. How to place this send in a timeline: `status` (a pure status signal), `card` or `none`. Not declared as a closed enum so that a value added later does not fail decoding; treat an unknown value as `none`. Absent on inbound messages. Older servers omit it.\n"
34269
34301
  }
34270
34302
  },
34271
34303
  "required": ["direction", "id"]
@@ -35252,9 +35284,25 @@ function readCursor(path) {
35252
35284
  } catch {}
35253
35285
  return null;
35254
35286
  }
35255
- /** Setup challenges and presence probes come from the control address. */
35256
- function isControlMail(email, identity) {
35257
- return email.presence_control !== void 0 || email.sender.trim().toLowerCase() === identity.ownerAddress.trim().toLowerCase();
35287
+ /**
35288
+ * Mail the CLI handles itself: a presence probe whose authenticated
35289
+ * projection marks it as control mail (verified, or pending while its proof
35290
+ * settles; a rejected one is ordinary mail), and the exact setup challenge
35291
+ * this profile's setup recorded. Nothing is judged by sender or subject: the
35292
+ * owner can write from the control address, and that email is listed like
35293
+ * any other.
35294
+ */
35295
+ function isControlMail(email, setupChallengeId) {
35296
+ return presenceDisposition(email) !== "ordinary" || setupChallengeId !== null && email.id === setupChallengeId;
35297
+ }
35298
+ /** The setup challenge's email ID saved by this profile's setup, if any. */
35299
+ function savedSetupChallengeId(directory) {
35300
+ try {
35301
+ const id = readMailJson(join(directory, "setup.json"))?.challenge?.id;
35302
+ return typeof id === "string" && id.length > 0 ? id : null;
35303
+ } catch {
35304
+ return null;
35305
+ }
35258
35306
  }
35259
35307
  async function checkAgentMail(options) {
35260
35308
  const { identity } = options;
@@ -35263,9 +35311,14 @@ async function checkAgentMail(options) {
35263
35311
  const release = acquireListenLock(directory, "mail-check");
35264
35312
  const readCommand = (id) => `PRIMITIVE_AGENT_PROFILE=${identity.profileName} ${options.invocation ?? "primitive"} emails get --id ${id} --brief`;
35265
35313
  const to = identity.agentAddress.toLowerCase();
35314
+ const ownerMember = (options.ownerMemberAddress ?? (() => refreshOwnerMemberAddressPeriodically({
35315
+ configDir: options.configDir,
35316
+ profileName: identity.profileName
35317
+ })))().catch(() => identity.ownerMemberAddress ?? null);
35266
35318
  try {
35267
35319
  const path = join(directory, CURSOR_FILE);
35268
35320
  const saved = readCursor(path);
35321
+ const setupChallenge = savedSetupChallengeId(directory);
35269
35322
  let cursor = saved;
35270
35323
  const emails = [];
35271
35324
  let controlSkipped = 0;
@@ -35285,7 +35338,7 @@ async function checkAgentMail(options) {
35285
35338
  });
35286
35339
  if (result.error || !result.data) throw new MailCheckApiError(result.error);
35287
35340
  const rows = result.data.data ?? [];
35288
- for (const row of rows) if (isControlMail(row, identity)) controlSkipped++;
35341
+ for (const row of rows) if (isControlMail(row, setupChallenge)) controlSkipped++;
35289
35342
  else emails.push({
35290
35343
  id: row.id,
35291
35344
  received_at: row.received_at,
@@ -35300,10 +35353,12 @@ async function checkAgentMail(options) {
35300
35353
  more = page === maxPages - 1;
35301
35354
  }
35302
35355
  const output = {
35356
+ ...emails.length > 0 ? { guidance: LOAD_SKILL_LINE } : {},
35303
35357
  outcome: emails.length > 0 ? "mail" : "empty",
35304
35358
  emails,
35305
35359
  more,
35306
35360
  control_skipped: controlSkipped,
35361
+ owner_member_address: await ownerMember,
35307
35362
  profile: identity.profileName,
35308
35363
  to,
35309
35364
  read_command: readCommand("<id>")
@@ -35328,9 +35383,9 @@ var AgentCheckMailCommand = class AgentCheckMailCommand extends Command {
35328
35383
  static summary = "Check a connected agent's mail since its last check";
35329
35384
  static description = `Print the mail that reached the selected connected agent profile since its previous check, oldest first, once, without waiting. This is how an agent connected with poll receiving (no local session ID or hooks, so nothing can wake it) receives mail: run it at the start of each turn and after sending, then read each email with its \`read_command\`, which selects this profile: an email is readable only under the profile that received it.
35330
35385
 
35331
- Acknowledgements marked fyi and mail in muted threads are left out. Setup and presence mail from the connection's control address is handled by the CLI and only counted. The position is saved privately with the profile and moves forward only after mail was read, so mail is reported again rather than lost when a check fails or is interrupted; deduplicate by email ID. The first check starts before the address's first email. \`more: true\` means more new mail remains: handle these and check again.
35386
+ Acknowledgements marked fyi and mail in muted threads are left out. Presence probes and this profile's setup challenge are handled by the CLI and only counted in \`control_skipped\`; any other email from the connection's control address, such as one the owner wrote from it, is listed like any other email. The position is saved privately with the profile and moves forward only after mail was read, so mail is reported again rather than lost when a check fails or is interrupted; deduplicate by email ID. The first check starts before the address's first email. \`more: true\` means more new mail remains: handle these and check again.
35332
35387
 
35333
- Requires a connected agent profile selected with ${AGENT_PROFILE_ENV}. Output is one JSON document: \`outcome\` ("mail" | "empty"), \`emails\` (id, received_at, sender, thread_id, to, and the read_command that reads that email under this profile; never subject or body), \`more\`, \`control_skipped\`, \`profile\`, \`to\` (the address this profile receives for) and \`read_command\` (the template with <id>).`;
35388
+ Requires a connected agent profile selected with ${AGENT_PROFILE_ENV}. Output is one JSON document: \`guidance\` (present only with mail: one line to load the primitive-connect skill before handling it), \`outcome\` ("mail" | "empty"), \`emails\` (id, received_at, sender, thread_id, to, and the read_command that reads that email under this profile; never subject or body), \`more\`, \`control_skipped\`, \`owner_member_address\` (the owner's personal address, where reports and questions go, or null when none is known; refreshed from the server every few minutes), \`profile\`, \`to\` (the address this profile receives for) and \`read_command\` (the template with <id>).`;
35334
35389
  static examples = [`${AGENT_PROFILE_ENV}=connection-0123456789ab <%= config.bin %> agent check-mail --json`];
35335
35390
  static flags = { json: Flags.boolean({ description: "Print JSON (already the default)" }) };
35336
35391
  async run() {
@@ -35489,7 +35544,7 @@ function invocation$1(entry) {
35489
35544
  return entry && /[\\/]_npx[\\/]/.test(entry) ? "npx -y primitive@latest" : "primitive";
35490
35545
  }
35491
35546
  var AgentConnectCommand = class AgentConnectCommand extends Command {
35492
- 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, and prints one JSON result. The receiver defaults to external hooks in Claude Code and the native background listener elsewhere. 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: 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, or with PRIMITIVE_AGENT_PROFILE set, to inspect saved identity and local receiver health offline; it exits 1 when the profile is not configured.`;
35547
+ 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, 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: 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, or with PRIMITIVE_AGENT_PROFILE set, to inspect saved identity and local receiver health offline; it exits 1 when the profile is not configured. 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.`;
35493
35548
  static summary = "Connect and verify an agent address";
35494
35549
  static examples = [
35495
35550
  "<%= config.bin %> agent connect --session \"$CODEX_THREAD_ID\" --name Research --info \"Reviews pull requests\" --json < private-invitation.txt",
@@ -35552,6 +35607,7 @@ var AgentConnectCommand = class AgentConnectCommand extends Command {
35552
35607
  async run() {
35553
35608
  const { flags } = await this.parse(AgentConnectCommand);
35554
35609
  let pollProfile;
35610
+ let replaced = [];
35555
35611
  try {
35556
35612
  if (flags.status) {
35557
35613
  const profileName = flags.profile ?? (process.env["PRIMITIVE_AGENT_PROFILE"]?.trim() || void 0);
@@ -35583,7 +35639,6 @@ var AgentConnectCommand = class AgentConnectCommand extends Command {
35583
35639
  invitationText ??= await readAgentInvitation(process.stdin, process.stdin.isTTY);
35584
35640
  return invitationText;
35585
35641
  };
35586
- let replaced = [];
35587
35642
  let replaceExisting;
35588
35643
  const guardSession = flags.resume ? null : flags.session !== void 0 ? session?.toLowerCase() ?? null : guardedSession(void 0);
35589
35644
  if (guardSession && !flags["keep-existing"]) {
@@ -35644,13 +35699,25 @@ var AgentConnectCommand = class AgentConnectCommand extends Command {
35644
35699
  });
35645
35700
  const external = output.receiving.mode === "external";
35646
35701
  const poll = output.receiving.mode === "poll";
35702
+ const identity = identitySuggestions({
35703
+ invocation: invocation$1(process.argv[1]),
35704
+ profile: output.profile,
35705
+ ..."nameIsDefault" in output ? { nameIsDefault: output.nameIsDefault } : {},
35706
+ connectedNow: output.status === "connected"
35707
+ });
35708
+ const nextSteps = output.status === "connected" ? connectNextSteps({
35709
+ address: output.address,
35710
+ receiving: output.receiving,
35711
+ ..."name" in output ? { name: output.name } : {},
35712
+ suggestions: identity.suggestions
35713
+ }) : [];
35647
35714
  const suggested = {
35648
35715
  ...output,
35649
- ...identitySuggestions({
35650
- invocation: invocation$1(process.argv[1]),
35651
- profile: output.profile,
35652
- connectedNow: output.status === "connected"
35653
- })
35716
+ ...identity,
35717
+ ...nextSteps.length ? {
35718
+ nextSteps,
35719
+ guidance: `${output.guidance} Next: ${nextSteps.join(" ")}`
35720
+ } : {}
35654
35721
  };
35655
35722
  if (flags.json) this.log(JSON.stringify(replaced.length ? {
35656
35723
  ...suggested,
@@ -35659,10 +35726,18 @@ var AgentConnectCommand = class AgentConnectCommand extends Command {
35659
35726
  else {
35660
35727
  this.log(`Agent ${output.address}: verification ${output.verification.state}; receiving ${output.receiving.state}; skill ${output.skill.state}.`);
35661
35728
  this.log(`Select it with ${output.selectProfile}.`);
35729
+ for (const warning of output.warnings) this.log(warning.message);
35662
35730
  if (output.ownerNotifications === "silenced") this.log("Owner notifications remain silenced by the existing preference or policy.");
35663
35731
  if (external && verificationReplySubmitted(output.verification.state)) this.log(output.externalHook === "installed_unverified" ? "External receive hook installed. Idle wake still needs a live mail check." : "External receive hook is unavailable. Pairing may complete, but this session will not wake automatically.");
35732
+ if (poll && "fallbackDetail" in output.receiving) this.log(String(output.receiving.fallbackDetail));
35664
35733
  if (poll && "checkCommand" in output.receiving) this.log(`Nothing wakes this session for new mail. Check it at the start of each turn and after sending with: ${output.receiving.checkCommand}`);
35665
35734
  if (output.status !== "connected") this.log(`Resume: ${output.resumeCommand}`);
35735
+ if (nextSteps.length) {
35736
+ this.log("Next steps:");
35737
+ nextSteps.forEach((step, index) => {
35738
+ this.log(`${index + 1}. ${step}`);
35739
+ });
35740
+ }
35666
35741
  }
35667
35742
  if (external && output.externalHook !== "installed_unverified" || !external && !poll && output.receiving.state !== "healthy" || !verificationReplySubmitted(output.verification.state)) process.exitCode = 2;
35668
35743
  return;
@@ -35680,16 +35755,23 @@ var AgentConnectCommand = class AgentConnectCommand extends Command {
35680
35755
  configDir: this.config.configDir,
35681
35756
  onlyIfUnknown: claimed.status === "claimed"
35682
35757
  });
35758
+ const warnings = connectWarnings(this.config.configDir, result.identity.profileName);
35683
35759
  if (flags.json) this.log(JSON.stringify(replaced.length ? {
35684
35760
  ...result,
35761
+ warnings,
35685
35762
  replacedExisting: replaced
35686
- } : result));
35763
+ } : {
35764
+ ...result,
35765
+ warnings
35766
+ }));
35687
35767
  else {
35688
35768
  this.log(result.status === "claimed" ? "Agent profile saved. Email readiness is not yet verified." : "Agent profile already configured; no claim was sent.");
35689
35769
  this.log(`Select it with PRIMITIVE_AGENT_PROFILE=${result.identity.profileName}.`);
35690
35770
  this.log(result.ownerReportGuidance);
35771
+ for (const warning of warnings) this.log(warning.message);
35691
35772
  }
35692
- } catch (error) {
35773
+ } catch (caught) {
35774
+ const error = refusalAfterReplacement(caught, replaced);
35693
35775
  throw new Errors.CLIError(error instanceof AgentConnectionSetupError ? error.message : flags.session?.trim() ? `Setup paused. Preserve the private profile and run ${invocation$1(process.argv[1])} agent connect --profile ${flags.profile ?? defaultAgentProfileName(flags.session.trim())} --session ${flags.session.trim()}${flags.receiver ? ` --receiver ${flags.receiver}` : ""} --resume --json. Do not manually resend verification or reclaim the invitation.` : pollProfile ? `Setup paused. Preserve the private profile and run ${invocation$1(process.argv[1])} agent connect --profile ${pollProfile} --receiver poll --resume --json. Do not manually resend verification or reclaim the invitation.` : "Agent setup did not complete. Preserve the private profile and request a fresh owner invitation if a claim may have been submitted.", { exit: 1 });
35694
35776
  }
35695
35777
  }
@@ -35975,6 +36057,7 @@ var AgentEnrollCommand = class AgentEnrollCommand extends Command {
35975
36057
  agentAddress: result.identity.agentAddress,
35976
36058
  sessionId: flags.session
35977
36059
  }) : null;
36060
+ const warnings = connectWarnings(this.config.configDir, result.identity.profileName);
35978
36061
  const output = result.receiving.state === "poll" ? {
35979
36062
  ...result,
35980
36063
  receiving: {
@@ -35982,10 +36065,20 @@ var AgentEnrollCommand = class AgentEnrollCommand extends Command {
35982
36065
  mode: "poll",
35983
36066
  checkCommand: pollCheckCommand(invocation(process.argv[1]), result.identity.profileName)
35984
36067
  },
35985
- externalHook
36068
+ externalHook,
36069
+ warnings
36070
+ } : flags.receiver === "external" && result.connection.status !== "owner_inactive" ? {
36071
+ ...result,
36072
+ receiving: {
36073
+ ...result.receiving,
36074
+ state: externalReceivingState(externalHook)
36075
+ },
36076
+ externalHook,
36077
+ warnings
35986
36078
  } : {
35987
36079
  ...result,
35988
- externalHook
36080
+ externalHook,
36081
+ warnings
35989
36082
  };
35990
36083
  const identity = identitySuggestions({
35991
36084
  invocation: invocation(process.argv[1]),
@@ -35993,18 +36086,33 @@ var AgentEnrollCommand = class AgentEnrollCommand extends Command {
35993
36086
  nameIsDefault: generatedAgentName(result.name),
35994
36087
  connectedNow: result.connection.status === "connected"
35995
36088
  });
35996
- const printed = replaced.length ? {
36089
+ const nextSteps = result.connection.status === "connected" ? connectNextSteps({
36090
+ address: result.identity.agentAddress,
36091
+ receiving: {
36092
+ state: output.receiving.state,
36093
+ mode: "mode" in output.receiving ? String(output.receiving.mode) : flags.receiver === "external" ? "external" : "native"
36094
+ },
36095
+ name: result.name,
36096
+ suggestions: identity.suggestions
36097
+ }) : [];
36098
+ const guided = nextSteps.length ? {
35997
36099
  ...output,
35998
36100
  ...identity,
35999
- replacedExisting: replaced
36101
+ nextSteps,
36102
+ guidance: `${output.guidance} Next: ${nextSteps.join(" ")}`
36000
36103
  } : {
36001
36104
  ...output,
36002
36105
  ...identity
36003
36106
  };
36107
+ const printed = replaced.length ? {
36108
+ ...guided,
36109
+ replacedExisting: replaced
36110
+ } : guided;
36004
36111
  if (flags.json) this.log(JSON.stringify(printed));
36005
36112
  else {
36006
- this.log(`Agent ${result.identity.agentAddress}: pairing ${result.connection.status}; verification ${result.verification.state}; receiving ${result.receiving.state}.`);
36113
+ this.log(`Agent ${result.identity.agentAddress}: pairing ${result.connection.status}; verification ${result.verification.state}; receiving ${output.receiving.state}.`);
36007
36114
  this.log(`Select it with PRIMITIVE_AGENT_PROFILE=${result.identity.profileName}.`);
36115
+ for (const warning of warnings) this.log(warning.message);
36008
36116
  if (flags["contact-requests"]) this.log(`Contact requests: ${result.contactRequestPolicy}.`);
36009
36117
  if (result.contactRequestPolicy === "owner_disabled") this.log("The owner disabled contact requests for this address. Review the policy in the app if you want them enabled.");
36010
36118
  if (result.contactRequestPolicy === "unavailable") this.log("Contact-request policy could not be confirmed. Receiving can still be configured; rerun this exact enrollment after policy access is restored.");
@@ -36013,6 +36121,12 @@ var AgentEnrollCommand = class AgentEnrollCommand extends Command {
36013
36121
  if (result.connection.status !== "connected") this.log("Pairing is not yet confirmed. Rerun this command with the same options to resume the saved session; do not create another address.");
36014
36122
  else if ("checkCommand" in output.receiving) this.log(`Nothing wakes this session for new mail. Check it at the start of each turn and after sending with: ${output.receiving.checkCommand}`);
36015
36123
  else if (result.receiving.state !== "healthy") this.log("Pairing is confirmed; receiving needs separate setup or recovery.");
36124
+ if (nextSteps.length) {
36125
+ this.log("Next steps:");
36126
+ nextSteps.forEach((step, index) => {
36127
+ this.log(`${index + 1}. ${step}`);
36128
+ });
36129
+ }
36016
36130
  }
36017
36131
  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;
36018
36132
  } catch (error) {
@@ -36293,6 +36407,8 @@ var AgentRenameCommand = class AgentRenameCommand extends Command {
36293
36407
  address,
36294
36408
  name
36295
36409
  });
36410
+ const own = auth.connectedAgent;
36411
+ if (own && own.agentAddress.toLowerCase() === connection.address.toLowerCase()) saveConnectionName(this.config.configDir, own.profileName, connection.name);
36296
36412
  if (flags.json) this.log(JSON.stringify({ connection }, null, 2));
36297
36413
  else this.log(`Renamed ${connection.address} to "${connection.name}". The address is unchanged.`);
36298
36414
  } catch (error) {
@@ -36629,6 +36745,66 @@ var AgentSessionRegisterCommand = class AgentSessionRegisterCommand extends Comm
36629
36745
  }
36630
36746
  };
36631
36747
  //#endregion
36748
+ //#region src/oclif/commands/agent-status.ts
36749
+ /**
36750
+ * Picks the profile `agent status` reads: an explicit --profile, then
36751
+ * PRIMITIVE_AGENT_PROFILE, then the one address connected for this runtime
36752
+ * session. Null when none applies or the session has several addresses.
36753
+ */
36754
+ function statusProfile(params) {
36755
+ const env = params.env ?? process.env;
36756
+ const chosen = params.profile ?? (env["PRIMITIVE_AGENT_PROFILE"]?.trim() || void 0);
36757
+ if (chosen) return { profile: chosen };
36758
+ const session = guardedSession(void 0, env);
36759
+ if (!session) return {
36760
+ profile: null,
36761
+ bound: []
36762
+ };
36763
+ const { others } = inspectSessionAddresses({
36764
+ configDir: params.configDir,
36765
+ session
36766
+ });
36767
+ const only = others.length === 1 ? others[0] : void 0;
36768
+ return only ? { profile: only.profile } : {
36769
+ profile: null,
36770
+ bound: others.map((row) => row.profile)
36771
+ };
36772
+ }
36773
+ /** A hidden alias of `agent connect --status`, for the command agents guess. */
36774
+ var AgentStatusCommand = class AgentStatusCommand extends Command {
36775
+ static hidden = true;
36776
+ static summary = "Show this agent's saved connection (agent connect --status)";
36777
+ static description = `Same as \`agent connect --status\`: read the saved identity and local receiver health offline. The profile is --profile, else ${AGENT_PROFILE_ENV}, else the one address connected for this runtime session.`;
36778
+ static flags = {
36779
+ profile: Flags.string({ description: "Local agent profile name" }),
36780
+ json: Flags.boolean({ description: "Print the status as JSON" })
36781
+ };
36782
+ async run() {
36783
+ const { flags } = await this.parse(AgentStatusCommand);
36784
+ const picked = statusProfile({
36785
+ configDir: this.config.configDir,
36786
+ profile: flags.profile
36787
+ });
36788
+ if (picked.profile === null) {
36789
+ const detail = picked.bound.length > 1 ? `This session has several connected profiles (${picked.bound.join(", ")}). Pass --profile <name>.` : `No Primitive address is connected for this session. Pass --profile <name> or set ${AGENT_PROFILE_ENV} to inspect a saved profile.`;
36790
+ this.log(flags.json ? JSON.stringify({
36791
+ status: "not_configured",
36792
+ profileName: null,
36793
+ ...picked.bound.length > 1 ? { profiles: picked.bound } : {},
36794
+ detail
36795
+ }) : detail);
36796
+ process.exitCode = 1;
36797
+ return;
36798
+ }
36799
+ await AgentConnectCommand.run([
36800
+ "--status",
36801
+ "--profile",
36802
+ picked.profile,
36803
+ ...flags.json ? ["--json"] : []
36804
+ ], this.config);
36805
+ }
36806
+ };
36807
+ //#endregion
36632
36808
  //#region src/oclif/commands/agent-upgrade.ts
36633
36809
  /**
36634
36810
  * Interactive upgrade of an emailless agent account to a full developer
@@ -41505,7 +41681,7 @@ async function buildEmailBrief(input) {
41505
41681
  connected_agent_verified: detail.sender_connected_agent_verified === true
41506
41682
  },
41507
41683
  thread_id: threadId,
41508
- in_thread: sentInThread(thread, self) ?? null,
41684
+ in_thread: sentInThread(thread, self, input.isOwnSignal) ?? null,
41509
41685
  ...alsoAddressed(otherParticipants(detail, self)),
41510
41686
  attachments: briefAttachments(detail, { hideInteractionPart: interaction?.hint === "card" || interaction?.hint === "status" }),
41511
41687
  newer: thread?.newerInboundCount === void 0 ? null : {
@@ -41614,6 +41790,7 @@ async function runBrief(command, flags) {
41614
41790
  client: apiClient.client,
41615
41791
  detail,
41616
41792
  connected,
41793
+ isOwnSignal: (sentId) => isSentSignal(command.config.configDir, sentId),
41617
41794
  signal: AbortSignal.timeout(3e4)
41618
41795
  });
41619
41796
  command.log(flags.json ? JSON.stringify(brief, null, 2) : renderEmailBrief(brief));
@@ -43317,7 +43494,7 @@ const PRIMITIVE_TEAM_AUTHOR = {
43317
43494
  url: "https://primitive.dev"
43318
43495
  };
43319
43496
  const SDK_VERSION_RANGE = "^1.35.0";
43320
- const CLI_VERSION_RANGE = "^1.48.0";
43497
+ const CLI_VERSION_RANGE = "^1.50.0";
43321
43498
  const ESBUILD_VERSION_RANGE = "^0.27.0";
43322
43499
  function renderHandler() {
43323
43500
  return `// env.PRIMITIVE_API_KEY, env.PRIMITIVE_WEBHOOK_SECRET, and
@@ -46848,6 +47025,7 @@ async function runSharedNotificationListen(options) {
46848
47025
  contact: !authorization?.contactRequest
46849
47026
  }),
46850
47027
  localInThread: false,
47028
+ isOwnSignal: (sentId) => isSentSignal(options.configDir, sentId),
46851
47029
  signal: nextSignal
46852
47030
  });
46853
47031
  } catch {
@@ -47563,6 +47741,10 @@ async function createWakeMail(options) {
47563
47741
  });
47564
47742
  const identity = auth.connectedAgent;
47565
47743
  const recipient = identity?.agentAddress;
47744
+ if (identity) refreshOwnerMemberAddressPeriodically({
47745
+ configDir: options.configDir,
47746
+ profileName: identity.profileName
47747
+ });
47566
47748
  const policy = recipient ? apiContactPolicy(apiClient.client, recipient, options.contactRequests) : void 0;
47567
47749
  const notices = identity && options.contactRequests ? openContactRequestNotices(options.configDir, identity) : void 0;
47568
47750
  const activatedAt = notices ? Date.parse(notices.activate()) : 0;
@@ -47799,6 +47981,7 @@ async function createWakeMail(options) {
47799
47981
  contact: admission.kind === "allowed"
47800
47982
  }),
47801
47983
  localInThread: Boolean(requested || followed),
47984
+ isOwnSignal: (sentId) => isSentSignal(options.configDir, sentId),
47802
47985
  signal
47803
47986
  });
47804
47987
  if (!await recordNotice(detail, {
@@ -48390,7 +48573,8 @@ var ListenCommand = class ListenCommand extends Command {
48390
48573
  const context = wake.context?.();
48391
48574
  const metadata = context ? ` ${formatWakeContext(context)}` : "";
48392
48575
  const interaction = wakeInteractionSentence(context?.interaction);
48393
- process.stderr.write(`Primitive mail arrived: ${wake.wakeId()}${recipient}${metadata}. Read with ${wakeReadCommand(wake.wakeId() ?? "", hookProfileName)}.${interaction} ${authority}\n`);
48576
+ const skillFirst = skillFirstLine(relation ?? context?.relationship);
48577
+ process.stderr.write(`${skillFirst ? `${skillFirst}\n` : ""}Primitive mail arrived: ${wake.wakeId()}${recipient}${metadata}. Read with ${wakeReadCommand(wake.wakeId() ?? "", hookProfileName)}.${interaction} ${authority}\n`);
48394
48578
  process.exitCode = 2;
48395
48579
  const auto = wake.autoSignal?.();
48396
48580
  if (auto) dispatchAutoRead({
@@ -49848,7 +50032,7 @@ function shellQuote(value) {
49848
50032
  }
49849
50033
  const MANAGED_SUFFIX = /\bagent session-register --runtime codex --hook\s*$/;
49850
50034
  function codexHookCommand(cli) {
49851
- return `${shellQuote(cli.node)} ${shellQuote(cli.entry)} agent session-register --runtime codex --hook`;
50035
+ return `${shellQuote(cli.runtimeNode)} ${shellQuote(cli.entry)} agent session-register --runtime codex --hook`;
49852
50036
  }
49853
50037
  /** A SessionStart hook this CLI installed, from any CLI path or version. */
49854
50038
  function isManaged(hook) {
@@ -50074,6 +50258,10 @@ function repairCodexHook(settings, cli) {
50074
50258
  changed
50075
50259
  };
50076
50260
  }
50261
+ /** Whether Codex hooks.json carries the SessionStart hook, from any CLI path. */
50262
+ function hasCodexSessionHook(settings) {
50263
+ return managedPositions(settings).length > 0;
50264
+ }
50077
50265
  function writeCodexHooks(params) {
50078
50266
  const original = params.read.state === "present" ? params.read.text : null;
50079
50267
  const indent = original === null ? 2 : jsonIndentation(original);
@@ -50312,6 +50500,29 @@ async function ownerConnectionStatuses(credentials, fetchImpl) {
50312
50500
  }
50313
50501
  return partial();
50314
50502
  }
50503
+ /** Whether any saved agent profile still holds a credential. */
50504
+ function connectedProfileSaved(configDir) {
50505
+ let names;
50506
+ try {
50507
+ names = readdirSync(join(agentProfilesDirectory(configDir), "profiles"));
50508
+ } catch {
50509
+ return false;
50510
+ }
50511
+ return names.some((name) => {
50512
+ try {
50513
+ agentProfileName(name);
50514
+ return loadConnectedAgentProfile(configDir, name) !== null;
50515
+ } catch {
50516
+ return false;
50517
+ }
50518
+ });
50519
+ }
50520
+ /**
50521
+ * Why a machine-wide check does not apply: agents on this machine were
50522
+ * connected one session at a time with `agent connect`, and no member login
50523
+ * (which machine-wide session registration needs) is saved.
50524
+ */
50525
+ const PER_CONNECTION_SKIP = "Not set up: agents on this machine were connected one session at a time with `primitive agent connect`, which does not need it. To register every session on this machine automatically, sign in with `primitive login`, then run `primitive machine doctor --fix`.";
50315
50526
  function check(id, status, detail, extra = {}) {
50316
50527
  return {
50317
50528
  id,
@@ -50336,9 +50547,21 @@ async function runMachineDoctor(options) {
50336
50547
  const selected = (runtime) => !options.runtimes || options.runtimes.has(runtime);
50337
50548
  const present = Object.fromEntries(MACHINE_RUNTIMES.map((runtime) => [runtime, runtimePresent(runtime, paths, env)]));
50338
50549
  const skipRuntime = (runtime) => !selected(runtime) ? "Not selected with --runtime." : !present[runtime] ? `${runtime === "claude" ? "Claude Code" : runtime === "codex" ? "Codex" : "omp"} was not found on this machine.` : null;
50339
- const cli = currentCliLocation(options.cliEntry, env, options.execPath);
50550
+ const cli = currentCliLocation(options.cliEntry, env, options.execPath, {
50551
+ configDir: options.configDir,
50552
+ platform: options.platform
50553
+ });
50340
50554
  const ephemeral = cli ? ephemeralCliReason(cli.entry) : null;
50341
- const hookBlocked = !cli ? "This CLI's hook scripts were not found next to it." : ephemeral ? `This CLI runs from ${ephemeral}, which can be deleted; install it with \`npm install -g primitive\` before repairing hooks.` : null;
50555
+ const ephemeralBlocked = ephemeral ? `This CLI runs from ${ephemeral}, which can be deleted; install it with \`npm install -g primitive\` before repairing hooks.` : null;
50556
+ const hookBlocked = !cli ? "This CLI's hook scripts were not found next to it." : cli.launcher ? null : ephemeralBlocked;
50557
+ const codexBlocked = !cli ? "This CLI's hook scripts were not found next to it." : ephemeralBlocked;
50558
+ const perConnection = !(() => {
50559
+ try {
50560
+ return loadCliCredentials(options.configDir) !== null;
50561
+ } catch {
50562
+ return true;
50563
+ }
50564
+ })() && connectedProfileSaved(options.configDir);
50342
50565
  const skillEnv = {
50343
50566
  ...env,
50344
50567
  CLAUDE_CONFIG_DIR: paths.claudeDir,
@@ -50365,6 +50588,7 @@ async function runMachineDoctor(options) {
50365
50588
  path: target,
50366
50589
  action: "edit_file"
50367
50590
  });
50591
+ if (perConnection && (read.state === "absent" || inspectManagedBlock(read.text, body).state === "missing")) return check(id, "skip", PER_CONNECTION_SKIP, { path: target });
50368
50592
  if (read.state === "absent") return check(id, "fail", `${target} does not exist yet.`, {
50369
50593
  path: target,
50370
50594
  fixable: true
@@ -50409,6 +50633,7 @@ async function runMachineDoctor(options) {
50409
50633
  } catch {
50410
50634
  info = null;
50411
50635
  }
50636
+ if (!info && perConnection) return check(id, "skip", PER_CONNECTION_SKIP, { path: target });
50412
50637
  if (!info) return check(id, "fail", `Not installed at ${target}.`, {
50413
50638
  path: target,
50414
50639
  fixable: true
@@ -50467,12 +50692,20 @@ async function runMachineDoctor(options) {
50467
50692
  },
50468
50693
  restoreProfiles: options.profiles
50469
50694
  };
50695
+ const launcherMissing = () => !!cli?.launcher && settingsRead.ok && !existsSync(cli.launcher.path) && JSON.stringify(settingsRead.settings).includes(JSON.stringify(cli.launcher.path));
50470
50696
  const hookCheck = (id) => ({
50471
50697
  inspect: () => {
50472
50698
  const skip = skipRuntime("claude");
50473
50699
  if (skip) return check(id, "skip", skip);
50474
50700
  if (!settingsRead.ok) return check(id, "fail", "Claude settings.json is invalid; repair it first.", { path: join(paths.claudeDir, "settings.json") });
50475
- const finding = inspectClaudeHooks(settingsRead.settings, hookContext)[id];
50701
+ if (perConnection && id !== "claude.hook.stop" && !hasMachineSessionHooks(settingsRead.settings)) return check(id, "skip", PER_CONNECTION_SKIP, { path: join(paths.claudeDir, "settings.json") });
50702
+ const inspected = inspectClaudeHooks(settingsRead.settings, hookContext)[id];
50703
+ const finding = inspected.status === "fail" && launcherMissing() ? {
50704
+ ...inspected,
50705
+ detail: `${inspected.detail} The hook launcher ${cli?.launcher?.path} is missing; a repair writes it again.`
50706
+ } : inspected;
50707
+ const launcherWarning = id === "claude.hook.stop" && cli?.launcher ? readHookLauncherWarning(options.configDir) : null;
50708
+ if (launcherWarning && finding.status === "ok") return check(id, "warn", `${finding.detail} The last hook run reported: ${launcherWarning}`, { path: join(paths.claudeDir, "settings.json") });
50476
50709
  return check(id, finding.status, finding.detail, {
50477
50710
  fixable: finding.fixable,
50478
50711
  path: join(paths.claudeDir, "settings.json"),
@@ -50487,9 +50720,17 @@ async function runMachineDoctor(options) {
50487
50720
  repair: () => {
50488
50721
  if (!settingsRead.ok) return false;
50489
50722
  const findings = inspectClaudeHooks(settingsRead.settings, hookContext);
50490
- const ids = HOOK_CHECK_IDS.filter((hook) => (hook === id || !options.only || options.only.has(hook)) && findings[hook].status === "fail" && findings[hook].fixable);
50723
+ const machineHooksSkipped = perConnection && !hasMachineSessionHooks(settingsRead.settings);
50724
+ const ids = HOOK_CHECK_IDS.filter((hook) => (hook === "claude.hook.stop" || !machineHooksSkipped) && (hook === id || !options.only || options.only.has(hook)) && findings[hook].status === "fail" && findings[hook].fixable);
50491
50725
  const repaired = repairClaudeHooks(settingsRead.settings, hookContext, new Set(ids), { profiles: options.profiles });
50492
- if (!repaired.changed.size) return false;
50726
+ const restoreLauncher = launcherMissing();
50727
+ if (!repaired.changed.size && !restoreLauncher) return false;
50728
+ if (cli && hookBlocked === null) try {
50729
+ ensureHookLauncher(cli);
50730
+ } catch {
50731
+ throw new MachineFileError(`The hook launcher ${cli.launcher?.path ?? ""} could not be written.`);
50732
+ }
50733
+ if (!repaired.changed.size) return id === "claude.hook.stop";
50493
50734
  writeClaudeSettings({
50494
50735
  claudeDir: paths.claudeDir,
50495
50736
  read: settingsRead.read,
@@ -50512,17 +50753,21 @@ async function runMachineDoctor(options) {
50512
50753
  path: read.path,
50513
50754
  action: "edit_file"
50514
50755
  });
50756
+ if (perConnection && !hasCodexSessionHook(read.settings)) return check(id, "skip", PER_CONNECTION_SKIP, { path: read.path });
50515
50757
  const configToml = readManagedFile(join(paths.codexHome, "config.toml"));
50516
- const finding = inspectCodexHook(read, hookContext, configToml.state === "present" ? configToml.text : null);
50758
+ const finding = inspectCodexHook(read, {
50759
+ cli,
50760
+ blocked: codexBlocked
50761
+ }, configToml.state === "present" ? configToml.text : null);
50517
50762
  return check(id, finding.status, finding.detail, {
50518
50763
  fixable: finding.fixable,
50519
50764
  path: read.path,
50520
- ...finding.status === "fail" && !finding.fixable && hookBlocked ? { action: "install_cli" } : {}
50765
+ ...finding.status === "fail" && !finding.fixable && codexBlocked ? { action: "install_cli" } : {}
50521
50766
  });
50522
50767
  },
50523
50768
  repair: () => {
50524
50769
  const read = readCodexHooks(paths.codexHome);
50525
- if (!read.ok || !cli || hookBlocked) return false;
50770
+ if (!read.ok || !cli || codexBlocked) return false;
50526
50771
  const repaired = repairCodexHook(read.settings, cli);
50527
50772
  if (!repaired.changed) return false;
50528
50773
  writeCodexHooks({
@@ -50635,10 +50880,18 @@ async function runMachineDoctor(options) {
50635
50880
  } },
50636
50881
  "cli.path_stable": { inspect: () => {
50637
50882
  if (!cli) return check("cli.path_stable", "fail", "The running CLI's files could not be located.", { action: "install_cli" });
50638
- if (ephemeral) return check("cli.path_stable", "fail", `This CLI runs from ${ephemeral}; hooks pointing at it would break. Install it globally with \`npm install -g primitive\`.`, {
50883
+ if (ephemeral && !cli.launcher) return check("cli.path_stable", "fail", `This CLI runs from ${ephemeral}; hooks pointing at it would break. Install it globally with \`npm install -g primitive\`.`, {
50639
50884
  action: "install_cli",
50640
50885
  path: cli.entry
50641
50886
  });
50887
+ if (ephemeral) {
50888
+ const launcherNote = `This CLI runs from ${ephemeral}. Claude Code hooks run through ${cli.launcher?.path}, which uses the \`primitive\` on PATH or fetches this version again with npx if the cache is removed.`;
50889
+ const codexRead = readCodexHooks(paths.codexHome);
50890
+ return selected("codex") && present.codex && !(perConnection && codexRead.ok && !hasCodexSessionHook(codexRead.settings)) ? check("cli.path_stable", "warn", `${launcherNote} The Codex SessionStart hook names the CLI directly; install it globally with \`npm install -g primitive\` so that hook keeps working.`, {
50891
+ action: "install_cli",
50892
+ path: cli.entry
50893
+ }) : check("cli.path_stable", "ok", launcherNote, { path: cli.entry });
50894
+ }
50642
50895
  const onPath = findOnPath("primitive", env);
50643
50896
  if (onPath && !samePath(onPath, cli.entry)) return check("cli.path_stable", "warn", `\`primitive\` on PATH is ${onPath}, but this run is ${cli.entry}; hooks follow the copy that runs the doctor.`, { path: cli.entry });
50644
50897
  return check("cli.path_stable", "ok", `Hooks use ${cli.node} and ${cli.entry}.`, { path: cli.entry });
@@ -50650,7 +50903,7 @@ async function runMachineDoctor(options) {
50650
50903
  } catch {
50651
50904
  return check("auth.member_login", "fail", "The saved login file is unreadable. Sign in again.", { action: "login" });
50652
50905
  }
50653
- if (!saved) return check("auth.member_login", "fail", "No saved member login on this machine.", { action: "login" });
50906
+ if (!saved) return perConnection ? check("auth.member_login", "skip", "No member login is saved. Agents on this machine were connected with `primitive agent connect` and use their own saved credentials; sign in with `primitive login` only to register every session on this machine automatically.") : check("auth.member_login", "fail", "No saved member login on this machine.", { action: "login" });
50654
50907
  let credentials;
50655
50908
  try {
50656
50909
  credentials = await refreshStoredCliCredentials({
@@ -50804,7 +51057,7 @@ function renderCheck(check) {
50804
51057
  }
50805
51058
  var MachineDoctorCommand = class MachineDoctorCommand extends Command {
50806
51059
  static summary = "Check, and optionally repair, this machine's Primitive setup for coding agents";
50807
- static description = "Checks everything that lets Claude Code, Codex and omp sessions on this machine register with Primitive and answer mail: the CLI install and version, the saved member login, Claude settings and Primitive's SessionStart, SessionEnd and per-session receive hooks, the managed instruction block in each runtime's global instructions file, the bundled primitive-connect skill, and saved agent profiles disconnected in Primitive. Each check reports ok, warn, fail or skip, whether it can be repaired automatically, and an action (login, install_cli, update_cli, edit_file) when only a person can fix it. --fix repairs what it safely can: it only adds, rewrites or removes Primitive-owned hooks, blocks and skill copies, backs up any existing file beside it as <file>.primitive-bak-<timestamp> before changing it, writes atomically, and changes nothing when nothing drifted, so it is safe to run on a timer. Malformed or hand-edited files it cannot parse are reported and left unchanged. Exits 0 when every check is ok or skipped, 1 otherwise.";
51060
+ static description = "Checks everything that lets Claude Code, Codex and omp sessions on this machine register with Primitive and answer mail: the CLI install and version, the saved member login, Claude settings and Primitive's SessionStart, SessionEnd and per-session receive hooks, the managed instruction block in each runtime's global instructions file, the bundled primitive-connect skill, and saved agent profiles disconnected in Primitive. Each check reports ok, warn, fail or skip, whether it can be repaired automatically, and an action (login, install_cli, update_cli, edit_file) when only a person can fix it. --fix repairs what it safely can: it only adds, rewrites or removes Primitive-owned hooks, blocks and skill copies, backs up any existing file beside it as <file>.primitive-bak-<timestamp> before changing it, writes atomically, and changes nothing when nothing drifted, so it is safe to run on a timer. Malformed or hand-edited files it cannot parse are reported and left unchanged. On a machine whose agents were all connected with `agent connect` and that has no saved member login, machine-wide setup it does not use (the member login, SessionStart and SessionEnd hooks, instruction blocks, skills) is reported as skip, and --fix does not add it. Exits 0 when every check is ok or skipped, 1 otherwise.";
50808
51061
  static examples = [
50809
51062
  "<%= config.bin %> machine doctor",
50810
51063
  "<%= config.bin %> machine doctor --json",
@@ -54401,7 +54654,8 @@ var ReplyCommand = class ReplyCommand extends Command {
54401
54654
  } else emailId = flags.id;
54402
54655
  const priorRepliesCheck = await checkPriorReplies({
54403
54656
  client: apiClient.client,
54404
- emailId
54657
+ emailId,
54658
+ isLocalSignal: (sentId) => isSentSignal(this.config.configDir, sentId)
54405
54659
  });
54406
54660
  this.priorRepliesCheck = priorRepliesCheck;
54407
54661
  const priorRepliesMessage = priorRepliesCheck.status === "checked" ? formatPriorRepliesWarning(priorRepliesCheck.prior) : formatPriorRepliesCheckSkipped(emailId, priorRepliesCheck.reason);
@@ -54521,7 +54775,10 @@ function priorRepliesEnvelopeFields(check) {
54521
54775
  };
54522
54776
  return check.status === "checked" ? {
54523
54777
  prior_replies: check.prior,
54524
- prior_replies_check: { status: "checked" }
54778
+ prior_replies_check: {
54779
+ status: "checked",
54780
+ signals_excluded: check.signals ?? 0
54781
+ }
54525
54782
  } : {
54526
54783
  prior_replies: null,
54527
54784
  prior_replies_check: {
@@ -55433,7 +55690,10 @@ var SendCommand = class SendCommand extends Command {
55433
55690
  ]
55434
55691
  }),
55435
55692
  wait: Flags.boolean({ description: "Block until the receiving MTA returns an outcome. Without --wait, the call returns once Primitive has accepted the message for delivery." }),
55436
- "wait-timeout-ms": Flags.integer({ description: "Maximum time to wait when --wait is set. Defaults to 30000ms." }),
55693
+ "wait-timeout-ms": Flags.integer({
55694
+ description: `Maximum time to wait for the delivery outcome when --wait is set. Defaults to 30000ms; the server waits at most ${MAX_SEND_WAIT_TIMEOUT_MS}ms, so a longer value is shortened to that with a notice. This waits for delivery, not for a reply: to wait for the recipient's answer, run \`primitive emails wait --reply-to-sent-email-id <sent id> --from <recipient> --timeout <seconds>\` after sending.`,
55695
+ min: 1
55696
+ }),
55437
55697
  "idempotency-key": Flags.string({ description: IDEMPOTENCY_KEY_FLAG_DESCRIPTION }),
55438
55698
  json: Flags.boolean({ description: "Emit one outcome envelope { outcome, exit_code, outcome_message, sent_email_id, idempotency_key, sent, http_status, error, follow_up_commands } on stdout for every outcome, including failures, with nothing on stderr. Without --json, stdout is the send record as before." }),
55439
55699
  time: Flags.boolean({ description: TIME_FLAG_DESCRIPTION }),
@@ -55447,6 +55707,8 @@ var SendCommand = class SendCommand extends Command {
55447
55707
  attemptStartedAtIso = null;
55448
55708
  idempotencyKey = null;
55449
55709
  sendRequestStarted = false;
55710
+ /** Set when --wait-timeout-ms was shortened to the server's limit. */
55711
+ waitNotice = null;
55450
55712
  async run() {
55451
55713
  const { flags } = await this.parse(SendCommand);
55452
55714
  try {
@@ -55457,7 +55719,8 @@ var SendCommand = class SendCommand extends Command {
55457
55719
  error,
55458
55720
  idempotencyKey: this.idempotencyKey,
55459
55721
  noun: "Message",
55460
- requestStarted: this.sendRequestStarted
55722
+ requestStarted: this.sendRequestStarted,
55723
+ ...this.waitNotice ? { extraEnvelopeFields: { wait_notice: this.waitNotice } } : {}
55461
55724
  }), null, 2));
55462
55725
  if (this.sendRequestStarted) {
55463
55726
  const detail = error instanceof Error ? error.message : String(error);
@@ -55512,10 +55775,14 @@ var SendCommand = class SendCommand extends Command {
55512
55775
  ...flags.bcc !== void 0 ? { bcc: flags.bcc } : {},
55513
55776
  subject
55514
55777
  };
55778
+ const requestedWait = flags["wait-timeout-ms"];
55779
+ const waitTimeoutMs = requestedWait === void 0 ? void 0 : Math.min(requestedWait, MAX_SEND_WAIT_TIMEOUT_MS);
55780
+ if (flags.wait && requestedWait !== void 0 && requestedWait > 3e4) this.waitNotice = sendWaitClampNotice(requestedWait);
55781
+ if (this.waitNotice && !flags.json) process.stderr.write(`${this.waitNotice}\n`);
55515
55782
  const threading = {
55516
55783
  ...flags["in-reply-to"] !== void 0 ? { in_reply_to: flags["in-reply-to"] } : {},
55517
55784
  ...flags.wait !== void 0 ? { wait: flags.wait } : {},
55518
- ...flags["wait-timeout-ms"] !== void 0 ? { wait_timeout_ms: flags["wait-timeout-ms"] } : {},
55785
+ ...waitTimeoutMs !== void 0 ? { wait_timeout_ms: waitTimeoutMs } : {},
55519
55786
  ...repeat !== void 0 ? { repeat } : {}
55520
55787
  };
55521
55788
  const idempotencyKey = this.idempotencyKey ?? deriveSendIdempotencyKey("send", flags.fyi ? {
@@ -55562,6 +55829,7 @@ var SendCommand = class SendCommand extends Command {
55562
55829
  });
55563
55830
  const outcome = reportSendCommandResult({
55564
55831
  attemptStartedAtIso,
55832
+ ...this.waitNotice ? { extraEnvelopeFields: { wait_notice: this.waitNotice } } : {},
55565
55833
  idempotencyKey,
55566
55834
  json: flags.json,
55567
55835
  log: (line) => this.log(line),
@@ -57434,6 +57702,7 @@ const COMMANDS = {
57434
57702
  completion: CompletionCommand,
57435
57703
  "agent:upgrade": AgentUpgradeCommand,
57436
57704
  "agent:connect": AgentConnectCommand,
57705
+ "agent:status": AgentStatusCommand,
57437
57706
  "agent:check-mail": AgentCheckMailCommand,
57438
57707
  "agent:disconnect": AgentDisconnectCommand,
57439
57708
  "agent:enroll": AgentEnrollCommand,