primcli 1.48.0 → 1.49.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/dist/{api-command-DzQ8KxD9.js → api-command-BixHVNwQ.js} +9 -5
- package/dist/{connect-skill-DHPc9dVN.js → connect-skill-DBkhFAkO.js} +3 -3
- package/dist/{machine-session-BaJ1Xmdm.js → machine-session-BEkDi4_N.js} +590 -130
- package/dist/oclif/auto-signal-worker.js +2 -2
- package/dist/oclif/auto-signals.js +1 -1
- package/dist/oclif/index.js +215 -35
- package/dist/oclif/listen-supervisor.js +1 -1
- package/dist/oclif/receiver-heal.js +2 -2
- package/dist/{scoped-chat-DhxtuNXs.js → scoped-chat-DSLrmgWQ.js} +1 -1
- package/dist/{signal-command-BbeV2Nd8.js → signal-command-D0Rig6eA.js} +4 -4
- package/dist/skills/primitive-connect/SKILL.md +16 -266
- package/dist/skills/primitive-connect/references/manual-setup.md +294 -0
- package/dist/skills/primitive-connect.json +4 -3
- package/package.json +1 -1
- /package/dist/{listen-background-CyLc8VBn.js → listen-background-CMfxkeVP.js} +0 -0
- /package/dist/{repeats-D2xtLium-DdiJECLI.js → repeats-D2xtLium-B8Wq41vG.js} +0 -0
- /package/dist/{shared-mail-watch-BUfUaq6j.js → shared-mail-watch-CWhpfJ0N.js} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { A as readThreadContext, Mt as createAuthenticatedCliApiClient, fn as getSentEmail } from "../api-command-
|
|
1
|
+
import { A as readThreadContext, Mt as createAuthenticatedCliApiClient, fn as getSentEmail } from "../api-command-BixHVNwQ.js";
|
|
2
2
|
import { _ as acquireListenLock } from "../shared-mail-files-SPPcis9g.js";
|
|
3
|
-
import { t as sendSignal } from "../signal-command-
|
|
3
|
+
import { t as sendSignal } from "../signal-command-D0Rig6eA.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";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { d as readMailJson, h as writeMailJson, i as mailId, l as privateMailDirectory, r as mailAddress } from "../shared-mail-files-SPPcis9g.js";
|
|
2
|
-
import { a as scopedChatSenderTrust, n as isPlainChatReply } from "../scoped-chat-
|
|
2
|
+
import { a as scopedChatSenderTrust, n as isPlainChatReply } from "../scoped-chat-DSLrmgWQ.js";
|
|
3
3
|
import { existsSync, readFileSync, readdirSync, unlinkSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { randomUUID } from "node:crypto";
|
|
5
5
|
import { join } from "node:path";
|
package/dist/oclif/index.js
CHANGED
|
@@ -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-
|
|
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-BixHVNwQ.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
|
|
5
|
-
import {
|
|
6
|
-
import { c as
|
|
7
|
-
import {
|
|
8
|
-
import { a as
|
|
9
|
-
import { a as
|
|
10
|
-
import { autoSignalEligible, dispatchAutoRead, dispatchAutoWorking, haltAutoWorking, restoreAutoWorking } from "./auto-signals.js";
|
|
4
|
+
import { $ as currentCliLocation, A as NETWORK_ADMISSION_PENDING_RETRY_MS, B as contactAgentAddress, C as invitationProfileName, D as externalReceivingState, E as RECEIVER_MODES, F as AddressNotesApiError, G as readAgentInvitation, H as agentConnectionStatus, I as addressNoteTarget, J as savedReceiver, K as receiverStatusCommand, L as runAddressNotesRequest, M as createNotificationContactPolicy, N as evaluateContactPolicy, O as verificationReplySubmitted, P as canonicalContactSelector, Q as claudeConfigDir, R as ContactsApiError, S as defaultAgentProfileName, T as runAgentConnect, U as agentInvitationHash, V as runContactRequest, W as connectAgent, X as recordHookMailCheck, Y as installClaudeWakeHook, Z as boundSessionProfiles, _ as disconnectAgent, _t as readHookLauncherWarning, a as endSession, at as hasMachineSessionHooks, b as identitySuggestions, c as pendingSessionDisconnects, ct as repairClaudeHooks, d as registerSession, dt as MachineFileError, et as describeSessionHookChange, f as retryPendingDisconnects, ft as inspectManagedBlock, g as AgentDisconnectError, gt as writeManagedFile, h as enrollmentResumes, ht as upsertManagedBlock, i as connectedProfilesForSession, it as findOnPath, j as NetworkAdmissionPendingError, k as ContactPolicyReadRetryError, l as psProcessInfo, lt as samePath, m as enrollAgent, mt as readManagedFile, n as OMP_MAIN, nt as ensureHookLauncher, o as headlessClaudeRun, ot as inspectClaudeHooks, p as runDetached, pt as jsonIndentation, q as refusalAfterReplacement, r as agentConnectionState, rt as ephemeralCliReason, st as readClaudeSettings, t as MACHINE_RUNTIMES, tt as describeSessionHookItem, u as readClaudeHookInput, ut as writeClaudeSettings, v as cliInvocation, vt as refreshOwnerMemberAddressPeriodically, w as pollCheckCommand, x as connectWarnings, y as generatedAgentName, yt as withOwnerMemberAddress, z as contactAddress } from "../machine-session-BEkDi4_N.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-DBkhFAkO.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-D0Rig6eA.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";
|
|
@@ -35252,9 +35252,25 @@ function readCursor(path) {
|
|
|
35252
35252
|
} catch {}
|
|
35253
35253
|
return null;
|
|
35254
35254
|
}
|
|
35255
|
-
/**
|
|
35256
|
-
|
|
35257
|
-
|
|
35255
|
+
/**
|
|
35256
|
+
* Mail the CLI handles itself: a presence probe whose authenticated
|
|
35257
|
+
* projection marks it as control mail (verified, or pending while its proof
|
|
35258
|
+
* settles; a rejected one is ordinary mail), and the exact setup challenge
|
|
35259
|
+
* this profile's setup recorded. Nothing is judged by sender or subject: the
|
|
35260
|
+
* owner can write from the control address, and that email is listed like
|
|
35261
|
+
* any other.
|
|
35262
|
+
*/
|
|
35263
|
+
function isControlMail(email, setupChallengeId) {
|
|
35264
|
+
return presenceDisposition(email) !== "ordinary" || setupChallengeId !== null && email.id === setupChallengeId;
|
|
35265
|
+
}
|
|
35266
|
+
/** The setup challenge's email ID saved by this profile's setup, if any. */
|
|
35267
|
+
function savedSetupChallengeId(directory) {
|
|
35268
|
+
try {
|
|
35269
|
+
const id = readMailJson(join(directory, "setup.json"))?.challenge?.id;
|
|
35270
|
+
return typeof id === "string" && id.length > 0 ? id : null;
|
|
35271
|
+
} catch {
|
|
35272
|
+
return null;
|
|
35273
|
+
}
|
|
35258
35274
|
}
|
|
35259
35275
|
async function checkAgentMail(options) {
|
|
35260
35276
|
const { identity } = options;
|
|
@@ -35263,9 +35279,14 @@ async function checkAgentMail(options) {
|
|
|
35263
35279
|
const release = acquireListenLock(directory, "mail-check");
|
|
35264
35280
|
const readCommand = (id) => `PRIMITIVE_AGENT_PROFILE=${identity.profileName} ${options.invocation ?? "primitive"} emails get --id ${id} --brief`;
|
|
35265
35281
|
const to = identity.agentAddress.toLowerCase();
|
|
35282
|
+
const ownerMember = (options.ownerMemberAddress ?? (() => refreshOwnerMemberAddressPeriodically({
|
|
35283
|
+
configDir: options.configDir,
|
|
35284
|
+
profileName: identity.profileName
|
|
35285
|
+
})))().catch(() => identity.ownerMemberAddress ?? null);
|
|
35266
35286
|
try {
|
|
35267
35287
|
const path = join(directory, CURSOR_FILE);
|
|
35268
35288
|
const saved = readCursor(path);
|
|
35289
|
+
const setupChallenge = savedSetupChallengeId(directory);
|
|
35269
35290
|
let cursor = saved;
|
|
35270
35291
|
const emails = [];
|
|
35271
35292
|
let controlSkipped = 0;
|
|
@@ -35285,7 +35306,7 @@ async function checkAgentMail(options) {
|
|
|
35285
35306
|
});
|
|
35286
35307
|
if (result.error || !result.data) throw new MailCheckApiError(result.error);
|
|
35287
35308
|
const rows = result.data.data ?? [];
|
|
35288
|
-
for (const row of rows) if (isControlMail(row,
|
|
35309
|
+
for (const row of rows) if (isControlMail(row, setupChallenge)) controlSkipped++;
|
|
35289
35310
|
else emails.push({
|
|
35290
35311
|
id: row.id,
|
|
35291
35312
|
received_at: row.received_at,
|
|
@@ -35304,6 +35325,7 @@ async function checkAgentMail(options) {
|
|
|
35304
35325
|
emails,
|
|
35305
35326
|
more,
|
|
35306
35327
|
control_skipped: controlSkipped,
|
|
35328
|
+
owner_member_address: await ownerMember,
|
|
35307
35329
|
profile: identity.profileName,
|
|
35308
35330
|
to,
|
|
35309
35331
|
read_command: readCommand("<id>")
|
|
@@ -35328,9 +35350,9 @@ var AgentCheckMailCommand = class AgentCheckMailCommand extends Command {
|
|
|
35328
35350
|
static summary = "Check a connected agent's mail since its last check";
|
|
35329
35351
|
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
35352
|
|
|
35331
|
-
Acknowledgements marked fyi and mail in muted threads are left out.
|
|
35353
|
+
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
35354
|
|
|
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>).`;
|
|
35355
|
+
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\`, \`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
35356
|
static examples = [`${AGENT_PROFILE_ENV}=connection-0123456789ab <%= config.bin %> agent check-mail --json`];
|
|
35335
35357
|
static flags = { json: Flags.boolean({ description: "Print JSON (already the default)" }) };
|
|
35336
35358
|
async run() {
|
|
@@ -35489,7 +35511,7 @@ function invocation$1(entry) {
|
|
|
35489
35511
|
return entry && /[\\/]_npx[\\/]/.test(entry) ? "npx -y primitive@latest" : "primitive";
|
|
35490
35512
|
}
|
|
35491
35513
|
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.`;
|
|
35514
|
+
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.`;
|
|
35493
35515
|
static summary = "Connect and verify an agent address";
|
|
35494
35516
|
static examples = [
|
|
35495
35517
|
"<%= config.bin %> agent connect --session \"$CODEX_THREAD_ID\" --name Research --info \"Reviews pull requests\" --json < private-invitation.txt",
|
|
@@ -35552,6 +35574,7 @@ var AgentConnectCommand = class AgentConnectCommand extends Command {
|
|
|
35552
35574
|
async run() {
|
|
35553
35575
|
const { flags } = await this.parse(AgentConnectCommand);
|
|
35554
35576
|
let pollProfile;
|
|
35577
|
+
let replaced = [];
|
|
35555
35578
|
try {
|
|
35556
35579
|
if (flags.status) {
|
|
35557
35580
|
const profileName = flags.profile ?? (process.env["PRIMITIVE_AGENT_PROFILE"]?.trim() || void 0);
|
|
@@ -35583,7 +35606,6 @@ var AgentConnectCommand = class AgentConnectCommand extends Command {
|
|
|
35583
35606
|
invitationText ??= await readAgentInvitation(process.stdin, process.stdin.isTTY);
|
|
35584
35607
|
return invitationText;
|
|
35585
35608
|
};
|
|
35586
|
-
let replaced = [];
|
|
35587
35609
|
let replaceExisting;
|
|
35588
35610
|
const guardSession = flags.resume ? null : flags.session !== void 0 ? session?.toLowerCase() ?? null : guardedSession(void 0);
|
|
35589
35611
|
if (guardSession && !flags["keep-existing"]) {
|
|
@@ -35659,8 +35681,10 @@ var AgentConnectCommand = class AgentConnectCommand extends Command {
|
|
|
35659
35681
|
else {
|
|
35660
35682
|
this.log(`Agent ${output.address}: verification ${output.verification.state}; receiving ${output.receiving.state}; skill ${output.skill.state}.`);
|
|
35661
35683
|
this.log(`Select it with ${output.selectProfile}.`);
|
|
35684
|
+
for (const warning of output.warnings) this.log(warning.message);
|
|
35662
35685
|
if (output.ownerNotifications === "silenced") this.log("Owner notifications remain silenced by the existing preference or policy.");
|
|
35663
35686
|
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.");
|
|
35687
|
+
if (poll && "fallbackDetail" in output.receiving) this.log(String(output.receiving.fallbackDetail));
|
|
35664
35688
|
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
35689
|
if (output.status !== "connected") this.log(`Resume: ${output.resumeCommand}`);
|
|
35666
35690
|
}
|
|
@@ -35680,16 +35704,23 @@ var AgentConnectCommand = class AgentConnectCommand extends Command {
|
|
|
35680
35704
|
configDir: this.config.configDir,
|
|
35681
35705
|
onlyIfUnknown: claimed.status === "claimed"
|
|
35682
35706
|
});
|
|
35707
|
+
const warnings = connectWarnings(this.config.configDir, result.identity.profileName);
|
|
35683
35708
|
if (flags.json) this.log(JSON.stringify(replaced.length ? {
|
|
35684
35709
|
...result,
|
|
35710
|
+
warnings,
|
|
35685
35711
|
replacedExisting: replaced
|
|
35686
|
-
} :
|
|
35712
|
+
} : {
|
|
35713
|
+
...result,
|
|
35714
|
+
warnings
|
|
35715
|
+
}));
|
|
35687
35716
|
else {
|
|
35688
35717
|
this.log(result.status === "claimed" ? "Agent profile saved. Email readiness is not yet verified." : "Agent profile already configured; no claim was sent.");
|
|
35689
35718
|
this.log(`Select it with PRIMITIVE_AGENT_PROFILE=${result.identity.profileName}.`);
|
|
35690
35719
|
this.log(result.ownerReportGuidance);
|
|
35720
|
+
for (const warning of warnings) this.log(warning.message);
|
|
35691
35721
|
}
|
|
35692
|
-
} catch (
|
|
35722
|
+
} catch (caught) {
|
|
35723
|
+
const error = refusalAfterReplacement(caught, replaced);
|
|
35693
35724
|
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
35725
|
}
|
|
35695
35726
|
}
|
|
@@ -35975,6 +36006,7 @@ var AgentEnrollCommand = class AgentEnrollCommand extends Command {
|
|
|
35975
36006
|
agentAddress: result.identity.agentAddress,
|
|
35976
36007
|
sessionId: flags.session
|
|
35977
36008
|
}) : null;
|
|
36009
|
+
const warnings = connectWarnings(this.config.configDir, result.identity.profileName);
|
|
35978
36010
|
const output = result.receiving.state === "poll" ? {
|
|
35979
36011
|
...result,
|
|
35980
36012
|
receiving: {
|
|
@@ -35982,10 +36014,20 @@ var AgentEnrollCommand = class AgentEnrollCommand extends Command {
|
|
|
35982
36014
|
mode: "poll",
|
|
35983
36015
|
checkCommand: pollCheckCommand(invocation(process.argv[1]), result.identity.profileName)
|
|
35984
36016
|
},
|
|
35985
|
-
externalHook
|
|
36017
|
+
externalHook,
|
|
36018
|
+
warnings
|
|
36019
|
+
} : flags.receiver === "external" && result.connection.status !== "owner_inactive" ? {
|
|
36020
|
+
...result,
|
|
36021
|
+
receiving: {
|
|
36022
|
+
...result.receiving,
|
|
36023
|
+
state: externalReceivingState(externalHook)
|
|
36024
|
+
},
|
|
36025
|
+
externalHook,
|
|
36026
|
+
warnings
|
|
35986
36027
|
} : {
|
|
35987
36028
|
...result,
|
|
35988
|
-
externalHook
|
|
36029
|
+
externalHook,
|
|
36030
|
+
warnings
|
|
35989
36031
|
};
|
|
35990
36032
|
const identity = identitySuggestions({
|
|
35991
36033
|
invocation: invocation(process.argv[1]),
|
|
@@ -36003,8 +36045,9 @@ var AgentEnrollCommand = class AgentEnrollCommand extends Command {
|
|
|
36003
36045
|
};
|
|
36004
36046
|
if (flags.json) this.log(JSON.stringify(printed));
|
|
36005
36047
|
else {
|
|
36006
|
-
this.log(`Agent ${result.identity.agentAddress}: pairing ${result.connection.status}; verification ${result.verification.state}; receiving ${
|
|
36048
|
+
this.log(`Agent ${result.identity.agentAddress}: pairing ${result.connection.status}; verification ${result.verification.state}; receiving ${output.receiving.state}.`);
|
|
36007
36049
|
this.log(`Select it with PRIMITIVE_AGENT_PROFILE=${result.identity.profileName}.`);
|
|
36050
|
+
for (const warning of warnings) this.log(warning.message);
|
|
36008
36051
|
if (flags["contact-requests"]) this.log(`Contact requests: ${result.contactRequestPolicy}.`);
|
|
36009
36052
|
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
36053
|
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.");
|
|
@@ -36629,6 +36672,66 @@ var AgentSessionRegisterCommand = class AgentSessionRegisterCommand extends Comm
|
|
|
36629
36672
|
}
|
|
36630
36673
|
};
|
|
36631
36674
|
//#endregion
|
|
36675
|
+
//#region src/oclif/commands/agent-status.ts
|
|
36676
|
+
/**
|
|
36677
|
+
* Picks the profile `agent status` reads: an explicit --profile, then
|
|
36678
|
+
* PRIMITIVE_AGENT_PROFILE, then the one address connected for this runtime
|
|
36679
|
+
* session. Null when none applies or the session has several addresses.
|
|
36680
|
+
*/
|
|
36681
|
+
function statusProfile(params) {
|
|
36682
|
+
const env = params.env ?? process.env;
|
|
36683
|
+
const chosen = params.profile ?? (env["PRIMITIVE_AGENT_PROFILE"]?.trim() || void 0);
|
|
36684
|
+
if (chosen) return { profile: chosen };
|
|
36685
|
+
const session = guardedSession(void 0, env);
|
|
36686
|
+
if (!session) return {
|
|
36687
|
+
profile: null,
|
|
36688
|
+
bound: []
|
|
36689
|
+
};
|
|
36690
|
+
const { others } = inspectSessionAddresses({
|
|
36691
|
+
configDir: params.configDir,
|
|
36692
|
+
session
|
|
36693
|
+
});
|
|
36694
|
+
const only = others.length === 1 ? others[0] : void 0;
|
|
36695
|
+
return only ? { profile: only.profile } : {
|
|
36696
|
+
profile: null,
|
|
36697
|
+
bound: others.map((row) => row.profile)
|
|
36698
|
+
};
|
|
36699
|
+
}
|
|
36700
|
+
/** A hidden alias of `agent connect --status`, for the command agents guess. */
|
|
36701
|
+
var AgentStatusCommand = class AgentStatusCommand extends Command {
|
|
36702
|
+
static hidden = true;
|
|
36703
|
+
static summary = "Show this agent's saved connection (agent connect --status)";
|
|
36704
|
+
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.`;
|
|
36705
|
+
static flags = {
|
|
36706
|
+
profile: Flags.string({ description: "Local agent profile name" }),
|
|
36707
|
+
json: Flags.boolean({ description: "Print the status as JSON" })
|
|
36708
|
+
};
|
|
36709
|
+
async run() {
|
|
36710
|
+
const { flags } = await this.parse(AgentStatusCommand);
|
|
36711
|
+
const picked = statusProfile({
|
|
36712
|
+
configDir: this.config.configDir,
|
|
36713
|
+
profile: flags.profile
|
|
36714
|
+
});
|
|
36715
|
+
if (picked.profile === null) {
|
|
36716
|
+
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.`;
|
|
36717
|
+
this.log(flags.json ? JSON.stringify({
|
|
36718
|
+
status: "not_configured",
|
|
36719
|
+
profileName: null,
|
|
36720
|
+
...picked.bound.length > 1 ? { profiles: picked.bound } : {},
|
|
36721
|
+
detail
|
|
36722
|
+
}) : detail);
|
|
36723
|
+
process.exitCode = 1;
|
|
36724
|
+
return;
|
|
36725
|
+
}
|
|
36726
|
+
await AgentConnectCommand.run([
|
|
36727
|
+
"--status",
|
|
36728
|
+
"--profile",
|
|
36729
|
+
picked.profile,
|
|
36730
|
+
...flags.json ? ["--json"] : []
|
|
36731
|
+
], this.config);
|
|
36732
|
+
}
|
|
36733
|
+
};
|
|
36734
|
+
//#endregion
|
|
36632
36735
|
//#region src/oclif/commands/agent-upgrade.ts
|
|
36633
36736
|
/**
|
|
36634
36737
|
* Interactive upgrade of an emailless agent account to a full developer
|
|
@@ -41505,7 +41608,7 @@ async function buildEmailBrief(input) {
|
|
|
41505
41608
|
connected_agent_verified: detail.sender_connected_agent_verified === true
|
|
41506
41609
|
},
|
|
41507
41610
|
thread_id: threadId,
|
|
41508
|
-
in_thread: sentInThread(thread, self) ?? null,
|
|
41611
|
+
in_thread: sentInThread(thread, self, input.isOwnSignal) ?? null,
|
|
41509
41612
|
...alsoAddressed(otherParticipants(detail, self)),
|
|
41510
41613
|
attachments: briefAttachments(detail, { hideInteractionPart: interaction?.hint === "card" || interaction?.hint === "status" }),
|
|
41511
41614
|
newer: thread?.newerInboundCount === void 0 ? null : {
|
|
@@ -41614,6 +41717,7 @@ async function runBrief(command, flags) {
|
|
|
41614
41717
|
client: apiClient.client,
|
|
41615
41718
|
detail,
|
|
41616
41719
|
connected,
|
|
41720
|
+
isOwnSignal: (sentId) => isSentSignal(command.config.configDir, sentId),
|
|
41617
41721
|
signal: AbortSignal.timeout(3e4)
|
|
41618
41722
|
});
|
|
41619
41723
|
command.log(flags.json ? JSON.stringify(brief, null, 2) : renderEmailBrief(brief));
|
|
@@ -43317,7 +43421,7 @@ const PRIMITIVE_TEAM_AUTHOR = {
|
|
|
43317
43421
|
url: "https://primitive.dev"
|
|
43318
43422
|
};
|
|
43319
43423
|
const SDK_VERSION_RANGE = "^1.35.0";
|
|
43320
|
-
const CLI_VERSION_RANGE = "^1.
|
|
43424
|
+
const CLI_VERSION_RANGE = "^1.49.0";
|
|
43321
43425
|
const ESBUILD_VERSION_RANGE = "^0.27.0";
|
|
43322
43426
|
function renderHandler() {
|
|
43323
43427
|
return `// env.PRIMITIVE_API_KEY, env.PRIMITIVE_WEBHOOK_SECRET, and
|
|
@@ -46848,6 +46952,7 @@ async function runSharedNotificationListen(options) {
|
|
|
46848
46952
|
contact: !authorization?.contactRequest
|
|
46849
46953
|
}),
|
|
46850
46954
|
localInThread: false,
|
|
46955
|
+
isOwnSignal: (sentId) => isSentSignal(options.configDir, sentId),
|
|
46851
46956
|
signal: nextSignal
|
|
46852
46957
|
});
|
|
46853
46958
|
} catch {
|
|
@@ -47563,6 +47668,10 @@ async function createWakeMail(options) {
|
|
|
47563
47668
|
});
|
|
47564
47669
|
const identity = auth.connectedAgent;
|
|
47565
47670
|
const recipient = identity?.agentAddress;
|
|
47671
|
+
if (identity) refreshOwnerMemberAddressPeriodically({
|
|
47672
|
+
configDir: options.configDir,
|
|
47673
|
+
profileName: identity.profileName
|
|
47674
|
+
});
|
|
47566
47675
|
const policy = recipient ? apiContactPolicy(apiClient.client, recipient, options.contactRequests) : void 0;
|
|
47567
47676
|
const notices = identity && options.contactRequests ? openContactRequestNotices(options.configDir, identity) : void 0;
|
|
47568
47677
|
const activatedAt = notices ? Date.parse(notices.activate()) : 0;
|
|
@@ -47799,6 +47908,7 @@ async function createWakeMail(options) {
|
|
|
47799
47908
|
contact: admission.kind === "allowed"
|
|
47800
47909
|
}),
|
|
47801
47910
|
localInThread: Boolean(requested || followed),
|
|
47911
|
+
isOwnSignal: (sentId) => isSentSignal(options.configDir, sentId),
|
|
47802
47912
|
signal
|
|
47803
47913
|
});
|
|
47804
47914
|
if (!await recordNotice(detail, {
|
|
@@ -49848,7 +49958,7 @@ function shellQuote(value) {
|
|
|
49848
49958
|
}
|
|
49849
49959
|
const MANAGED_SUFFIX = /\bagent session-register --runtime codex --hook\s*$/;
|
|
49850
49960
|
function codexHookCommand(cli) {
|
|
49851
|
-
return `${shellQuote(cli.
|
|
49961
|
+
return `${shellQuote(cli.runtimeNode)} ${shellQuote(cli.entry)} agent session-register --runtime codex --hook`;
|
|
49852
49962
|
}
|
|
49853
49963
|
/** A SessionStart hook this CLI installed, from any CLI path or version. */
|
|
49854
49964
|
function isManaged(hook) {
|
|
@@ -50074,6 +50184,10 @@ function repairCodexHook(settings, cli) {
|
|
|
50074
50184
|
changed
|
|
50075
50185
|
};
|
|
50076
50186
|
}
|
|
50187
|
+
/** Whether Codex hooks.json carries the SessionStart hook, from any CLI path. */
|
|
50188
|
+
function hasCodexSessionHook(settings) {
|
|
50189
|
+
return managedPositions(settings).length > 0;
|
|
50190
|
+
}
|
|
50077
50191
|
function writeCodexHooks(params) {
|
|
50078
50192
|
const original = params.read.state === "present" ? params.read.text : null;
|
|
50079
50193
|
const indent = original === null ? 2 : jsonIndentation(original);
|
|
@@ -50312,6 +50426,29 @@ async function ownerConnectionStatuses(credentials, fetchImpl) {
|
|
|
50312
50426
|
}
|
|
50313
50427
|
return partial();
|
|
50314
50428
|
}
|
|
50429
|
+
/** Whether any saved agent profile still holds a credential. */
|
|
50430
|
+
function connectedProfileSaved(configDir) {
|
|
50431
|
+
let names;
|
|
50432
|
+
try {
|
|
50433
|
+
names = readdirSync(join(agentProfilesDirectory(configDir), "profiles"));
|
|
50434
|
+
} catch {
|
|
50435
|
+
return false;
|
|
50436
|
+
}
|
|
50437
|
+
return names.some((name) => {
|
|
50438
|
+
try {
|
|
50439
|
+
agentProfileName(name);
|
|
50440
|
+
return loadConnectedAgentProfile(configDir, name) !== null;
|
|
50441
|
+
} catch {
|
|
50442
|
+
return false;
|
|
50443
|
+
}
|
|
50444
|
+
});
|
|
50445
|
+
}
|
|
50446
|
+
/**
|
|
50447
|
+
* Why a machine-wide check does not apply: agents on this machine were
|
|
50448
|
+
* connected one session at a time with `agent connect`, and no member login
|
|
50449
|
+
* (which machine-wide session registration needs) is saved.
|
|
50450
|
+
*/
|
|
50451
|
+
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
50452
|
function check(id, status, detail, extra = {}) {
|
|
50316
50453
|
return {
|
|
50317
50454
|
id,
|
|
@@ -50336,9 +50473,21 @@ async function runMachineDoctor(options) {
|
|
|
50336
50473
|
const selected = (runtime) => !options.runtimes || options.runtimes.has(runtime);
|
|
50337
50474
|
const present = Object.fromEntries(MACHINE_RUNTIMES.map((runtime) => [runtime, runtimePresent(runtime, paths, env)]));
|
|
50338
50475
|
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
|
|
50476
|
+
const cli = currentCliLocation(options.cliEntry, env, options.execPath, {
|
|
50477
|
+
configDir: options.configDir,
|
|
50478
|
+
platform: options.platform
|
|
50479
|
+
});
|
|
50340
50480
|
const ephemeral = cli ? ephemeralCliReason(cli.entry) : null;
|
|
50341
|
-
const
|
|
50481
|
+
const ephemeralBlocked = ephemeral ? `This CLI runs from ${ephemeral}, which can be deleted; install it with \`npm install -g primitive\` before repairing hooks.` : null;
|
|
50482
|
+
const hookBlocked = !cli ? "This CLI's hook scripts were not found next to it." : cli.launcher ? null : ephemeralBlocked;
|
|
50483
|
+
const codexBlocked = !cli ? "This CLI's hook scripts were not found next to it." : ephemeralBlocked;
|
|
50484
|
+
const perConnection = !(() => {
|
|
50485
|
+
try {
|
|
50486
|
+
return loadCliCredentials(options.configDir) !== null;
|
|
50487
|
+
} catch {
|
|
50488
|
+
return true;
|
|
50489
|
+
}
|
|
50490
|
+
})() && connectedProfileSaved(options.configDir);
|
|
50342
50491
|
const skillEnv = {
|
|
50343
50492
|
...env,
|
|
50344
50493
|
CLAUDE_CONFIG_DIR: paths.claudeDir,
|
|
@@ -50365,6 +50514,7 @@ async function runMachineDoctor(options) {
|
|
|
50365
50514
|
path: target,
|
|
50366
50515
|
action: "edit_file"
|
|
50367
50516
|
});
|
|
50517
|
+
if (perConnection && (read.state === "absent" || inspectManagedBlock(read.text, body).state === "missing")) return check(id, "skip", PER_CONNECTION_SKIP, { path: target });
|
|
50368
50518
|
if (read.state === "absent") return check(id, "fail", `${target} does not exist yet.`, {
|
|
50369
50519
|
path: target,
|
|
50370
50520
|
fixable: true
|
|
@@ -50409,6 +50559,7 @@ async function runMachineDoctor(options) {
|
|
|
50409
50559
|
} catch {
|
|
50410
50560
|
info = null;
|
|
50411
50561
|
}
|
|
50562
|
+
if (!info && perConnection) return check(id, "skip", PER_CONNECTION_SKIP, { path: target });
|
|
50412
50563
|
if (!info) return check(id, "fail", `Not installed at ${target}.`, {
|
|
50413
50564
|
path: target,
|
|
50414
50565
|
fixable: true
|
|
@@ -50467,12 +50618,20 @@ async function runMachineDoctor(options) {
|
|
|
50467
50618
|
},
|
|
50468
50619
|
restoreProfiles: options.profiles
|
|
50469
50620
|
};
|
|
50621
|
+
const launcherMissing = () => !!cli?.launcher && settingsRead.ok && !existsSync(cli.launcher.path) && JSON.stringify(settingsRead.settings).includes(JSON.stringify(cli.launcher.path));
|
|
50470
50622
|
const hookCheck = (id) => ({
|
|
50471
50623
|
inspect: () => {
|
|
50472
50624
|
const skip = skipRuntime("claude");
|
|
50473
50625
|
if (skip) return check(id, "skip", skip);
|
|
50474
50626
|
if (!settingsRead.ok) return check(id, "fail", "Claude settings.json is invalid; repair it first.", { path: join(paths.claudeDir, "settings.json") });
|
|
50475
|
-
|
|
50627
|
+
if (perConnection && id !== "claude.hook.stop" && !hasMachineSessionHooks(settingsRead.settings)) return check(id, "skip", PER_CONNECTION_SKIP, { path: join(paths.claudeDir, "settings.json") });
|
|
50628
|
+
const inspected = inspectClaudeHooks(settingsRead.settings, hookContext)[id];
|
|
50629
|
+
const finding = inspected.status === "fail" && launcherMissing() ? {
|
|
50630
|
+
...inspected,
|
|
50631
|
+
detail: `${inspected.detail} The hook launcher ${cli?.launcher?.path} is missing; a repair writes it again.`
|
|
50632
|
+
} : inspected;
|
|
50633
|
+
const launcherWarning = id === "claude.hook.stop" && cli?.launcher ? readHookLauncherWarning(options.configDir) : null;
|
|
50634
|
+
if (launcherWarning && finding.status === "ok") return check(id, "warn", `${finding.detail} The last hook run reported: ${launcherWarning}`, { path: join(paths.claudeDir, "settings.json") });
|
|
50476
50635
|
return check(id, finding.status, finding.detail, {
|
|
50477
50636
|
fixable: finding.fixable,
|
|
50478
50637
|
path: join(paths.claudeDir, "settings.json"),
|
|
@@ -50487,9 +50646,17 @@ async function runMachineDoctor(options) {
|
|
|
50487
50646
|
repair: () => {
|
|
50488
50647
|
if (!settingsRead.ok) return false;
|
|
50489
50648
|
const findings = inspectClaudeHooks(settingsRead.settings, hookContext);
|
|
50490
|
-
const
|
|
50649
|
+
const machineHooksSkipped = perConnection && !hasMachineSessionHooks(settingsRead.settings);
|
|
50650
|
+
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
50651
|
const repaired = repairClaudeHooks(settingsRead.settings, hookContext, new Set(ids), { profiles: options.profiles });
|
|
50492
|
-
|
|
50652
|
+
const restoreLauncher = launcherMissing();
|
|
50653
|
+
if (!repaired.changed.size && !restoreLauncher) return false;
|
|
50654
|
+
if (cli && hookBlocked === null) try {
|
|
50655
|
+
ensureHookLauncher(cli);
|
|
50656
|
+
} catch {
|
|
50657
|
+
throw new MachineFileError(`The hook launcher ${cli.launcher?.path ?? ""} could not be written.`);
|
|
50658
|
+
}
|
|
50659
|
+
if (!repaired.changed.size) return id === "claude.hook.stop";
|
|
50493
50660
|
writeClaudeSettings({
|
|
50494
50661
|
claudeDir: paths.claudeDir,
|
|
50495
50662
|
read: settingsRead.read,
|
|
@@ -50512,17 +50679,21 @@ async function runMachineDoctor(options) {
|
|
|
50512
50679
|
path: read.path,
|
|
50513
50680
|
action: "edit_file"
|
|
50514
50681
|
});
|
|
50682
|
+
if (perConnection && !hasCodexSessionHook(read.settings)) return check(id, "skip", PER_CONNECTION_SKIP, { path: read.path });
|
|
50515
50683
|
const configToml = readManagedFile(join(paths.codexHome, "config.toml"));
|
|
50516
|
-
const finding = inspectCodexHook(read,
|
|
50684
|
+
const finding = inspectCodexHook(read, {
|
|
50685
|
+
cli,
|
|
50686
|
+
blocked: codexBlocked
|
|
50687
|
+
}, configToml.state === "present" ? configToml.text : null);
|
|
50517
50688
|
return check(id, finding.status, finding.detail, {
|
|
50518
50689
|
fixable: finding.fixable,
|
|
50519
50690
|
path: read.path,
|
|
50520
|
-
...finding.status === "fail" && !finding.fixable &&
|
|
50691
|
+
...finding.status === "fail" && !finding.fixable && codexBlocked ? { action: "install_cli" } : {}
|
|
50521
50692
|
});
|
|
50522
50693
|
},
|
|
50523
50694
|
repair: () => {
|
|
50524
50695
|
const read = readCodexHooks(paths.codexHome);
|
|
50525
|
-
if (!read.ok || !cli ||
|
|
50696
|
+
if (!read.ok || !cli || codexBlocked) return false;
|
|
50526
50697
|
const repaired = repairCodexHook(read.settings, cli);
|
|
50527
50698
|
if (!repaired.changed) return false;
|
|
50528
50699
|
writeCodexHooks({
|
|
@@ -50635,10 +50806,18 @@ async function runMachineDoctor(options) {
|
|
|
50635
50806
|
} },
|
|
50636
50807
|
"cli.path_stable": { inspect: () => {
|
|
50637
50808
|
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\`.`, {
|
|
50809
|
+
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
50810
|
action: "install_cli",
|
|
50640
50811
|
path: cli.entry
|
|
50641
50812
|
});
|
|
50813
|
+
if (ephemeral) {
|
|
50814
|
+
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.`;
|
|
50815
|
+
const codexRead = readCodexHooks(paths.codexHome);
|
|
50816
|
+
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.`, {
|
|
50817
|
+
action: "install_cli",
|
|
50818
|
+
path: cli.entry
|
|
50819
|
+
}) : check("cli.path_stable", "ok", launcherNote, { path: cli.entry });
|
|
50820
|
+
}
|
|
50642
50821
|
const onPath = findOnPath("primitive", env);
|
|
50643
50822
|
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
50823
|
return check("cli.path_stable", "ok", `Hooks use ${cli.node} and ${cli.entry}.`, { path: cli.entry });
|
|
@@ -50650,7 +50829,7 @@ async function runMachineDoctor(options) {
|
|
|
50650
50829
|
} catch {
|
|
50651
50830
|
return check("auth.member_login", "fail", "The saved login file is unreadable. Sign in again.", { action: "login" });
|
|
50652
50831
|
}
|
|
50653
|
-
if (!saved) return check("auth.member_login", "fail", "No saved member login on this machine.", { action: "login" });
|
|
50832
|
+
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
50833
|
let credentials;
|
|
50655
50834
|
try {
|
|
50656
50835
|
credentials = await refreshStoredCliCredentials({
|
|
@@ -50804,7 +50983,7 @@ function renderCheck(check) {
|
|
|
50804
50983
|
}
|
|
50805
50984
|
var MachineDoctorCommand = class MachineDoctorCommand extends Command {
|
|
50806
50985
|
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.";
|
|
50986
|
+
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
50987
|
static examples = [
|
|
50809
50988
|
"<%= config.bin %> machine doctor",
|
|
50810
50989
|
"<%= config.bin %> machine doctor --json",
|
|
@@ -57434,6 +57613,7 @@ const COMMANDS = {
|
|
|
57434
57613
|
completion: CompletionCommand,
|
|
57435
57614
|
"agent:upgrade": AgentUpgradeCommand,
|
|
57436
57615
|
"agent:connect": AgentConnectCommand,
|
|
57616
|
+
"agent:status": AgentStatusCommand,
|
|
57437
57617
|
"agent:check-mail": AgentCheckMailCommand,
|
|
57438
57618
|
"agent:disconnect": AgentDisconnectCommand,
|
|
57439
57619
|
"agent:enroll": AgentEnrollCommand,
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { s as runBackgroundListenSupervisor } from "../listen-background-
|
|
1
|
+
import { s as runBackgroundListenSupervisor } from "../listen-background-CMfxkeVP.js";
|
|
2
2
|
export { runBackgroundListenSupervisor };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { N as agentProfileDirectory, P as agentProfileName, R as loadConnectedAgentProfile, j as AGENT_PROFILE_ENV } from "../cli-config-DGrZCUfw.js";
|
|
2
2
|
import { d as readMailJson } from "../shared-mail-files-SPPcis9g.js";
|
|
3
|
-
import { m as SESSION_UUID, n as detectAgentRuntime, o as notificationScope } from "../connect-skill-
|
|
4
|
-
import { a as claimBackgroundListenRestart, n as backgroundListenRestartable, r as backgroundListenStatus } from "../listen-background-
|
|
3
|
+
import { m as SESSION_UUID, n as detectAgentRuntime, o as notificationScope } from "../connect-skill-DBkhFAkO.js";
|
|
4
|
+
import { a as claimBackgroundListenRestart, n as backgroundListenRestartable, r as backgroundListenStatus } from "../listen-background-CMfxkeVP.js";
|
|
5
5
|
import { join } from "node:path";
|
|
6
6
|
import { spawn } from "node:child_process";
|
|
7
7
|
import { homedir } from "node:os";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { _ as isTrustedSender, c as classifySignalContent } from "./repeats-D2xtLium-
|
|
1
|
+
import { _ as isTrustedSender, c as classifySignalContent } from "./repeats-D2xtLium-B8Wq41vG.js";
|
|
2
2
|
//#region src/oclif/presence-provenance.ts
|
|
3
3
|
function readPresenceProjection(detail) {
|
|
4
4
|
if (!detail || typeof detail !== "object") return null;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { Bt as createEndpoint, Dn as listSentEmails, Gn as sendEmail, T as bareAddress, in as getEmail, mt as successfulSendOutcome, o as extractErrorPayload, tt as classifySendError } from "./api-command-
|
|
1
|
+
import { Bt as createEndpoint, Dn as listSentEmails, Gn as sendEmail, T as bareAddress, in as getEmail, mt as successfulSendOutcome, o as extractErrorPayload, tt as classifySendError } from "./api-command-BixHVNwQ.js";
|
|
2
2
|
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-SPPcis9g.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { a as scopedChatSenderTrust, i as readBeforeDeadline, n as isPlainChatReply } from "./scoped-chat-DSLrmgWQ.js";
|
|
4
|
+
import { h as sendPreparedSignal, p as prepareSignalEmail } from "./repeats-D2xtLium-B8Wq41vG.js";
|
|
5
|
+
import { n as tryOwnSharedMail, r as waitForSharedMailChange, t as readSharedMailOwner } from "./shared-mail-watch-CWhpfJ0N.js";
|
|
6
6
|
import { recordSentSignal } from "./oclif/auto-signals.js";
|
|
7
7
|
import { Errors } from "@oclif/core";
|
|
8
8
|
import { opendirSync } from "node:fs";
|