primcli 1.67.0 → 1.69.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.
- package/README.md +34 -10
- package/bin/claude-pending-mail.mjs +58 -1
- package/bin/claude-wake.mjs +6 -1
- package/dist/{api-command-Dh4hs7kh.js → api-command-C58Oh38I.js} +76 -14
- package/dist/{machine-session-s6LvMvRd.js → machine-session-CKmn5bvB.js} +359 -37
- package/dist/{notify-session-CeKAcPIX.js → notify-session-CVZtEboh.js} +1 -1
- package/dist/oclif/auto-signal-worker.js +2 -2
- package/dist/oclif/index.js +120 -45
- package/dist/oclif/receiver-heal.js +1 -1
- package/dist/{signal-command-BxafnMiU.js → signal-command-Dy_oub7_.js} +1 -1
- package/dist/skills/primitive-connect/SKILL.md +6 -0
- package/dist/skills/primitive-connect/package-lock.json +78 -78
- package/dist/skills/primitive-connect/package.json +1 -1
- package/dist/skills/primitive-connect/references/conversations.md +22 -1
- package/dist/skills/primitive-connect.json +6 -6
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { b as parseWebhookEvent, c as classifySignalContent, v as isEmailReceivedEvent, y as isTrustedSender } from "./repeats-BL7ZC-_6-BZ-MphTV.js";
|
|
2
|
-
import { F as wakeReadCommand, P as skillFirstLine, Y as wakeInteractionSentence, dn as downloadEmailAttachmentPart } from "./api-command-
|
|
2
|
+
import { F as wakeReadCommand, P as skillFirstLine, Y as wakeInteractionSentence, dn as downloadEmailAttachmentPart } from "./api-command-C58Oh38I.js";
|
|
3
3
|
import { _ as acquireListenLock, g as ListenStateError, y as listenIdentity } from "./shared-mail-files-MwlVE90c.js";
|
|
4
4
|
import { closeSync, copyFileSync, existsSync, fsyncSync, lstatSync, mkdirSync, openSync, opendirSync, readFileSync, readdirSync, readlinkSync, renameSync, rmSync, statSync, symlinkSync, unlinkSync, writeFileSync } from "node:fs";
|
|
5
5
|
import { createHash, randomUUID, scryptSync } from "node:crypto";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { A as readThreadContext, En as getSentEmail, Kt as createAuthenticatedCliApiClient } from "../api-command-
|
|
1
|
+
import { A as readThreadContext, En as getSentEmail, Kt as createAuthenticatedCliApiClient } from "../api-command-C58Oh38I.js";
|
|
2
2
|
import { _ as acquireListenLock } from "../shared-mail-files-MwlVE90c.js";
|
|
3
|
-
import { t as sendSignal } from "../signal-command-
|
|
3
|
+
import { t as sendSignal } from "../signal-command-Dy_oub7_.js";
|
|
4
4
|
import { AUTO_SIGNAL_KIND_ENV, AUTO_WORKING_RENEW_MS, autoSignalsDisabled, clearWorkingSending, markWorkingSending, readAutoClaim, readWorkingLease, recordRenewer, stopWorkingLease, writeWorkingLease } from "./auto-signals.js";
|
|
5
5
|
import { join } from "node:path";
|
|
6
6
|
import { homedir } from "node:os";
|
package/dist/oclif/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
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-BZ-MphTV.js";
|
|
2
2
|
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-DMszFbGn.js";
|
|
3
|
-
import { $ as apiResultHttpStatus, $n as replyToEmail, $t as completeWebhookEvent, A as readThreadContext, An as listAgentNetworks, At as formatAlreadySentNotice, B as pendingMailPath, Bn as listRoutes, Bt as expectedAutomatedVerdicts, C as queryUsesAwaiting, Cn as getMemory, Cr as verifyAgentSignup, Ct as cliInvocation, D as displayAddress, Dn as getThread, Dt as identitySuggestions, E as describeWake, En as getSentEmail, Et as generatedAgentName, F as wakeReadCommand, Fn as listEmails, Ft as AUTOMATED_VALUES, G as interactionNextActions, Gn as pollCliLogin, H as recordPendingMail, Hn as listWakeAuthorizations, Ht as isAutomatedRejectedError, I as wakeRecipientField, In as listEndpoints, It as AutomatedFilterUnsupportedError, J as replyInteractionWarning, Jt as refreshStoredCliCredentials, K as readEmailInteraction, Kn as pullWebhookEvent, Kt as createAuthenticatedCliApiClient, L as wakeRelationship, Ln as listFunctionLogs, Lt as assertAutomatedVerdict, M as serverMuted, Mn as listDefaultNetworkAgents, Mt as withFlagSuggestion, N as serverRelationship, Nn as listDefaultNetworkMembers, Nt as AUTOMATED_FILTER_UNSUPPORTED_CODE, O as formatMailWakeLine, On as getWakeSchedule, Ot as loadSkillLine, Pn as listDomains, Pt as AUTOMATED_FLAG_DESCRIPTION, Q as SEND_OUTCOME_HELP, Qn as reorderRoutes, Qt as cliLogout, R as clearConsumedPendingMail, Rn as listFunctions, Rt as automatedRejectedError, S as isAwaitingRejectedError, Sn as getInboxStatus, Sr as verifyAgentClaim, T as bareAddress, Tn as getRepeatingSend, U as removePendingMail, Un as listWakeDispatches, Ut as queryUsesAutomated, V as readPendingMail, Vn as listSentEmails, Vt as hasAutomatedVerdict, W as interactionHumanLine, Wn as listWakeSchedules, Wt as ConnectedAgentKeyRequiredError, X as IDEMPOTENCY_KEY_FLAG_DESCRIPTION, Xn as redeemCreditCode, Xt as addDefaultNetworkMember, Yt as resolveCliApiRequestConfig, Z as MAX_SEND_WAIT_TIMEOUT_MS, Zn as removeDefaultNetworkMember, Zt as checkDefaultNetworkContactAdmission, _ as awaitingRejectedError, _n as getDefaultNetworkAgent, _r as updateFunction, _t as sendWaitClampNotice, a as extractErrorCode, ar as sendEmail, at as deriveSendIdempotencyKey, b as formatRepliesCell, bn as getFunctionRouting, br as updateWakeAuthorization, bt as successfulSendOutcome, c as readTextFileFlag, cn as deleteRoute, cr as setMemory, ct as formatDeletedEarlierSendNotice, d as writeErrorWithHints, dr as startAgentSignup, dt as formatSendFailureSummary, en as createEndpoint, er as resendAgentSignupVerification, et as assertValidIdempotencyKey, f as AWAITING_FLAG_DESCRIPTION, fn as getAccount, fr as startCliLogin, ft as formatSendRecordFailureSummary, g as assertAwaitingFilterRows, gn as getCreditBalance, gr as updateDefaultNetworkMember, gt as sendOutcomeExitCode, h as ReplyStateUnsupportedError, hn as getConversation, hr as unsetFunctionRoute, ht as sendIdentityFields, i as createOperationCommand, in as createWakeSchedule, ir as semanticSearch, it as classifySendError, j as sentInThread, jt as writeIdempotentReplayBannerIfReplay, k as latestOwnOutbound, kn as listAgentContacts, kt as currentMailSessionKey, l as runWithTiming, ln as deleteWakeAuthorization, lr as simulateRoute, lt as formatPriorRepliesCheckSkipped, m as REPLY_STATE_UNSUPPORTED_CODE, mr as testFunction, mt as reportSendCommandResult, n as API_ERROR_CODES, nn as createRoute, nr as searchEmails, nt as buildThrownSendFailureEnvelope, o as extractErrorPayload, or as setFunctionRoute, ot as excludeSignalReplies, p as AWAITING_VALUES, pn as getAgentContactPolicy, pr as stopRepeatFromEmail, pt as priorRepliesThatWentOut, q as replyExpectation, qt as createCliApiClient, r as TIME_FLAG_DESCRIPTION, rn as createWakeAuthorization, rr as searchMemories, rt as checkPriorReplies, s as formatErrorPayload, sn as deleteMemory, sr as setFunctionSecret, st as followUpCommandPrefix, t as API_BASE_URL_FLAG_DESCRIPTION, tn as createFunction, tr as runWakeSchedule, tt as buildFollowUpCommand, u as surfaceUnauthorizedHint, un as deleteWakeSchedule, ur as startAgentClaim, ut as formatPriorRepliesWarning, v as ensureSearchReportsReplyState, vn as getEmail, vr as updateRepeatingSend, vt as sentHistoryWindowStart, w as explainPendingMailNotFound, wn as getOrgRoutingTopology, wt as connectNextSteps, x as hasReplyState, xn as getFunctionTestRunTrace, xr as updateWakeSchedule, xt as thrownErrorExitCode, y as formatAwaitingCell, yn as getFunction, yr as updateRoute, yt as serializeErrorPayload, z as clearReadPendingMail, zn as listRepeatingSends, zt as ensureSearchReportsAutomated } from "../api-command-
|
|
3
|
+
import { $ as apiResultHttpStatus, $n as replyToEmail, $t as completeWebhookEvent, A as readThreadContext, An as listAgentNetworks, At as formatAlreadySentNotice, B as pendingMailPath, Bn as listRoutes, Bt as expectedAutomatedVerdicts, C as queryUsesAwaiting, Cn as getMemory, Cr as verifyAgentSignup, Ct as cliInvocation, D as displayAddress, Dn as getThread, Dt as identitySuggestions, E as describeWake, En as getSentEmail, Et as generatedAgentName, F as wakeReadCommand, Fn as listEmails, Ft as AUTOMATED_VALUES, G as interactionNextActions, Gn as pollCliLogin, H as recordPendingMail, Hn as listWakeAuthorizations, Ht as isAutomatedRejectedError, I as wakeRecipientField, In as listEndpoints, It as AutomatedFilterUnsupportedError, J as replyInteractionWarning, Jt as refreshStoredCliCredentials, K as readEmailInteraction, Kn as pullWebhookEvent, Kt as createAuthenticatedCliApiClient, L as wakeRelationship, Ln as listFunctionLogs, Lt as assertAutomatedVerdict, M as serverMuted, Mn as listDefaultNetworkAgents, Mt as withFlagSuggestion, N as serverRelationship, Nn as listDefaultNetworkMembers, Nt as AUTOMATED_FILTER_UNSUPPORTED_CODE, O as formatMailWakeLine, On as getWakeSchedule, Ot as loadSkillLine, Pn as listDomains, Pt as AUTOMATED_FLAG_DESCRIPTION, Q as SEND_OUTCOME_HELP, Qn as reorderRoutes, Qt as cliLogout, R as clearConsumedPendingMail, Rn as listFunctions, Rt as automatedRejectedError, S as isAwaitingRejectedError, Sn as getInboxStatus, Sr as verifyAgentClaim, T as bareAddress, Tn as getRepeatingSend, U as removePendingMail, Un as listWakeDispatches, Ut as queryUsesAutomated, V as readPendingMail, Vn as listSentEmails, Vt as hasAutomatedVerdict, W as interactionHumanLine, Wn as listWakeSchedules, Wt as ConnectedAgentKeyRequiredError, X as IDEMPOTENCY_KEY_FLAG_DESCRIPTION, Xn as redeemCreditCode, Xt as addDefaultNetworkMember, Yt as resolveCliApiRequestConfig, Z as MAX_SEND_WAIT_TIMEOUT_MS, Zn as removeDefaultNetworkMember, Zt as checkDefaultNetworkContactAdmission, _ as awaitingRejectedError, _n as getDefaultNetworkAgent, _r as updateFunction, _t as sendWaitClampNotice, a as extractErrorCode, ar as sendEmail, at as deriveSendIdempotencyKey, b as formatRepliesCell, bn as getFunctionRouting, br as updateWakeAuthorization, bt as successfulSendOutcome, c as readTextFileFlag, cn as deleteRoute, cr as setMemory, ct as formatDeletedEarlierSendNotice, d as writeErrorWithHints, dr as startAgentSignup, dt as formatSendFailureSummary, en as createEndpoint, er as resendAgentSignupVerification, et as assertValidIdempotencyKey, f as AWAITING_FLAG_DESCRIPTION, fn as getAccount, fr as startCliLogin, ft as formatSendRecordFailureSummary, g as assertAwaitingFilterRows, gn as getCreditBalance, gr as updateDefaultNetworkMember, gt as sendOutcomeExitCode, h as ReplyStateUnsupportedError, hn as getConversation, hr as unsetFunctionRoute, ht as sendIdentityFields, i as createOperationCommand, in as createWakeSchedule, ir as semanticSearch, it as classifySendError, j as sentInThread, jt as writeIdempotentReplayBannerIfReplay, k as latestOwnOutbound, kn as listAgentContacts, kt as currentMailSessionKey, l as runWithTiming, ln as deleteWakeAuthorization, lr as simulateRoute, lt as formatPriorRepliesCheckSkipped, m as REPLY_STATE_UNSUPPORTED_CODE, mr as testFunction, mt as reportSendCommandResult, n as API_ERROR_CODES, nn as createRoute, nr as searchEmails, nt as buildThrownSendFailureEnvelope, o as extractErrorPayload, or as setFunctionRoute, ot as excludeSignalReplies, p as AWAITING_VALUES, pn as getAgentContactPolicy, pr as stopRepeatFromEmail, pt as priorRepliesThatWentOut, q as replyExpectation, qt as createCliApiClient, r as TIME_FLAG_DESCRIPTION, rn as createWakeAuthorization, rr as searchMemories, rt as checkPriorReplies, s as formatErrorPayload, sn as deleteMemory, sr as setFunctionSecret, st as followUpCommandPrefix, t as API_BASE_URL_FLAG_DESCRIPTION, tn as createFunction, tr as runWakeSchedule, tt as buildFollowUpCommand, u as surfaceUnauthorizedHint, un as deleteWakeSchedule, ur as startAgentClaim, ut as formatPriorRepliesWarning, v as ensureSearchReportsReplyState, vn as getEmail, vr as updateRepeatingSend, vt as sentHistoryWindowStart, w as explainPendingMailNotFound, wn as getOrgRoutingTopology, wt as connectNextSteps, x as hasReplyState, xn as getFunctionTestRunTrace, xr as updateWakeSchedule, xt as thrownErrorExitCode, y as formatAwaitingCell, yn as getFunction, yr as updateRoute, yt as serializeErrorPayload, z as clearReadPendingMail, zn as listRepeatingSends, zt as ensureSearchReportsAutomated } from "../api-command-C58Oh38I.js";
|
|
4
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-
|
|
6
|
-
import { $ as
|
|
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-CVZtEboh.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-CKmn5bvB.js";
|
|
7
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-Dsark9hm.js";
|
|
8
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-
|
|
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-Dy_oub7_.js";
|
|
10
10
|
import { autoSignalEligible, dispatchAutoRead, dispatchAutoWorking, haltAutoWorking, isSentSignal, readWorkingLease, restoreAutoWorking } from "./auto-signals.js";
|
|
11
11
|
import { t as guardJsonOutputCommands } from "../json-output-CEskSQJi.js";
|
|
12
12
|
import { Args, Command, Errors, Flags, ux } from "@oclif/core";
|
|
@@ -36477,7 +36477,7 @@ function withClearedNote(message, cleared) {
|
|
|
36477
36477
|
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.`;
|
|
36478
36478
|
}
|
|
36479
36479
|
var AgentConnectCommand = class AgentConnectCommand extends Command {
|
|
36480
|
-
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: 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.`;
|
|
36480
|
+
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.`;
|
|
36481
36481
|
static summary = "Connect and verify an agent address";
|
|
36482
36482
|
static examples = [
|
|
36483
36483
|
"<%= config.bin %> agent connect --session \"$CODEX_THREAD_ID\" --name Research --info \"Reviews pull requests\" --json < private-invitation.txt",
|
|
@@ -36699,6 +36699,7 @@ var AgentConnectCommand = class AgentConnectCommand extends Command {
|
|
|
36699
36699
|
this.log(`Agent ${output.address}: verification ${output.verification.state}; receiving ${output.receiving.state}; skill ${output.skill.state}.`);
|
|
36700
36700
|
this.log(`Select it with ${output.selectProfile}.`);
|
|
36701
36701
|
for (const warning of output.warnings) this.log(warning.message);
|
|
36702
|
+
if (output.resumeNote === "failed") this.warn("The AGENT_RESUME note could not be updated. The connection is unaffected.");
|
|
36702
36703
|
if (output.ownerNotifications === "silenced") this.log("Owner notifications remain silenced by the existing preference or policy.");
|
|
36703
36704
|
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.");
|
|
36704
36705
|
if (poll && "fallbackDetail" in output.receiving) this.log(String(output.receiving.fallbackDetail));
|
|
@@ -37599,9 +37600,13 @@ var AgentRuntimeGetCommand = class AgentRuntimeGetCommand extends Command {
|
|
|
37599
37600
|
//#endregion
|
|
37600
37601
|
//#region src/oclif/commands/agent-session-end.ts
|
|
37601
37602
|
var AgentSessionEndCommand = class AgentSessionEndCommand extends Command {
|
|
37602
|
-
static summary = "
|
|
37603
|
-
static description = "
|
|
37604
|
-
static examples = [
|
|
37603
|
+
static summary = "Record that a registered session ended";
|
|
37604
|
+
static description = "Marks this session ended and removes its exact-session receive hooks. The agent that `primitive agent session-register` created for the session stays connected, with its credential and profile, so resuming the session (for example `claude --resume`) re-verifies it and reinstalls the hooks at the same address. Its presence lapses on its own once the session stops running. An agent whose session has not started again for 30 days is disconnected by `primitive machine doctor --fix` or the next `agent session-register` on this machine. --revoke disconnects the agent now instead, first deleting its AGENT_RESUME note (reported as resumeNote; a failed deletion is a warning and never stops the disconnect). Agents connected any other way are never disconnected, including an agent later connected into the same profile with `primitive agent connect`. Never blocks or fails a session: every outcome exits 0 with a status. --hook reads Claude's SessionEnd hook input from stdin and finishes in the background after a grace period: Claude reports the same end for a restart, a switch to another session and a real exit, so a start of the same session within the grace period cancels the end.";
|
|
37605
|
+
static examples = [
|
|
37606
|
+
"<%= config.bin %> agent session-end --runtime claude --json",
|
|
37607
|
+
"<%= config.bin %> agent session-end --runtime codex --session 11111111-1111-4111-8111-111111111111",
|
|
37608
|
+
"<%= config.bin %> agent session-end --runtime claude --session 11111111-1111-4111-8111-111111111111 --revoke"
|
|
37609
|
+
];
|
|
37605
37610
|
static flags = {
|
|
37606
37611
|
runtime: Flags.string({
|
|
37607
37612
|
required: true,
|
|
@@ -37612,10 +37617,11 @@ var AgentSessionEndCommand = class AgentSessionEndCommand extends Command {
|
|
|
37612
37617
|
grace: Flags.integer({
|
|
37613
37618
|
min: 0,
|
|
37614
37619
|
max: 3600,
|
|
37615
|
-
description: "Seconds to wait before
|
|
37620
|
+
description: "Seconds to wait before the end takes effect; a start of the same session meanwhile cancels it"
|
|
37616
37621
|
}),
|
|
37622
|
+
revoke: Flags.boolean({ description: "Disconnect the agent session-register created for this session instead of keeping it for a resume" }),
|
|
37617
37623
|
reason: Flags.string({ description: "The runtime's reason for the end, recorded with it" }),
|
|
37618
|
-
hook: Flags.boolean({ description: "Read Claude hook JSON from stdin and
|
|
37624
|
+
hook: Flags.boolean({ description: "Read Claude hook JSON from stdin and finish in the background" }),
|
|
37619
37625
|
json: Flags.boolean({ description: "Print the result as JSON" }),
|
|
37620
37626
|
quiet: Flags.boolean({ description: "Print nothing" })
|
|
37621
37627
|
};
|
|
@@ -37638,6 +37644,7 @@ var AgentSessionEndCommand = class AgentSessionEndCommand extends Command {
|
|
|
37638
37644
|
"--grace",
|
|
37639
37645
|
String(HOOK_END_GRACE_MS / 1e3),
|
|
37640
37646
|
...input.reason ? ["--reason", input.reason] : [],
|
|
37647
|
+
...flags.revoke ? ["--revoke"] : [],
|
|
37641
37648
|
"--quiet"
|
|
37642
37649
|
],
|
|
37643
37650
|
env: process.env,
|
|
@@ -37650,14 +37657,18 @@ var AgentSessionEndCommand = class AgentSessionEndCommand extends Command {
|
|
|
37650
37657
|
runtime,
|
|
37651
37658
|
session: flags.session,
|
|
37652
37659
|
graceMs: (flags.grace ?? 0) * 1e3,
|
|
37653
|
-
reason: flags.reason ?? null
|
|
37660
|
+
reason: flags.reason ?? null,
|
|
37661
|
+
revoke: flags.revoke === true
|
|
37654
37662
|
});
|
|
37655
37663
|
const { status, ...rest } = result;
|
|
37656
37664
|
if (flags.json) this.log(JSON.stringify({
|
|
37657
37665
|
status,
|
|
37658
37666
|
...rest
|
|
37659
37667
|
}));
|
|
37660
|
-
else if (!flags.quiet)
|
|
37668
|
+
else if (!flags.quiet) {
|
|
37669
|
+
this.log(`${result.status}: ${result.detail}`);
|
|
37670
|
+
if (result.resumeNote === "failed") this.warn("The AGENT_RESUME note could not be deleted before the agent was disconnected.");
|
|
37671
|
+
}
|
|
37661
37672
|
}
|
|
37662
37673
|
};
|
|
37663
37674
|
//#endregion
|
|
@@ -37666,7 +37677,7 @@ var AgentSessionEndCommand = class AgentSessionEndCommand extends Command {
|
|
|
37666
37677
|
const HOOK_BUDGET_MS = 3e3;
|
|
37667
37678
|
var AgentSessionRegisterCommand = class AgentSessionRegisterCommand extends Command {
|
|
37668
37679
|
static summary = "Register this coding session with Primitive, once";
|
|
37669
|
-
static description = "Gives the current Claude Code, Codex or omp session an address in your organization using the saved member login, without a browser. Safe to run on every start and resume: a session that already has a profile is only re-verified, and a session whose agent was disconnected or removed never gets a second address. The session ID comes from CLAUDE_CODE_SESSION_ID (Claude), CODEX_THREAD_ID or CODEX_SESSION_ID (Codex), or --session. omp does not expose a session ID to commands, so omp sessions use one generated ID per running omp process, and receiving mail is not supported for them. The agent is named <runtime>-<repository> and gets a private AGENT_INFO note naming the runtime and repository when it has none. Claude sessions receive mail through exact-session hooks; Codex through the native receiver. Non-interactive Claude runs (claude -p and SDK hosts, by CLAUDE_CODE_ENTRYPOINT) are skipped with status skipped_headless. Never blocks a session: every outcome, including no login or no network, exits 0 with a status. --hook reads Claude's or Codex's SessionStart hook input from stdin, returns within a few seconds and finishes slower work in the background.";
|
|
37680
|
+
static description = "Gives the current Claude Code, Codex or omp session an address in your organization using the saved member login, without a browser. Safe to run on every start and resume: a session that already has a profile is only re-verified, and a session that ended and starts again (for example `claude --resume`) keeps its agent and address, and a session whose agent was disconnected or removed never gets a second address. Each run also disconnects the agents of sessions on this machine that ended more than 30 days ago without starting again, only while their profile still holds the credential this command created. The session ID comes from CLAUDE_CODE_SESSION_ID (Claude), CODEX_THREAD_ID or CODEX_SESSION_ID (Codex), or --session. omp does not expose a session ID to commands, so omp sessions use one generated ID per running omp process, and receiving mail is not supported for them. The agent is named <runtime>-<repository> and gets a private AGENT_INFO note naming the runtime and repository when it has none. A connected Claude Code or Codex session also gets a private AGENT_RESUME note holding the one-line command that resumes it (`claude --resume <session>` or `codex resume <session>`), rewritten only when it changes; a failure to write it is reported as a warning and never fails the registration. Claude sessions receive mail through exact-session hooks; Codex through the native receiver. Non-interactive Claude runs (claude -p and SDK hosts, by CLAUDE_CODE_ENTRYPOINT) are skipped with status skipped_headless. Never blocks a session: every outcome, including no login or no network, exits 0 with a status. --hook reads Claude's or Codex's SessionStart hook input from stdin, returns within a few seconds and finishes slower work in the background.";
|
|
37670
37681
|
static examples = [
|
|
37671
37682
|
"<%= config.bin %> agent session-register --runtime codex --quiet",
|
|
37672
37683
|
"<%= config.bin %> agent session-register --runtime claude --json",
|
|
@@ -37731,7 +37742,13 @@ var AgentSessionRegisterCommand = class AgentSessionRegisterCommand extends Comm
|
|
|
37731
37742
|
...rest,
|
|
37732
37743
|
...identity
|
|
37733
37744
|
}));
|
|
37734
|
-
else if (!flags.quiet)
|
|
37745
|
+
else if (!flags.quiet) {
|
|
37746
|
+
this.log(`${result.status}: ${result.detail}`);
|
|
37747
|
+
if (result.resumeNote === "failed") this.warn("The AGENT_RESUME note could not be written. The session is registered; the next start retries it.");
|
|
37748
|
+
}
|
|
37749
|
+
try {
|
|
37750
|
+
await revokeStaleSessionAgents(this.config.configDir, { exclude: result.session });
|
|
37751
|
+
} catch {}
|
|
37735
37752
|
}
|
|
37736
37753
|
};
|
|
37737
37754
|
//#endregion
|
|
@@ -38931,11 +38948,19 @@ async function openConnectedReplyWait(options) {
|
|
|
38931
38948
|
signal: AbortSignal.timeout(2e3)
|
|
38932
38949
|
})).cancelRejectedSend(requestId);
|
|
38933
38950
|
},
|
|
38934
|
-
|
|
38951
|
+
/**
|
|
38952
|
+
* The session consumed this reply. Pass the reply itself when it is at
|
|
38953
|
+
* hand, so the older pending notices in its thread are cleared too.
|
|
38954
|
+
*/
|
|
38955
|
+
async observed(emailId, email) {
|
|
38935
38956
|
if (options.contactRequest && await store.observeNotifiedContactReply(emailId, requestId, waiter.token)) return;
|
|
38936
38957
|
await store.markWaitObserved(emailId, requestId);
|
|
38937
38958
|
try {
|
|
38938
|
-
await clearConsumedPendingMail(options.configDir, options.sessionKey, emailId
|
|
38959
|
+
await clearConsumedPendingMail(options.configDir, options.sessionKey, emailId, email ? {
|
|
38960
|
+
thread_id: email.thread_id ?? null,
|
|
38961
|
+
received_at: email.received_at,
|
|
38962
|
+
recipient: options.from
|
|
38963
|
+
} : null);
|
|
38939
38964
|
} catch {}
|
|
38940
38965
|
},
|
|
38941
38966
|
finish: () => store.finishWait(requestId),
|
|
@@ -39274,7 +39299,7 @@ async function requestContact(context, options) {
|
|
|
39274
39299
|
outcome: "sent_awaiting_reply"
|
|
39275
39300
|
}
|
|
39276
39301
|
};
|
|
39277
|
-
await wait.observed(accepted.id);
|
|
39302
|
+
await wait.observed(accepted.id, accepted);
|
|
39278
39303
|
await wait.finish();
|
|
39279
39304
|
return {
|
|
39280
39305
|
exitCode: 0,
|
|
@@ -39407,7 +39432,7 @@ async function waitForContact(context, sentId, timeoutSeconds) {
|
|
|
39407
39432
|
guidance: "Still awaiting acceptance. An active session listener can notify you later. Continue independent work instead of immediately chaining another wait; resume this same request when needed, without resending."
|
|
39408
39433
|
}
|
|
39409
39434
|
};
|
|
39410
|
-
await wait.observed(accepted.id);
|
|
39435
|
+
await wait.observed(accepted.id, accepted);
|
|
39411
39436
|
await wait.finish();
|
|
39412
39437
|
return {
|
|
39413
39438
|
exitCode: 0,
|
|
@@ -41136,7 +41161,7 @@ var ChatCommand = class ChatCommand extends Command {
|
|
|
41136
41161
|
requestId: connectedWait.requestId
|
|
41137
41162
|
};
|
|
41138
41163
|
saveChatReceipt(receipt);
|
|
41139
|
-
await connectedWait.observed(replyResult.reply.id);
|
|
41164
|
+
await connectedWait.observed(replyResult.reply.id, replyResult.reply);
|
|
41140
41165
|
await connectedWait.finish();
|
|
41141
41166
|
}
|
|
41142
41167
|
progress?.succeed(`Reply received from ${replyResult.reply.from_email}`);
|
|
@@ -43076,12 +43101,15 @@ const LINKS_DESCRIPTION = "With --compact, return the target URLs of links as `l
|
|
|
43076
43101
|
* Remove the email from the current profile's pending wake notices once the
|
|
43077
43102
|
* session has read it. Never fails the read.
|
|
43078
43103
|
*/
|
|
43079
|
-
async function clearPendingAfterRead(configDir, emailId) {
|
|
43104
|
+
async function clearPendingAfterRead(configDir, emailId, known) {
|
|
43080
43105
|
try {
|
|
43081
43106
|
const profileName = resolveCliAuth({ configDir }).connectedAgent?.profileName;
|
|
43082
43107
|
if (!profileName) return;
|
|
43083
43108
|
const runtime = currentMailSessionKey();
|
|
43084
|
-
await clearReadPendingMail(configDir, profileName, runtime ? runtime.slice(runtime.indexOf(":") + 1) : null, emailId
|
|
43109
|
+
await clearReadPendingMail(configDir, profileName, runtime ? runtime.slice(runtime.indexOf(":") + 1) : null, emailId, typeof known?.received_at === "string" ? {
|
|
43110
|
+
thread_id: known.thread_id ?? null,
|
|
43111
|
+
received_at: known.received_at
|
|
43112
|
+
} : null);
|
|
43085
43113
|
} catch {}
|
|
43086
43114
|
}
|
|
43087
43115
|
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).";
|
|
@@ -43150,7 +43178,7 @@ async function runBrief(command, flags) {
|
|
|
43150
43178
|
...brief,
|
|
43151
43179
|
working_signal: { stop_command: stop }
|
|
43152
43180
|
} : brief, null, 2) : `${renderEmailBrief(brief)}${stop ? `\n${workingStopLine(stop)}` : ""}`);
|
|
43153
|
-
await clearPendingAfterRead(command.config.configDir, detail.id);
|
|
43181
|
+
await clearPendingAfterRead(command.config.configDir, detail.id, detail);
|
|
43154
43182
|
});
|
|
43155
43183
|
}
|
|
43156
43184
|
const ROUTE_MISSING_NOTICE = "Note: this server does not offer the readable read yet, so a local compact view was printed.\n";
|
|
@@ -43180,7 +43208,7 @@ async function runCompact(command, flags) {
|
|
|
43180
43208
|
});
|
|
43181
43209
|
if (readable.kind === "ok") {
|
|
43182
43210
|
command.log(JSON.stringify(readable.data, null, 2));
|
|
43183
|
-
await clearPendingAfterRead(command.config.configDir, readable.data.id);
|
|
43211
|
+
await clearPendingAfterRead(command.config.configDir, readable.data.id, readable.data);
|
|
43184
43212
|
return;
|
|
43185
43213
|
}
|
|
43186
43214
|
if (readable.kind === "error") {
|
|
@@ -43199,7 +43227,7 @@ async function runCompact(command, flags) {
|
|
|
43199
43227
|
}
|
|
43200
43228
|
process.stderr.write(ROUTE_MISSING_NOTICE);
|
|
43201
43229
|
command.log(JSON.stringify(buildEmailCompact(detail), null, 2));
|
|
43202
|
-
await clearPendingAfterRead(command.config.configDir, detail.id);
|
|
43230
|
+
await clearPendingAfterRead(command.config.configDir, detail.id, detail);
|
|
43203
43231
|
});
|
|
43204
43232
|
}
|
|
43205
43233
|
/**
|
|
@@ -43585,7 +43613,7 @@ var EmailsWaitCommand = class EmailsWaitCommand extends Command {
|
|
|
43585
43613
|
const email = await waiter.next();
|
|
43586
43614
|
if (!email) break;
|
|
43587
43615
|
printEmail(email);
|
|
43588
|
-
await waiter.observed(email.id);
|
|
43616
|
+
await waiter.observed(email.id, email);
|
|
43589
43617
|
}
|
|
43590
43618
|
if (matched >= flags.number) {
|
|
43591
43619
|
await waiter.finish();
|
|
@@ -44928,7 +44956,7 @@ const PRIMITIVE_TEAM_AUTHOR = {
|
|
|
44928
44956
|
url: "https://primitive.dev"
|
|
44929
44957
|
};
|
|
44930
44958
|
const SDK_VERSION_RANGE = "^2.0.0";
|
|
44931
|
-
const CLI_VERSION_RANGE = "^1.
|
|
44959
|
+
const CLI_VERSION_RANGE = "^1.69.0";
|
|
44932
44960
|
const ESBUILD_VERSION_RANGE = "^0.27.0";
|
|
44933
44961
|
function renderHandler() {
|
|
44934
44962
|
return `// env.PRIMITIVE_API_KEY, env.PRIMITIVE_WEBHOOK_SECRET, and
|
|
@@ -49199,6 +49227,13 @@ async function createWakeMail(options) {
|
|
|
49199
49227
|
let wakeContext;
|
|
49200
49228
|
let statusEvent;
|
|
49201
49229
|
let autoSignal;
|
|
49230
|
+
let held;
|
|
49231
|
+
function surface(wake) {
|
|
49232
|
+
wakeId = wake.wakeId;
|
|
49233
|
+
senderRelation = wake.senderRelation;
|
|
49234
|
+
wakeContext = wake.context;
|
|
49235
|
+
autoSignal = wake.autoSignal;
|
|
49236
|
+
}
|
|
49202
49237
|
let pendingRequest;
|
|
49203
49238
|
const profileName = identity?.profileName;
|
|
49204
49239
|
const outcome = (accepted) => ({
|
|
@@ -49437,19 +49472,23 @@ async function createWakeMail(options) {
|
|
|
49437
49472
|
context
|
|
49438
49473
|
};
|
|
49439
49474
|
else {
|
|
49440
|
-
|
|
49441
|
-
|
|
49442
|
-
|
|
49443
|
-
|
|
49444
|
-
|
|
49445
|
-
|
|
49446
|
-
|
|
49447
|
-
|
|
49448
|
-
|
|
49449
|
-
|
|
49450
|
-
|
|
49451
|
-
|
|
49452
|
-
|
|
49475
|
+
const wake = {
|
|
49476
|
+
wakeId: detail.id,
|
|
49477
|
+
senderRelation: admission.senderRelation,
|
|
49478
|
+
context,
|
|
49479
|
+
autoSignal: profileName && autoSignalEligible(detail, {
|
|
49480
|
+
agentAddress: recipient,
|
|
49481
|
+
ownerAddress: identity?.ownerAddress
|
|
49482
|
+
}, admission) ? {
|
|
49483
|
+
emailId: detail.id,
|
|
49484
|
+
profileName,
|
|
49485
|
+
sender,
|
|
49486
|
+
threadId: detail.thread_id ?? null,
|
|
49487
|
+
replyToSentEmailId: detail.reply_to_sent_email_id ?? null
|
|
49488
|
+
} : void 0
|
|
49489
|
+
};
|
|
49490
|
+
if (context.newer !== void 0 && context.newer > 0) held = wake;
|
|
49491
|
+
else surface(wake);
|
|
49453
49492
|
}
|
|
49454
49493
|
return outcome(true);
|
|
49455
49494
|
} catch (error) {
|
|
@@ -49465,6 +49504,14 @@ async function createWakeMail(options) {
|
|
|
49465
49504
|
status: () => statusEvent,
|
|
49466
49505
|
autoSignal: () => wakeId === autoSignal?.emailId ? autoSignal : void 0,
|
|
49467
49506
|
completed: completePending,
|
|
49507
|
+
/** A superseded wake this run accepted and has not surfaced. */
|
|
49508
|
+
held: () => held?.wakeId,
|
|
49509
|
+
/** Surface the held wake, when nothing newer arrived for it. */
|
|
49510
|
+
wakeHeld: () => {
|
|
49511
|
+
if (wakeId || statusEvent || !held) return;
|
|
49512
|
+
surface(held);
|
|
49513
|
+
held = void 0;
|
|
49514
|
+
},
|
|
49468
49515
|
receiving: (ready) => {
|
|
49469
49516
|
receiving = ready;
|
|
49470
49517
|
},
|
|
@@ -49474,6 +49521,11 @@ async function createWakeMail(options) {
|
|
|
49474
49521
|
//#endregion
|
|
49475
49522
|
//#region src/oclif/commands/listen.ts
|
|
49476
49523
|
const RESUME_LOCK_RETRY_MS = 4e3;
|
|
49524
|
+
/**
|
|
49525
|
+
* How long a wake listener holding a superseded wake (one whose thread has
|
|
49526
|
+
* newer mail) waits for that newer mail before waking for the held one.
|
|
49527
|
+
*/
|
|
49528
|
+
const HELD_WAKE_SETTLE_MS = 5e3;
|
|
49477
49529
|
const MAIL_CHECK_RECORD_MS = 5e3;
|
|
49478
49530
|
const RESUME_LOCK_RETRY_STEP_MS = 250;
|
|
49479
49531
|
function isListenLockContention(error) {
|
|
@@ -49933,8 +49985,12 @@ var ListenCommand = class ListenCommand extends Command {
|
|
|
49933
49985
|
if (!target || !options.notifySession || !requestConfig) {
|
|
49934
49986
|
let resumeLockDeadline;
|
|
49935
49987
|
do {
|
|
49988
|
+
const settle = wake?.held?.() ? AbortSignal.timeout(HELD_WAKE_SETTLE_MS) : void 0;
|
|
49936
49989
|
for (;;) try {
|
|
49937
|
-
await runListen(
|
|
49990
|
+
await runListen(settle ? {
|
|
49991
|
+
...options,
|
|
49992
|
+
signal: AbortSignal.any([controller.signal, settle])
|
|
49993
|
+
} : options);
|
|
49938
49994
|
break;
|
|
49939
49995
|
} catch (error) {
|
|
49940
49996
|
if (!isListenLockContention(error) || hookEventName !== "SessionStart" || controller.signal.aborted) throw error;
|
|
@@ -49944,6 +50000,7 @@ var ListenCommand = class ListenCommand extends Command {
|
|
|
49944
50000
|
await new Promise((resolve) => setTimeout(resolve, Math.min(RESUME_LOCK_RETRY_STEP_MS, remaining)));
|
|
49945
50001
|
}
|
|
49946
50002
|
wake?.completed();
|
|
50003
|
+
if (settle?.aborted && !controller.signal.aborted) wake?.wakeHeld?.();
|
|
49947
50004
|
} while (wake && !wake.wakeId() && !wake.status() && !controller.signal.aborted);
|
|
49948
50005
|
} else {
|
|
49949
50006
|
const notify = options.notifySession;
|
|
@@ -52406,18 +52463,31 @@ async function runMachineDoctor(options) {
|
|
|
52406
52463
|
"profiles.orphaned": {
|
|
52407
52464
|
inspect: async () => {
|
|
52408
52465
|
const result = await inspectProfiles();
|
|
52409
|
-
const
|
|
52410
|
-
|
|
52411
|
-
const
|
|
52412
|
-
|
|
52466
|
+
const at = options.sessionDisconnect?.now?.() ?? now();
|
|
52467
|
+
const pending = pendingSessionDisconnects(options.configDir, at);
|
|
52468
|
+
const stale = staleSessionAgents(options.configDir, at);
|
|
52469
|
+
if (!pending.length && !stale.length) return result;
|
|
52470
|
+
const addresses = (records) => {
|
|
52471
|
+
const list = records.flatMap((record) => record.address ? [record.address] : []);
|
|
52472
|
+
return list.length ? ` (${list.join(", ")})` : "";
|
|
52473
|
+
};
|
|
52474
|
+
return check("profiles.orphaned", "fail", `${[...pending.length ? [`${pending.length} ended sessions still need their agent disconnected${addresses(pending)}; a repair retries it.`] : [], ...stale.length ? [`${stale.length} sessions ended more than 30 days ago without starting again and still hold the agent session-register created for them${addresses(stale)}; a repair disconnects it.`] : []].join(" ")}${result.status === "ok" ? "" : ` ${result.detail}`}`, { fixable: true });
|
|
52413
52475
|
},
|
|
52414
52476
|
repair: async () => {
|
|
52477
|
+
const stale = await revokeStaleSessionAgents(options.configDir, {
|
|
52478
|
+
env,
|
|
52479
|
+
fetch: options.fetch,
|
|
52480
|
+
dependencies: {
|
|
52481
|
+
now,
|
|
52482
|
+
...options.sessionDisconnect
|
|
52483
|
+
}
|
|
52484
|
+
});
|
|
52415
52485
|
const retried = await retryPendingDisconnects(options.configDir, {
|
|
52416
52486
|
env,
|
|
52417
52487
|
fetch: options.fetch,
|
|
52418
52488
|
...options.sessionDisconnect ? { dependencies: options.sessionDisconnect } : {}
|
|
52419
52489
|
});
|
|
52420
|
-
return await moveOrphans() || retried > 0;
|
|
52490
|
+
return await moveOrphans() || retried > 0 || stale > 0;
|
|
52421
52491
|
}
|
|
52422
52492
|
}
|
|
52423
52493
|
};
|
|
@@ -56221,6 +56291,11 @@ var ReplyCommand = class ReplyCommand extends Command {
|
|
|
56221
56291
|
const repeatLine = formatRepeatStarted(result, repeat);
|
|
56222
56292
|
if (repeatLine) process.stderr.write(`${repeatLine}\n`);
|
|
56223
56293
|
if (outcome === "not_sent") restoreAutoWorking(halted);
|
|
56294
|
+
const answered = priorRepliesCheck.status === "checked" && priorRepliesCheck.detail?.id === emailId ? priorRepliesCheck.detail : null;
|
|
56295
|
+
if (outcome !== "not_sent" && outcome !== "uncertain" && sessionKey && auth.connectedAgent) await clearReadPendingMail(this.config.configDir, auth.connectedAgent.profileName, sessionKey.slice(sessionKey.indexOf(":") + 1), emailId, answered ? {
|
|
56296
|
+
thread_id: answered.thread_id ?? null,
|
|
56297
|
+
received_at: answered.received_at
|
|
56298
|
+
} : null).catch(() => void 0);
|
|
56224
56299
|
const exitCode = sendOutcomeExitCode(outcome);
|
|
56225
56300
|
if (exitCode !== 0) process.exitCode = exitCode;
|
|
56226
56301
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { N as agentProfileDirectory, P as agentProfileName, R as loadConnectedAgentProfile, j as AGENT_PROFILE_ENV } from "../cli-config-DMszFbGn.js";
|
|
2
2
|
import { d as readMailJson } from "../shared-mail-files-MwlVE90c.js";
|
|
3
|
-
import { _ as detectAgentRuntime, l as SESSION_UUID, t as notificationScope } from "../notify-session-
|
|
3
|
+
import { _ as detectAgentRuntime, l as SESSION_UUID, t as notificationScope } from "../notify-session-CVZtEboh.js";
|
|
4
4
|
import { a as claimBackgroundListenRestart, n as backgroundListenRestartable, r as backgroundListenStatus } from "../listen-background--0peztKE.js";
|
|
5
5
|
import { join } from "node:path";
|
|
6
6
|
import { spawn } from "node:child_process";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { h as sendPreparedSignal, p as prepareSignalEmail } from "./repeats-BL7ZC-_6-BZ-MphTV.js";
|
|
2
|
-
import { T as bareAddress, Vn as listSentEmails, ar as sendEmail, bt as successfulSendOutcome, en as createEndpoint, it as classifySendError, o as extractErrorPayload, vn as getEmail } from "./api-command-
|
|
2
|
+
import { T as bareAddress, Vn as listSentEmails, ar as sendEmail, bt as successfulSendOutcome, en as createEndpoint, it as classifySendError, o as extractErrorPayload, vn as getEmail } from "./api-command-C58Oh38I.js";
|
|
3
3
|
import { _ as acquireListenLock, b as listenProcessIdentity, c as mailTime, d as readMailJson, f as removeMailFile, h as writeMailJson, i as mailId, l as privateMailDirectory, m as withMailLock, n as invalidSharedMail, o as mailObject, p as syncMailDirectory, r as mailAddress, s as mailString, t as SharedMailStateError, v as compareListenProcessIdentity, y as listenIdentity } from "./shared-mail-files-MwlVE90c.js";
|
|
4
4
|
import { a as scopedChatSenderTrust, i as readBeforeDeadline, n as isPlainChatReply } from "./scoped-chat-Dsark9hm.js";
|
|
5
5
|
import { n as tryOwnSharedMail, r as waitForSharedMailChange, t as readSharedMailOwner } from "./shared-mail-watch-DtKpsgg8.js";
|
|
@@ -158,6 +158,12 @@ line or check result names.
|
|
|
158
158
|
are responding to, and address each message they sent since your last
|
|
159
159
|
reply; never send a generic status that ignores their question. See
|
|
160
160
|
[Answer the latest message](references/conversations.md#answer-the-latest-message).
|
|
161
|
+
When the message has other To or Cc recipients, add `--all` so everyone on
|
|
162
|
+
it stays on it; a plain reply goes to the sender only. Never drop
|
|
163
|
+
recipients silently: if a reply is deliberately private, say so in it.
|
|
164
|
+
Continue an existing discussion in its thread rather than with a new
|
|
165
|
+
`primitive send`; see
|
|
166
|
+
[Keep one discussion in one thread](references/conversations.md#keep-one-discussion-in-one-thread).
|
|
161
167
|
Send `primitive signal typing --id <id>` just before composing a longer
|
|
162
168
|
answer. If you pause on a request from anyone other than your owner (to
|
|
163
169
|
ask your owner, or to wait on something else), or decide not to act on
|