primcli 1.49.0 → 1.51.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 +20 -3
- package/bin/claude-pending-mail.mjs +95 -1
- package/bin/claude-wake.mjs +3 -1
- package/dist/{api-command-BixHVNwQ.js → api-command-Bd21hvqY.js} +195 -6
- package/dist/{machine-session-BEkDi4_N.js → machine-session-DqxgyupM.js} +95 -50
- package/dist/{connect-skill-DBkhFAkO.js → notify-session-ejjYXO3O.js} +283 -242
- package/dist/oclif/auto-signal-worker.js +2 -2
- package/dist/oclif/auto-signals.js +1 -1
- package/dist/oclif/index.js +217 -32
- package/dist/oclif/receiver-heal.js +1 -1
- package/dist/{signal-command-D0Rig6eA.js → signal-command-DaQuMT8l.js} +2 -2
- package/dist/skills/primitive-connect/SKILL.md +3 -1
- package/dist/skills/primitive-connect/references/communication.md +7 -0
- package/dist/skills/primitive-connect.json +4 -4
- package/package.json +1 -1
- /package/dist/{scoped-chat-DSLrmgWQ.js → scoped-chat-BJVYBRim.js} +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { n as __exportAll } from "./rolldown-runtime-CNZpIYwj.js";
|
|
2
2
|
import { B as parseOwnerMemberAddress, F as agentProfilesDirectory, I as connectedAgentIdentity, L as connectedApiBaseUrl, M as AgentConnectionSetupError, N as agentProfileDirectory, P as agentProfileName, R as loadConnectedAgentProfile, U as saveConnectedAgentProfile, V as profileAlreadyConnectedMessage, W as PrimitiveApiClient, j as AGENT_PROFILE_ENV, x as loadCliCredentials, z as parseConnectedAgentProfile } from "./cli-config-DGrZCUfw.js";
|
|
3
|
-
import { $
|
|
3
|
+
import { $n as searchEmails, En as listAgentContacts, Gn as putAgentContactPolicy, Gt as refreshStoredCliCredentials, Kn as putContact, On as listContacts, Rn as listSentEmails, V as defaultConnectionName, Wn as putAgentContact, dn as getContact, hn as getEmail, jn as listDomains, nn as deleteAgentContact, nr as sendEmail, rn as deleteContact, un as getAgentContactPolicy } from "./api-command-Bd21hvqY.js";
|
|
4
4
|
import { _ as acquireListenLock, c as mailTime, d as readMailJson, f as removeMailFile, g as ListenStateError, h as writeMailJson, i as mailId, l as privateMailDirectory, o as mailObject, r as mailAddress, s as mailString } from "./shared-mail-files-SPPcis9g.js";
|
|
5
|
-
import { a as
|
|
6
|
-
import {
|
|
5
|
+
import { _ as detectAgentRuntime, a as NotificationRetryError, d as defaultSessionSocket, f as NativeSessionDisconnectedError, l as SESSION_UUID, t as notificationScope, u as connectNativeSession, v as installConnectSkill, x as readBundledConnectSkill } from "./notify-session-ejjYXO3O.js";
|
|
6
|
+
import { a as scopedChatSenderTrust } from "./scoped-chat-BJVYBRim.js";
|
|
7
7
|
import { l as stopBackgroundListen, r as backgroundListenStatus } from "./listen-background-CMfxkeVP.js";
|
|
8
8
|
import { t as readSharedMailOwner } from "./shared-mail-watch-CWhpfJ0N.js";
|
|
9
9
|
import { accessSync, chmodSync, closeSync, constants, copyFileSync, existsSync, fsyncSync, lstatSync, mkdirSync, openSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, rmdirSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
@@ -1636,6 +1636,7 @@ const MAX_INVITATION_BYTES = 4096;
|
|
|
1636
1636
|
const MAX_RESPONSE_BYTES = 32768;
|
|
1637
1637
|
const UNCERTAIN_CLAIM = "Setup did not complete safely. The invitation may have been consumed. Request a fresh invitation from the owner; do not retry this invitation.";
|
|
1638
1638
|
const INVITATION_UNAVAILABLE = "This invitation was already used, has expired, or was revoked, so it cannot connect this agent. Ask the owner to copy a fresh setup instruction from the app. Nothing was changed on this machine.";
|
|
1639
|
+
const INVITATION_ATTEMPTED_HERE = "An earlier setup on this machine already submitted this invitation and did not finish, so it was not submitted again; it may already be used. Ask the owner to copy a fresh setup instruction from the app. Nothing was changed on this machine.";
|
|
1639
1640
|
const INVITATION_INVALID = "Primitive rejected this invitation as invalid. Ask the owner to copy a fresh setup instruction from the app. Nothing was changed on this machine.";
|
|
1640
1641
|
/**
|
|
1641
1642
|
* The server answered the claim with a definite refusal, so nothing was
|
|
@@ -1683,12 +1684,70 @@ async function definiteClaimRefusal(response) {
|
|
|
1683
1684
|
}
|
|
1684
1685
|
return null;
|
|
1685
1686
|
}
|
|
1687
|
+
/** The message for an invitation another profile on this machine already claimed. */
|
|
1688
|
+
function invitationUsedHereMessage(address) {
|
|
1689
|
+
return `This invitation was already used on this machine${address ? ` to connect ${address}` : ""} under another profile, so it cannot connect this agent. Ask the owner to copy a fresh setup instruction from the app. Nothing was changed on this machine.`;
|
|
1690
|
+
}
|
|
1691
|
+
/**
|
|
1692
|
+
* A local record says this invitation was submitted before. It is never
|
|
1693
|
+
* submitted again: the claim is one-use, and a second submission could not
|
|
1694
|
+
* recover a credential lost with an earlier response. The refusal names the
|
|
1695
|
+
* address when the earlier attempt finished, and is a definite local refusal
|
|
1696
|
+
* either way, so a caller may discard whatever it created for this run.
|
|
1697
|
+
*/
|
|
1698
|
+
function earlierAttemptRefusal(configDir, journal, invitationHash) {
|
|
1699
|
+
const record = journal;
|
|
1700
|
+
let address = null;
|
|
1701
|
+
if (record?.status === "claimed" && typeof record.agent_address === "string") address = record.agent_address;
|
|
1702
|
+
else if (typeof record?.profile_name === "string") try {
|
|
1703
|
+
const earlier = loadConnectedAgentProfile(configDir, record.profile_name);
|
|
1704
|
+
if (earlier?.invitation_hash === invitationHash) address = earlier.agent_address;
|
|
1705
|
+
} catch {}
|
|
1706
|
+
return address !== null || record?.status === "claimed" ? new AgentInvitationRejectedError(invitationUsedHereMessage(address), "invitation_used_here") : new AgentInvitationRejectedError(INVITATION_ATTEMPTED_HERE, "invitation_attempted_here");
|
|
1707
|
+
}
|
|
1686
1708
|
/** Removes a directory only when it is empty. Best effort. */
|
|
1687
1709
|
function removeEmptyDirectory(path) {
|
|
1688
1710
|
try {
|
|
1689
1711
|
rmdirSync(path);
|
|
1690
1712
|
} catch {}
|
|
1691
1713
|
}
|
|
1714
|
+
const CONNECTION_NAME_FILE = "connection-name.json";
|
|
1715
|
+
/**
|
|
1716
|
+
* The display name this profile's claim reported, saved beside the profile
|
|
1717
|
+
* so a resumed setup can report it too. Undefined when none was saved.
|
|
1718
|
+
*/
|
|
1719
|
+
function savedConnectionName(configDir, profileName) {
|
|
1720
|
+
try {
|
|
1721
|
+
const saved = readMailJson(join(agentProfileDirectory(configDir, profileName), CONNECTION_NAME_FILE));
|
|
1722
|
+
return saved?.version === 1 ? claimedConnectionName({ data: { connection: { name: saved.name } } }) : void 0;
|
|
1723
|
+
} catch {
|
|
1724
|
+
return;
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
/**
|
|
1728
|
+
* Saves the connection's current display name beside its profile: from the
|
|
1729
|
+
* claim, and again after `agent rename`. Best effort: without it a resume
|
|
1730
|
+
* omits the name, as for a claim made by an older version.
|
|
1731
|
+
*/
|
|
1732
|
+
function saveConnectionName(configDir, profileName, name) {
|
|
1733
|
+
try {
|
|
1734
|
+
writeMailJson(join(agentProfileDirectory(configDir, profileName), CONNECTION_NAME_FILE), {
|
|
1735
|
+
version: 1,
|
|
1736
|
+
name
|
|
1737
|
+
});
|
|
1738
|
+
} catch {}
|
|
1739
|
+
}
|
|
1740
|
+
/** The display name a claim response reports, or undefined when unusable. */
|
|
1741
|
+
function claimedConnectionName(value) {
|
|
1742
|
+
const name = value?.data?.connection?.name;
|
|
1743
|
+
if (typeof name !== "string") return void 0;
|
|
1744
|
+
const trimmed = name.trim();
|
|
1745
|
+
const printable = Array.from(trimmed).every((character) => {
|
|
1746
|
+
const code = character.charCodeAt(0);
|
|
1747
|
+
return code >= 32 && !(code >= 127 && code <= 159) && code !== 8232 && code !== 8233;
|
|
1748
|
+
});
|
|
1749
|
+
return trimmed.length > 0 && trimmed.length <= 80 && printable ? trimmed : void 0;
|
|
1750
|
+
}
|
|
1692
1751
|
/** The receiver a saved profile's setup record names. Offline. */
|
|
1693
1752
|
function savedReceiver(configDir, profileName) {
|
|
1694
1753
|
try {
|
|
@@ -1903,12 +1962,18 @@ async function connectAgent(params) {
|
|
|
1903
1962
|
identity: connectedAgentIdentity(profileName, existing)
|
|
1904
1963
|
};
|
|
1905
1964
|
}
|
|
1965
|
+
const journal = join(directory, "claims", `${invitationHash}.json`);
|
|
1966
|
+
privateMailDirectory(join(directory, "claims"), true);
|
|
1967
|
+
let earlier;
|
|
1968
|
+
try {
|
|
1969
|
+
earlier = readMailJson(journal);
|
|
1970
|
+
} catch {
|
|
1971
|
+
throw new AgentConnectionSetupError(UNCERTAIN_CLAIM);
|
|
1972
|
+
}
|
|
1973
|
+
if (earlier !== null) throw earlierAttemptRefusal(params.configDir, earlier, invitationHash);
|
|
1906
1974
|
privateMailDirectory(join(directory, "profiles"), true);
|
|
1907
1975
|
const profileDirectory = agentProfileDirectory(params.configDir, profileName);
|
|
1908
1976
|
privateMailDirectory(profileDirectory, true);
|
|
1909
|
-
const journal = join(directory, "claims", `${invitationHash}.json`);
|
|
1910
|
-
privateMailDirectory(join(directory, "claims"), true);
|
|
1911
|
-
if (readMailJson(journal) !== null) throw new AgentConnectionSetupError(UNCERTAIN_CLAIM);
|
|
1912
1977
|
writeMailJson(journal, {
|
|
1913
1978
|
version: 1,
|
|
1914
1979
|
profile_name: profileName,
|
|
@@ -1940,11 +2005,23 @@ async function connectAgent(params) {
|
|
|
1940
2005
|
removeEmptyDirectory(profileDirectory);
|
|
1941
2006
|
throw refusal;
|
|
1942
2007
|
}
|
|
1943
|
-
const
|
|
2008
|
+
const body = await readClaimResponse(response);
|
|
2009
|
+
const profile = profileFromClaim(body, invitation, invitationHash, params.now ?? Date.now);
|
|
2010
|
+
const name = claimedConnectionName(body);
|
|
1944
2011
|
saveConnectedAgentProfile(params.configDir, profileName, profile);
|
|
2012
|
+
try {
|
|
2013
|
+
writeMailJson(journal, {
|
|
2014
|
+
version: 1,
|
|
2015
|
+
profile_name: profileName,
|
|
2016
|
+
status: "claimed",
|
|
2017
|
+
agent_address: profile.agent_address
|
|
2018
|
+
});
|
|
2019
|
+
} catch {}
|
|
2020
|
+
if (name !== void 0) saveConnectionName(params.configDir, profileName, name);
|
|
1945
2021
|
return {
|
|
1946
2022
|
status: "claimed",
|
|
1947
|
-
identity: connectedAgentIdentity(profileName, profile)
|
|
2023
|
+
identity: connectedAgentIdentity(profileName, profile),
|
|
2024
|
+
...name === void 0 ? {} : { name }
|
|
1948
2025
|
};
|
|
1949
2026
|
} catch (error) {
|
|
1950
2027
|
if (error instanceof AgentInvitationRejectedError) throw error;
|
|
@@ -3140,6 +3217,7 @@ async function setupAgent(params) {
|
|
|
3140
3217
|
privateMailDirectory(directory, true);
|
|
3141
3218
|
const release = acquireListenLock(directory, "setup");
|
|
3142
3219
|
let discardStub = false;
|
|
3220
|
+
let claimedName;
|
|
3143
3221
|
try {
|
|
3144
3222
|
const path = join(directory, "setup.json");
|
|
3145
3223
|
const value = readMailJson(path);
|
|
@@ -3167,13 +3245,13 @@ async function setupAgent(params) {
|
|
|
3167
3245
|
writeMailJson(path, state);
|
|
3168
3246
|
}
|
|
3169
3247
|
try {
|
|
3170
|
-
await connectAgent({
|
|
3248
|
+
claimedName = (await connectAgent({
|
|
3171
3249
|
configDir: params.configDir,
|
|
3172
3250
|
profileName,
|
|
3173
3251
|
invitation: params.invitation ?? "",
|
|
3174
3252
|
fetch: params.fetch,
|
|
3175
3253
|
presence: true
|
|
3176
|
-
});
|
|
3254
|
+
})).name;
|
|
3177
3255
|
} catch (error) {
|
|
3178
3256
|
if (error instanceof AgentInvitationRejectedError && created) {
|
|
3179
3257
|
discardStub = true;
|
|
@@ -3215,8 +3293,10 @@ async function setupAgent(params) {
|
|
|
3215
3293
|
"bounced",
|
|
3216
3294
|
"canceled"
|
|
3217
3295
|
].includes(state.receipt?.status ?? "") ? "reply_failed" : ["unknown", "wait_timeout"].includes(state.receipt?.status ?? "") ? "delivery_unknown" : "reply_submitted" : state?.phase === "sending" ? "send_unknown" : "challenge_pending";
|
|
3296
|
+
claimedName ??= savedConnectionName(params.configDir, profileName);
|
|
3218
3297
|
const result = (receiving, ownerNotifications) => ({
|
|
3219
3298
|
identity: context.identity,
|
|
3299
|
+
...claimedName === void 0 ? {} : { connectionName: claimedName },
|
|
3220
3300
|
sessionId: params.session ?? state?.session ?? null,
|
|
3221
3301
|
verification: {
|
|
3222
3302
|
state: confirmed && submittedState() === "reply_submitted" ? "verified" : submittedState(),
|
|
@@ -3675,6 +3755,10 @@ async function runAgentConnect(options) {
|
|
|
3675
3755
|
ownerAddress: result.identity.ownerAddress,
|
|
3676
3756
|
ownerMemberAddress,
|
|
3677
3757
|
profile: result.identity.profileName,
|
|
3758
|
+
...result.connectionName === void 0 ? {} : {
|
|
3759
|
+
name: result.connectionName,
|
|
3760
|
+
nameIsDefault: defaultConnectionName(result.connectionName, result.identity.agentAddress)
|
|
3761
|
+
},
|
|
3678
3762
|
sessionId: session ?? null,
|
|
3679
3763
|
runtime,
|
|
3680
3764
|
cli: {
|
|
@@ -3696,45 +3780,6 @@ async function runAgentConnect(options) {
|
|
|
3696
3780
|
};
|
|
3697
3781
|
}
|
|
3698
3782
|
//#endregion
|
|
3699
|
-
//#region src/oclif/agent-identity-suggestions.ts
|
|
3700
|
-
/** The connection name enrollment uses when none is given. */
|
|
3701
|
-
const DEFAULT_ENROLL_NAME = "Coding agent";
|
|
3702
|
-
/** npx runs the CLI from its cache; print follow-up commands the same way. */
|
|
3703
|
-
function cliInvocation(entry) {
|
|
3704
|
-
return entry && /[\\/]_npx[\\/]/.test(entry) ? "npx -y primitive@latest" : "primitive";
|
|
3705
|
-
}
|
|
3706
|
-
/**
|
|
3707
|
-
* Whether an enrollment's connection name is the fallback it chose by itself.
|
|
3708
|
-
* Session registration's `<runtime>-<repository>` names are reported by
|
|
3709
|
-
* registration, which knows the exact name it generated.
|
|
3710
|
-
*/
|
|
3711
|
-
function generatedAgentName(name) {
|
|
3712
|
-
return name === DEFAULT_ENROLL_NAME;
|
|
3713
|
-
}
|
|
3714
|
-
/**
|
|
3715
|
-
* Additive result fields for a connect, enroll or session registration.
|
|
3716
|
-
* `nameIsDefault` appears only when it is known whether the connection name
|
|
3717
|
-
* is one this CLI generated. The runtime note is suggested once, after a
|
|
3718
|
-
* connection this run completed.
|
|
3719
|
-
*/
|
|
3720
|
-
function identitySuggestions(params) {
|
|
3721
|
-
const prefix = `PRIMITIVE_AGENT_PROFILE=${params.profile} ${params.invocation}`;
|
|
3722
|
-
const suggestions = [];
|
|
3723
|
-
const nameIsDefault = params.nameIsDefault;
|
|
3724
|
-
if (nameIsDefault) suggestions.push({
|
|
3725
|
-
kind: "rename",
|
|
3726
|
-
command: `${prefix} agent rename "<new name>"`
|
|
3727
|
-
});
|
|
3728
|
-
if (params.connectedNow) suggestions.push({
|
|
3729
|
-
kind: "runtime_note",
|
|
3730
|
-
command: `${prefix} agent runtime set`
|
|
3731
|
-
});
|
|
3732
|
-
return nameIsDefault === void 0 ? { suggestions } : {
|
|
3733
|
-
nameIsDefault,
|
|
3734
|
-
suggestions
|
|
3735
|
-
};
|
|
3736
|
-
}
|
|
3737
|
-
//#endregion
|
|
3738
3783
|
//#region src/oclif/agent-disconnect.ts
|
|
3739
3784
|
var AgentDisconnectError = class extends Error {};
|
|
3740
3785
|
function credentialDigest(profile) {
|
|
@@ -5211,4 +5256,4 @@ async function runDetached(params) {
|
|
|
5211
5256
|
}
|
|
5212
5257
|
}
|
|
5213
5258
|
//#endregion
|
|
5214
|
-
export {
|
|
5259
|
+
export { describeSessionHookItem as $, evaluateContactPolicy as A, agentInvitationHash as B, RECEIVER_MODES as C, NETWORK_ADMISSION_PENDING_RETRY_MS as D, ContactPolicyReadRetryError as E, ContactsApiError as F, saveConnectionName as G, readAgentInvitation as H, contactAddress as I, recordHookMailCheck as J, savedReceiver as K, contactAgentAddress as L, AddressNotesApiError as M, addressNoteTarget as N, NetworkAdmissionPendingError as O, runAddressNotesRequest as P, describeSessionHookChange as Q, runContactRequest as R, runAgentConnect as S, verificationReplySubmitted as T, receiverStatusCommand as U, connectAgent as V, refusalAfterReplacement as W, claudeConfigDir as X, boundSessionProfiles as Y, currentCliLocation as Z, disconnectAgent as _, withOwnerMemberAddress as _t, endSession as a, readClaudeSettings as at, invitationProfileName as b, pendingSessionDisconnects as c, writeClaudeSettings as ct, registerSession as d, jsonIndentation as dt, ensureHookLauncher as et, retryPendingDisconnects as f, readManagedFile as ft, AgentDisconnectError as g, refreshOwnerMemberAddressPeriodically as gt, enrollmentResumes as h, readHookLauncherWarning as ht, connectedProfilesForSession as i, inspectClaudeHooks as it, canonicalContactSelector as j, createNotificationContactPolicy as k, psProcessInfo as l, MachineFileError as lt, enrollAgent as m, writeManagedFile as mt, OMP_MAIN as n, findOnPath as nt, headlessClaudeRun as o, repairClaudeHooks as ot, runDetached as p, upsertManagedBlock as pt, installClaudeWakeHook as q, agentConnectionState as r, hasMachineSessionHooks as rt, machine_session_exports as s, samePath as st, MACHINE_RUNTIMES as t, ephemeralCliReason as tt, readClaudeHookInput as u, inspectManagedBlock as ut, connectWarnings as v, externalReceivingState as w, pollCheckCommand as x, defaultAgentProfileName as y, agentConnectionStatus as z };
|