primcli 1.42.0 → 1.44.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 +49 -2
- package/bin/claude-pending-mail.mjs +31 -6
- package/bin/claude-wake.mjs +7 -2
- package/dist/{interaction-actions-D5o_frTT.js → api-command-CpW39SQw.js} +1674 -1223
- package/dist/{auto-signals-D3NqwgYA.js → auto-signals-oSCnNgts.js} +1 -1
- package/dist/{cli-config-BoZ1lMUQ.js → cli-config-DGrZCUfw.js} +16 -1
- package/dist/{connect-skill-BHxdjtkK.js → connect-skill-BJFxnbwI.js} +2 -2
- package/dist/oclif/auto-signal-worker.js +3 -3
- package/dist/oclif/auto-signals.js +1 -1
- package/dist/oclif/index.js +1078 -757
- package/dist/oclif/receiver-heal.js +2 -2
- package/dist/oclif/root-signup-hint.js +1 -1
- package/dist/{repeats-CoK0tpCK-Bx7nmyRi.js → repeats-D2xtLium-Dv34tqei.js} +21 -2
- package/dist/{signal-command-D5YGxi_o.js → signal-command-BbdorL9t.js} +15 -182
- package/dist/skills/primitive-connect/SKILL.md +21 -0
- package/dist/skills/primitive-connect.json +3 -3
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { N as agentProfileDirectory, P as agentProfileName, R as loadConnectedAgentProfile, j as AGENT_PROFILE_ENV } from "../cli-config-
|
|
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-
|
|
3
|
+
import { m as SESSION_UUID, n as detectAgentRuntime, o as notificationScope } from "../connect-skill-BJFxnbwI.js";
|
|
4
4
|
import { a as claimBackgroundListenRestart, n as backgroundListenRestartable, r as backgroundListenStatus } from "../listen-background-TTBqrO_R.js";
|
|
5
5
|
import { join } from "node:path";
|
|
6
6
|
import { spawn } from "node:child_process";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { S as normalizeApiBaseUrl, c as resolveConfigEnvironment, i as loadCliConfig } from "../cli-config-
|
|
1
|
+
import { S as normalizeApiBaseUrl, c as resolveConfigEnvironment, i as loadCliConfig } from "../cli-config-DGrZCUfw.js";
|
|
2
2
|
import { existsSync, readFileSync } from "node:fs";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { homedir } from "node:os";
|
|
@@ -9676,7 +9676,7 @@ function normalizeOptions(options) {
|
|
|
9676
9676
|
};
|
|
9677
9677
|
}
|
|
9678
9678
|
//#endregion
|
|
9679
|
-
//#region ../sdk-node/dist/repeats-
|
|
9679
|
+
//#region ../sdk-node/dist/repeats-D2xtLium.js
|
|
9680
9680
|
const UUID$3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
9681
9681
|
const ATOM = "[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+";
|
|
9682
9682
|
const MAILBOX$1 = new RegExp(`^${ATOM}(?:\\.${ATOM})*@(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?)(?:\\.[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*$`);
|
|
@@ -9869,9 +9869,28 @@ function utcExpiry(value) {
|
|
|
9869
9869
|
];
|
|
9870
9870
|
return year >= 1970 && month >= 1 && month <= 12 && day >= 1 && day <= (days[month - 1] ?? 0) && Number(match[4]) < 24 && Number(match[5]) < 60 && Number(match[6]) < 60;
|
|
9871
9871
|
}
|
|
9872
|
+
/** The fixed body of a repeat-stop notice; the stated reason is its only variable text. */
|
|
9873
|
+
function repeatStopNoticeText(reason) {
|
|
9874
|
+
return reason ? `Stopped this repeating message. Reason: ${reason}` : "Stopped this repeating message.";
|
|
9875
|
+
}
|
|
9876
|
+
/**
|
|
9877
|
+
* The notice body for a `repeat.stop/1` envelope sent back to a repeat's sender:
|
|
9878
|
+
* step `stop`, a previous step, no expiry, and a payload of `{}` or `{reason}`.
|
|
9879
|
+
* Unlike a status signal, the notice text is required.
|
|
9880
|
+
*/
|
|
9881
|
+
function repeatStopFallback(e) {
|
|
9882
|
+
if (!exactKeys(e, ENVELOPE_KEYS$1) || e.protocol_version !== 1 || e.step !== "stop" || typeof e.prev_step_id !== "string" || e.expires_at !== null || !e.payload || typeof e.payload !== "object" || Array.isArray(e.payload)) return null;
|
|
9883
|
+
const p = e.payload;
|
|
9884
|
+
if (!exactKeys(p, [], ["reason"])) return null;
|
|
9885
|
+
if (!Object.hasOwn(p, "reason")) return repeatStopNoticeText(null);
|
|
9886
|
+
const reason = p.reason;
|
|
9887
|
+
if (typeof reason !== "string" || reason.length === 0 || reason.length > 280 || reason.includes("\0")) return null;
|
|
9888
|
+
return repeatStopNoticeText(reason);
|
|
9889
|
+
}
|
|
9872
9890
|
function fallback(result) {
|
|
9873
9891
|
if (result.status !== "valid") return null;
|
|
9874
9892
|
const e = result.envelope;
|
|
9893
|
+
if (e.protocol === "repeat.stop") return repeatStopFallback(e);
|
|
9875
9894
|
if (!exactKeys(e, ENVELOPE_KEYS$1) || e.protocol_version !== 1 || ![
|
|
9876
9895
|
"ack",
|
|
9877
9896
|
"read",
|
|
@@ -9948,7 +9967,7 @@ function classifySignalContent(input) {
|
|
|
9948
9967
|
};
|
|
9949
9968
|
const actual = (input.bodies.text ?? "").replace(/\r\n/g, "\n");
|
|
9950
9969
|
const expected = text.replace(/\r\n/g, "\n");
|
|
9951
|
-
const matches = actual === "" || actual === "\n" || actual === expected || actual === `${expected}\n`;
|
|
9970
|
+
const matches = !(interaction.status === "valid" && interaction.envelope.protocol === "repeat.stop") && (actual === "" || actual === "\n") || actual === expected || actual === `${expected}\n`;
|
|
9952
9971
|
return {
|
|
9953
9972
|
classification: matches ? "informational_only" : "mixed_or_unsupported",
|
|
9954
9973
|
reason: matches ? "informational_signal" : "text_mismatch",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { h as sendPreparedSignal, p as prepareSignalEmail } from "./repeats-
|
|
2
|
-
import {
|
|
1
|
+
import { h as sendPreparedSignal, p as prepareSignalEmail } from "./repeats-D2xtLium-Dv34tqei.js";
|
|
2
|
+
import { En as listSentEmails, T as bareAddress, Wn as sendEmail, mt as successfulSendOutcome, o as extractErrorPayload, rn as getEmail, tt as classifySendError, zt as createEndpoint } from "./api-command-CpW39SQw.js";
|
|
3
3
|
import { _ as acquireListenLock, a as mailLockBusy, 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";
|
|
4
|
-
import { F as readBeforeDeadline, I as scopedChatSenderTrust, N as isPlainChatReply, S as recordSentSignal } from "./auto-signals-
|
|
4
|
+
import { F as readBeforeDeadline, I as scopedChatSenderTrust, N as isPlainChatReply, S as recordSentSignal } from "./auto-signals-oSCnNgts.js";
|
|
5
5
|
import { Errors } from "@oclif/core";
|
|
6
6
|
import { opendirSync, watch } from "node:fs";
|
|
7
7
|
import { createHash, randomUUID, scryptSync } from "node:crypto";
|
|
@@ -332,7 +332,7 @@ async function pullFile(root, outPath, opts) {
|
|
|
332
332
|
return manifest;
|
|
333
333
|
}
|
|
334
334
|
//#endregion
|
|
335
|
-
//#region ../sdk-node/dist/api-
|
|
335
|
+
//#region ../sdk-node/dist/api-CQJEoY6H.js
|
|
336
336
|
const jsonBodySerializer = { bodySerializer: (body) => JSON.stringify(body, (_key, value) => typeof value === "bigint" ? value.toString() : value) };
|
|
337
337
|
function createSseClient({ onRequest, onSseError, onSseEvent, responseTransformer, responseValidator, sseDefaultRetryDelay, sseMaxRetryAttempts, sseMaxRetryDelay, sseSleepFn, url, ...options }) {
|
|
338
338
|
let lastEventId;
|
|
@@ -962,13 +962,13 @@ var EventReceiverError = class extends Error {
|
|
|
962
962
|
this.name = "EventReceiverError";
|
|
963
963
|
}
|
|
964
964
|
};
|
|
965
|
-
function record$
|
|
965
|
+
function record$1(value) {
|
|
966
966
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
967
967
|
}
|
|
968
968
|
function validateOffer(value) {
|
|
969
|
-
if (!record$
|
|
969
|
+
if (!record$1(value) || !Number.isSafeInteger(value.backlog) || Number(value.backlog) < 0 || !Number.isSafeInteger(value.gap_count) || Number(value.gap_count) < 0 || value.last_gap_reason !== null && typeof value.last_gap_reason !== "string" || value.retention_seconds !== 86400 || value.handler_timeout_seconds !== 30) throw new EventReceiverError("Invalid event status response", "invalid_response");
|
|
970
970
|
const d = value.delivery;
|
|
971
|
-
if (d !== null && (!record$
|
|
971
|
+
if (d !== null && (!record$1(d) || ![
|
|
972
972
|
"queue_id",
|
|
973
973
|
"event_id",
|
|
974
974
|
"delivery_id",
|
|
@@ -976,7 +976,7 @@ function validateOffer(value) {
|
|
|
976
976
|
"event_type",
|
|
977
977
|
"body",
|
|
978
978
|
"lease_expires_at"
|
|
979
|
-
].every((key) => typeof d[key] === "string") || !Number.isFinite(Date.parse(String(d.lease_expires_at))) || !record$
|
|
979
|
+
].every((key) => typeof d[key] === "string") || !Number.isFinite(Date.parse(String(d.lease_expires_at))) || !record$1(d.headers) || !Object.values(d.headers).every((header) => typeof header === "string"))) throw new EventReceiverError("Invalid event delivery response", "invalid_response");
|
|
980
980
|
return value;
|
|
981
981
|
}
|
|
982
982
|
function retryAfter(value) {
|
|
@@ -986,7 +986,7 @@ function retryAfter(value) {
|
|
|
986
986
|
}
|
|
987
987
|
function unwrap(result) {
|
|
988
988
|
if (result.data !== void 0 && !result.error) return result.data;
|
|
989
|
-
const code = record$
|
|
989
|
+
const code = record$1(result.error) && record$1(result.error.error) && typeof result.error.error.code === "string" ? result.error.error.code : "request_failed";
|
|
990
990
|
throw new EventReceiverError(`Event request failed (${result.response?.status ?? 0}, ${code})`, code, result.response?.status ?? 0, retryAfter(result.response?.headers.get("retry-after") ?? null));
|
|
991
991
|
}
|
|
992
992
|
/** Shared by the SDK and CLI. Completion retries preserve the original evidence. */
|
|
@@ -1038,7 +1038,7 @@ var EventConnection = class {
|
|
|
1038
1038
|
return;
|
|
1039
1039
|
}
|
|
1040
1040
|
this.touch?.();
|
|
1041
|
-
if (!record$
|
|
1041
|
+
if (!record$1(frame)) {
|
|
1042
1042
|
this.fail(new EventReceiverError("Invalid event frame", "invalid_response"));
|
|
1043
1043
|
return;
|
|
1044
1044
|
}
|
|
@@ -1077,7 +1077,7 @@ var EventConnection = class {
|
|
|
1077
1077
|
token
|
|
1078
1078
|
})), { once: true });
|
|
1079
1079
|
}, 15e3);
|
|
1080
|
-
if (!record$
|
|
1080
|
+
if (!record$1(ready) || ready.type !== "ready" || ready.protocol !== "primitive.events.v1") {
|
|
1081
1081
|
this.close();
|
|
1082
1082
|
throw new EventReceiverError("Unsupported event stream protocol", "unsupported");
|
|
1083
1083
|
}
|
|
@@ -1132,7 +1132,7 @@ var EventConnection = class {
|
|
|
1132
1132
|
})).data);
|
|
1133
1133
|
await this.open(signal);
|
|
1134
1134
|
const frame = await this.exchange(signal, { type: "receive" }, void 0, 9e4);
|
|
1135
|
-
if (!record$
|
|
1135
|
+
if (!record$1(frame) || frame.type !== "event") throw new EventReceiverError("Invalid event frame", "invalid_response");
|
|
1136
1136
|
return validateOffer(frame.data);
|
|
1137
1137
|
}
|
|
1138
1138
|
async complete(body, signal) {
|
|
@@ -1151,10 +1151,10 @@ var EventConnection = class {
|
|
|
1151
1151
|
type: "complete",
|
|
1152
1152
|
body
|
|
1153
1153
|
}, void 0, 15e3);
|
|
1154
|
-
if (!record$
|
|
1154
|
+
if (!record$1(frame) || frame.type !== "receipt") throw new EventReceiverError("Invalid event receipt", "invalid_response");
|
|
1155
1155
|
receipt = frame.data;
|
|
1156
1156
|
}
|
|
1157
|
-
if (!record$
|
|
1157
|
+
if (!record$1(receipt) || !["completed", "already_completed"].includes(String(receipt.result))) throw new EventReceiverError("Invalid event receipt", "invalid_response");
|
|
1158
1158
|
}
|
|
1159
1159
|
};
|
|
1160
1160
|
//#endregion
|
|
@@ -1298,173 +1298,6 @@ function waitForSharedMailChange(store, options) {
|
|
|
1298
1298
|
});
|
|
1299
1299
|
}
|
|
1300
1300
|
//#endregion
|
|
1301
|
-
//#region src/oclif/wake-context.ts
|
|
1302
|
-
const security = [{
|
|
1303
|
-
scheme: "bearer",
|
|
1304
|
-
type: "http"
|
|
1305
|
-
}];
|
|
1306
|
-
const UUID = /^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$/i;
|
|
1307
|
-
const WAKE_ADDRESS = /^[a-z0-9._%+-]{1,64}@[a-z0-9.-]{1,253}$/;
|
|
1308
|
-
const afterUnsupported = /* @__PURE__ */ new WeakSet();
|
|
1309
|
-
/** The bare lowercase address in `Name <addr>` or `addr` form. */
|
|
1310
|
-
function bareAddress(value) {
|
|
1311
|
-
if (typeof value !== "string") return null;
|
|
1312
|
-
const address = (/<([^<>\s]+@[^<>\s]+)>\s*$/.exec(value)?.[1] ?? value).trim().toLowerCase();
|
|
1313
|
-
return /^[^\s<>@]+@[^\s<>@]+$/.test(address) ? address : null;
|
|
1314
|
-
}
|
|
1315
|
-
function record$1(value) {
|
|
1316
|
-
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
1317
|
-
}
|
|
1318
|
-
function newerRows(value) {
|
|
1319
|
-
if (!Array.isArray(value)) return void 0;
|
|
1320
|
-
const rows = [];
|
|
1321
|
-
for (const item of value.slice(-20)) {
|
|
1322
|
-
const row = record$1(item);
|
|
1323
|
-
const from = bareAddress(row?.from);
|
|
1324
|
-
if (!row || typeof row.id !== "string" || !UUID.test(row.id) || !from || typeof row.received_at !== "string" || !Number.isFinite(Date.parse(row.received_at))) return void 0;
|
|
1325
|
-
rows.push({
|
|
1326
|
-
id: row.id.toLowerCase(),
|
|
1327
|
-
from,
|
|
1328
|
-
received_at: row.received_at
|
|
1329
|
-
});
|
|
1330
|
-
}
|
|
1331
|
-
return rows;
|
|
1332
|
-
}
|
|
1333
|
-
/**
|
|
1334
|
-
* Read one thread, asking for mail newer than `afterEmailId`. The newer-mail
|
|
1335
|
-
* fields are feature-detected: an API that does not return them yields a
|
|
1336
|
-
* context without `newerInboundCount`. Returns null when the thread cannot be
|
|
1337
|
-
* read; callers treat that as "unknown", never as an error.
|
|
1338
|
-
*/
|
|
1339
|
-
async function readThreadContext(client, threadId, afterEmailId, signal) {
|
|
1340
|
-
if (!UUID.test(threadId)) return null;
|
|
1341
|
-
const bounded = AbortSignal.any([signal, AbortSignal.timeout(5e3)]);
|
|
1342
|
-
const read = (after) => client.get({
|
|
1343
|
-
security,
|
|
1344
|
-
url: "/threads/{id}",
|
|
1345
|
-
path: { id: threadId },
|
|
1346
|
-
...after ? { query: { after } } : {},
|
|
1347
|
-
signal: bounded,
|
|
1348
|
-
responseStyle: "fields"
|
|
1349
|
-
});
|
|
1350
|
-
try {
|
|
1351
|
-
const askAfter = afterEmailId !== void 0 && UUID.test(afterEmailId) && !afterUnsupported.has(client);
|
|
1352
|
-
let result = await read(askAfter ? afterEmailId : void 0);
|
|
1353
|
-
if (askAfter && result.response?.status === 400) {
|
|
1354
|
-
afterUnsupported.add(client);
|
|
1355
|
-
result = await read();
|
|
1356
|
-
}
|
|
1357
|
-
if (result.error !== void 0) return null;
|
|
1358
|
-
const body = record$1(result.data);
|
|
1359
|
-
const data = record$1(body?.data);
|
|
1360
|
-
if (body?.success !== true || !data || !Array.isArray(data.messages)) return null;
|
|
1361
|
-
const messages = data.messages.filter((message) => Boolean(record$1(message)) && typeof message.id === "string" && ["inbound", "outbound"].includes(message.direction));
|
|
1362
|
-
const count = data.newer_inbound_count;
|
|
1363
|
-
const newerInboundCount = typeof count === "number" && Number.isSafeInteger(count) && count >= 0 ? count : void 0;
|
|
1364
|
-
const newerInbound = newerInboundCount === void 0 ? void 0 : newerRows(data.newer_inbound);
|
|
1365
|
-
return {
|
|
1366
|
-
threadId: threadId.toLowerCase(),
|
|
1367
|
-
messages,
|
|
1368
|
-
truncated: typeof data.message_count === "number" && data.message_count > messages.length,
|
|
1369
|
-
...newerInboundCount === void 0 ? {} : { newerInboundCount },
|
|
1370
|
-
...newerInbound === void 0 ? {} : { newerInbound }
|
|
1371
|
-
};
|
|
1372
|
-
} catch {
|
|
1373
|
-
signal.throwIfAborted();
|
|
1374
|
-
return null;
|
|
1375
|
-
}
|
|
1376
|
-
}
|
|
1377
|
-
/** Whether `self` has an outbound message in the thread; undefined if unknowable. */
|
|
1378
|
-
function sentInThread(context, self) {
|
|
1379
|
-
if (!context) return void 0;
|
|
1380
|
-
const address = self.toLowerCase();
|
|
1381
|
-
if (context.messages.some((message) => message.direction === "outbound" && bareAddress(message.from) === address)) return true;
|
|
1382
|
-
return context.truncated ? void 0 : false;
|
|
1383
|
-
}
|
|
1384
|
-
/** The latest outbound message from `self` in the thread, if listed. */
|
|
1385
|
-
function latestOwnOutbound(context, self) {
|
|
1386
|
-
const address = self.toLowerCase();
|
|
1387
|
-
return [...context?.messages ?? []].reverse().find((message) => message.direction === "outbound" && bareAddress(message.from) === address);
|
|
1388
|
-
}
|
|
1389
|
-
function hasAttachments(detail) {
|
|
1390
|
-
return (detail.parsed?.attachments?.length ?? 0) > 0;
|
|
1391
|
-
}
|
|
1392
|
-
/**
|
|
1393
|
-
* Map server-provided sender facts to one relationship label. The owner and
|
|
1394
|
-
* member labels come only from server admission; `agent` from the server's
|
|
1395
|
-
* connected-agent verification or network admission; `contact` from an
|
|
1396
|
-
* explicit contact allowance.
|
|
1397
|
-
*/
|
|
1398
|
-
function wakeRelationship(input) {
|
|
1399
|
-
if (input.senderRelation) return input.senderRelation;
|
|
1400
|
-
if (input.connectedAgentVerified || input.network) return "agent";
|
|
1401
|
-
if (input.contact) return "contact";
|
|
1402
|
-
return "other";
|
|
1403
|
-
}
|
|
1404
|
-
const SERVER_RELATIONSHIPS = {
|
|
1405
|
-
owner: "owner",
|
|
1406
|
-
org_agent: "agent",
|
|
1407
|
-
member: "member",
|
|
1408
|
-
contact: "contact",
|
|
1409
|
-
other: "other"
|
|
1410
|
-
};
|
|
1411
|
-
/** The `collaboration` object of an email read, when the server sends one. */
|
|
1412
|
-
function collaborationOf(detail) {
|
|
1413
|
-
return record$1(record$1(detail)?.collaboration);
|
|
1414
|
-
}
|
|
1415
|
-
/**
|
|
1416
|
-
* The sender relationship the server computed for this email
|
|
1417
|
-
* (`collaboration.sender_relationship`), mapped to the CLI's labels:
|
|
1418
|
-
* `org_agent` reads as `agent`. When present it is authoritative, `other`
|
|
1419
|
-
* included, so a stale local classification cannot override it. Returns
|
|
1420
|
-
* undefined only for an older server that sends no such field, or an
|
|
1421
|
-
* unrecognized value; the caller then keeps its own derivation.
|
|
1422
|
-
*/
|
|
1423
|
-
function serverRelationship(detail) {
|
|
1424
|
-
const value = collaborationOf(detail)?.sender_relationship;
|
|
1425
|
-
return typeof value === "string" && Object.hasOwn(SERVER_RELATIONSHIPS, value) ? SERVER_RELATIONSHIPS[value] : void 0;
|
|
1426
|
-
}
|
|
1427
|
-
/**
|
|
1428
|
-
* True when the server reports this email's thread as muted for the
|
|
1429
|
-
* receiving address (`collaboration.muted`, or `muted` on the email). An
|
|
1430
|
-
* older server sends neither and nothing is muted by it.
|
|
1431
|
-
*/
|
|
1432
|
-
function serverMuted(detail) {
|
|
1433
|
-
return collaborationOf(detail)?.muted === true || record$1(detail)?.muted === true;
|
|
1434
|
-
}
|
|
1435
|
-
/**
|
|
1436
|
-
* An address fit to print as trusted metadata, or `unavailable`. The
|
|
1437
|
-
* sender's address is parsed from a header the sender wrote, so anything
|
|
1438
|
-
* outside a plain charset (quotes, spaces, line breaks) is withheld.
|
|
1439
|
-
*/
|
|
1440
|
-
function displayAddress(value) {
|
|
1441
|
-
return WAKE_ADDRESS.test(value) ? value : "unavailable";
|
|
1442
|
-
}
|
|
1443
|
-
/** The metadata clause of a wake line. Addresses outside a plain charset are withheld. */
|
|
1444
|
-
function formatWakeContext(context) {
|
|
1445
|
-
const sender = displayAddress(context.sender);
|
|
1446
|
-
const thread = context.threadId && UUID.test(context.threadId) ? context.threadId.toLowerCase() : "none";
|
|
1447
|
-
const newer = context.newer !== void 0 && Number.isSafeInteger(context.newer) && context.newer >= 0 ? ` newer=${Math.min(context.newer, 9999)}` : "";
|
|
1448
|
-
const interaction = isWakeInteractionLabel(context.interaction) ? ` interaction=${context.interaction}` : "";
|
|
1449
|
-
return `from=${sender} relationship=${context.relationship} thread=${thread} in_thread=${context.inThread ? "yes" : "no"} attachments=${context.attachments ? "yes" : "no"}${newer}${interaction}`;
|
|
1450
|
-
}
|
|
1451
|
-
/** Build a wake context, reading the thread once. Never throws for API failures. */
|
|
1452
|
-
async function describeWake(input) {
|
|
1453
|
-
const { detail } = input;
|
|
1454
|
-
const threadId = typeof detail.thread_id === "string" && UUID.test(detail.thread_id) ? detail.thread_id.toLowerCase() : null;
|
|
1455
|
-
const thread = threadId ? await readThreadContext(input.client, threadId, detail.id, input.signal) : null;
|
|
1456
|
-
const interaction = wakeInteractionLabel(detail);
|
|
1457
|
-
return {
|
|
1458
|
-
sender: detail.from_email.trim().toLowerCase(),
|
|
1459
|
-
relationship: serverRelationship(detail) ?? input.relationship,
|
|
1460
|
-
threadId,
|
|
1461
|
-
inThread: input.localInThread || sentInThread(thread, input.self) === true,
|
|
1462
|
-
attachments: hasAttachments(detail),
|
|
1463
|
-
...thread?.newerInboundCount === void 0 ? {} : { newer: thread.newerInboundCount },
|
|
1464
|
-
...interaction ? { interaction } : {}
|
|
1465
|
-
};
|
|
1466
|
-
}
|
|
1467
|
-
//#endregion
|
|
1468
1301
|
//#region src/oclif/email-participants.ts
|
|
1469
1302
|
/**
|
|
1470
1303
|
* Everyone else an email was addressed to: its parsed To and Cc, as bare
|
|
@@ -2953,4 +2786,4 @@ async function sendSignal(context, options) {
|
|
|
2953
2786
|
}
|
|
2954
2787
|
}
|
|
2955
2788
|
//#endregion
|
|
2956
|
-
export {
|
|
2789
|
+
export { ensureSharedMailSubscription as a, reserveSharedMailSubscription as c, otherParticipants as d, readSharedMailOwner as f, pushFile as g, pullFile as h, sharedMailScope as i, followEmailConversation as l, EventReceiverError as m, reconcileChatSend as n, createSharedMailWaiter as o, EventConnection as p, openSharedMailReceiver as r, openSharedMailStore as s, sendSignal as t, readConversationFollow as u };
|
|
@@ -13,6 +13,25 @@ later work. An imperative setup instruction pasted as the owner's request
|
|
|
13
13
|
authorizes this connection, private credential storage, the verification reply
|
|
14
14
|
and continued receiving; do not ask for that approval again.
|
|
15
15
|
|
|
16
|
+
**One address per session unless the owner says otherwise.** If this session
|
|
17
|
+
already has a Primitive address (you connected it earlier, or a profile is
|
|
18
|
+
already receiving mail here), ask the owner whether to keep that address or
|
|
19
|
+
disconnect that agent first, and do not create a second address without their
|
|
20
|
+
answer. The connect command checks this itself: when the session is already
|
|
21
|
+
connected it claims nothing and exits with status 3 and
|
|
22
|
+
`status: "already_connected"` and names an address already connected here
|
|
23
|
+
(there can be more than one). Tell the owner, relay the same choice, then rerun
|
|
24
|
+
the same command as they chose:
|
|
25
|
+
|
|
26
|
+
- `--replace-existing` disconnects every address connected to this session,
|
|
27
|
+
not just one, then connects. Say so before they choose.
|
|
28
|
+
- `--keep-existing` keeps them all. If the existing address uses this
|
|
29
|
+
session's default profile, also pass a new `--profile <name>` so the second
|
|
30
|
+
address gets its own profile; otherwise the rerun is refused again.
|
|
31
|
+
|
|
32
|
+
Never switch to a separate profile on your own to get around this check; only
|
|
33
|
+
use a new profile as part of the owner's choice to keep both.
|
|
34
|
+
|
|
16
35
|
The command validates the invitation's API origin, claims it once, answers the
|
|
17
36
|
verification email, starts receiving for this exact session (or sets up
|
|
18
37
|
checking for mail when nothing can wake this session), installs or refreshes
|
|
@@ -79,6 +98,8 @@ Read the one JSON result:
|
|
|
79
98
|
`selectProfile` (`PRIMITIVE_AGENT_PROFILE=<profile>`).
|
|
80
99
|
- `status: "pending"`: run `resumeCommand` exactly as printed. It never reads
|
|
81
100
|
or claims the invitation again. `skipped` names each step not done and why.
|
|
101
|
+
- `status: "already_connected"` (exit status 3): ask the owner, then rerun
|
|
102
|
+
with `--replace-existing` or `--keep-existing` as described above.
|
|
82
103
|
- Exit status 1: follow its message. Never feed the same invitation to the
|
|
83
104
|
command twice, and never claim it over HTTP after the command may have
|
|
84
105
|
claimed it. Switch to the [HTTP API path](#connect-with-the-http-api) only
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "primitive-connect",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "c744659c2610f3a2",
|
|
4
4
|
"source": {
|
|
5
5
|
"repository": "https://github.com/primitivedotdev/skills",
|
|
6
6
|
"path": "skills/primitive-connect",
|
|
7
|
-
"commit": "
|
|
7
|
+
"commit": "8f4040ad7b91816efa58c0c175ff860db1e24abe"
|
|
8
8
|
},
|
|
9
9
|
"files": {
|
|
10
|
-
"SKILL.md": "
|
|
10
|
+
"SKILL.md": "e246e732bfede41a5538f8736bf3c6c5cd0b7d3c1ba1b8bb6e2a2d5103e915fb",
|
|
11
11
|
"package-lock.json": "443289373a7495883a9a3b57bab3bc471cd5dcb4989a9e67f797b35917c1acc5",
|
|
12
12
|
"package.json": "8cc45b2c28ba415960c9b85f6c1449f15f9c10bac0b96922e7907b40d50e3dbf",
|
|
13
13
|
"references/communication.md": "c931aada9553a8592088c28de5b272d5e0a15234aa9c9318ea7d1d5f69b39a79",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "primcli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.44.0",
|
|
4
4
|
"description": "Official Primitive CLI: deploy Primitive Functions, send and inspect mail, manage endpoints, all from the terminal. Wraps the @primitivedotdev/sdk runtime client with one-shot commands.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|