primcli 1.75.0 → 3.0.0-preview.10
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 +131 -68
- package/bin/claude-pending-mail.mjs +1 -1
- package/bin/run.js +14 -0
- package/dist/api-command-D0KHkqhA.js +56084 -0
- package/dist/{cli-config-B80p0pLk.js → cli-config-Ms_0vNjq.js} +59 -16
- package/dist/{json-output-BzSBR-KX.js → json-output-ch756TXV.js} +14 -1
- package/dist/{listen-background-C0F9gNDD.js → listen-background-DyBYca28.js} +323 -36
- package/dist/{machine-session-Cq_nD5eF.js → machine-session-CI8tnGzz.js} +27 -14
- package/dist/{notify-session-CbY4FYUt.js → notify-session-DN8tSfAi.js} +335 -5
- package/dist/oclif/auto-signal-worker.js +3 -3
- package/dist/oclif/auto-signals.js +2 -2
- package/dist/oclif/command-not-found.js +62 -0
- package/dist/oclif/global-org-flag.js +76 -0
- package/dist/oclif/index.js +61145 -36959
- package/dist/oclif/listen-supervisor.js +1 -1
- package/dist/oclif/proxy-auto-detect.js +1 -1
- package/dist/oclif/receiver-heal.js +5 -4
- package/dist/oclif/root-signup-hint.js +17 -17
- package/dist/receiver.d.ts +95 -0
- package/dist/receiver.js +569 -0
- package/dist/{repeats-Dj_o6c-X-LyCkKYjp.js → repeats-Dj_o6c-X-CDaE-kdZ.js} +3981 -930
- package/dist/{scoped-chat-B0thCwME.js → scoped-chat-C4TDfZND.js} +1 -1
- package/dist/{signal-command-DCPsJBdz.js → signal-command-f5QeK45s.js} +9 -8
- package/man/primitive.1 +50 -0
- package/package.json +68 -11
- package/dist/api-command-rlS3eTlZ.js +0 -2938
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { l as runBackgroundListenSupervisor } from "../listen-background-DyBYca28.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { N as agentProfileDirectory, P as agentProfileName, R as loadConnectedAgentProfile, j as AGENT_PROFILE_ENV } from "../cli-config-Ms_0vNjq.js";
|
|
2
|
+
import { a as backgroundListenStatus, i as backgroundListenRestartable, s as claimBackgroundListenRestart, t as BACKGROUND_LISTEN_RELAUNCH_ENV } from "../listen-background-DyBYca28.js";
|
|
3
|
+
import { d as SESSION_UUID, t as notificationScope } from "../notify-session-DN8tSfAi.js";
|
|
4
|
+
import { Lt as detectAgentRuntime } from "../api-command-D0KHkqhA.js";
|
|
5
5
|
import { d as readMailJson } from "../shared-mail-files-BAQSGxxz.js";
|
|
6
6
|
import { join } from "node:path";
|
|
7
7
|
import { spawn } from "node:child_process";
|
|
@@ -66,6 +66,7 @@ function healSelectedReceiver(options = {}) {
|
|
|
66
66
|
PRIMITIVE_CONFIG_DIR: configDir,
|
|
67
67
|
[RECEIVER_HEAL_ENV]: "0"
|
|
68
68
|
};
|
|
69
|
+
delete childEnv[BACKGROUND_LISTEN_RELAUNCH_ENV];
|
|
69
70
|
(options.spawnListener ?? spawnDetached)(listenArgv, childEnv);
|
|
70
71
|
return {
|
|
71
72
|
action: "restarting",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { c as resolveConfigEnvironment, i as loadCliConfig, x as normalizeApiBaseUrl } from "../cli-config-Ms_0vNjq.js";
|
|
2
2
|
import { existsSync, readFileSync } from "node:fs";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { homedir } from "node:os";
|
|
@@ -19,7 +19,7 @@ function readRootCredentials(configDir) {
|
|
|
19
19
|
}
|
|
20
20
|
try {
|
|
21
21
|
const parsed = JSON.parse(raw);
|
|
22
|
-
if (parsed.auth_method !== "oauth") return null;
|
|
22
|
+
if (parsed.auth_method !== "oauth" && parsed.auth_method !== "user_grant") return null;
|
|
23
23
|
if (typeof parsed.access_token !== "string" || !parsed.access_token.trim()) return null;
|
|
24
24
|
const apiBaseUrl = parsed.api_base_url ?? parsed.api_base_url_1;
|
|
25
25
|
if (typeof apiBaseUrl !== "string" || !apiBaseUrl.trim()) return null;
|
|
@@ -31,23 +31,23 @@ function readRootCredentials(configDir) {
|
|
|
31
31
|
return null;
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
|
-
function
|
|
35
|
-
return `${apiBaseUrl.replace(/\/+$/, "")}/
|
|
34
|
+
function whoamiEndpoint(apiBaseUrl) {
|
|
35
|
+
return `${apiBaseUrl.replace(/\/+$/, "")}/whoami`;
|
|
36
36
|
}
|
|
37
|
-
function
|
|
37
|
+
function parseRootIdentity(payload) {
|
|
38
38
|
if (payload === null || typeof payload !== "object" || Array.isArray(payload)) return null;
|
|
39
39
|
const data = payload.data;
|
|
40
40
|
if (data === null || typeof data !== "object" || Array.isArray(data)) return null;
|
|
41
|
-
const
|
|
42
|
-
if (typeof
|
|
43
|
-
|
|
41
|
+
const identity = data;
|
|
42
|
+
if (typeof identity.org_id !== "string" || !identity.org_id.trim()) return null;
|
|
43
|
+
const member = identity.member_address;
|
|
44
44
|
return {
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
memberAddress: member && typeof member.address === "string" && member.address.trim() ? member.address : null,
|
|
46
|
+
orgId: identity.org_id
|
|
47
47
|
};
|
|
48
48
|
}
|
|
49
|
-
function rootAuthLine(
|
|
50
|
-
return `Signed in as ${
|
|
49
|
+
function rootAuthLine(identity) {
|
|
50
|
+
return identity.memberAddress ? `Signed in as ${identity.memberAddress} (org ${identity.orgId})\n\n` : `Signed in (org ${identity.orgId})\n\n`;
|
|
51
51
|
}
|
|
52
52
|
function rootRequestConfig(configDir, env) {
|
|
53
53
|
const config = loadCliConfig(configDir);
|
|
@@ -60,11 +60,11 @@ function rootRequestConfig(configDir, env) {
|
|
|
60
60
|
headers: currentEnvironment?.config.headers
|
|
61
61
|
};
|
|
62
62
|
}
|
|
63
|
-
async function
|
|
63
|
+
async function fetchRootIdentity(params) {
|
|
64
64
|
const controller = new AbortController();
|
|
65
65
|
const timer = setTimeout(() => controller.abort(), params.timeoutMs);
|
|
66
66
|
try {
|
|
67
|
-
const response = await params.fetch(
|
|
67
|
+
const response = await params.fetch(whoamiEndpoint(params.apiBaseUrl), {
|
|
68
68
|
headers: {
|
|
69
69
|
...params.headers ?? {},
|
|
70
70
|
accept: "application/json",
|
|
@@ -73,7 +73,7 @@ async function fetchRootAccount(params) {
|
|
|
73
73
|
signal: controller.signal
|
|
74
74
|
});
|
|
75
75
|
if (!response.ok) return null;
|
|
76
|
-
return
|
|
76
|
+
return parseRootIdentity(await response.json().catch(() => null));
|
|
77
77
|
} catch {
|
|
78
78
|
return null;
|
|
79
79
|
} finally {
|
|
@@ -95,14 +95,14 @@ async function rootSignedInSummary(options = {}) {
|
|
|
95
95
|
const stored = explicitApiKey ? null : readRootCredentials(configDir);
|
|
96
96
|
const apiKey = explicitApiKey || stored?.accessToken;
|
|
97
97
|
if (!apiKey) return null;
|
|
98
|
-
const
|
|
98
|
+
const identity = await fetchRootIdentity({
|
|
99
99
|
apiBaseUrl: stored?.apiBaseUrl ?? requestConfig.apiBaseUrl,
|
|
100
100
|
apiKey,
|
|
101
101
|
fetch: options.fetch ?? fetch,
|
|
102
102
|
headers: requestConfig.headers,
|
|
103
103
|
timeoutMs: options.timeoutMs ?? ROOT_AUTH_TIMEOUT_MS
|
|
104
104
|
});
|
|
105
|
-
return
|
|
105
|
+
return identity ? rootAuthLine(identity) : null;
|
|
106
106
|
}
|
|
107
107
|
function shouldShowLoggedOutSignupHint(options = {}) {
|
|
108
108
|
if ((options.argv ?? process.argv.slice(2)).length > 0) return false;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/** One page of `listAgentContacts` (`primitive agent contacts list`). */
|
|
2
|
+
export type ContactPage = {
|
|
3
|
+
readonly data: readonly unknown[];
|
|
4
|
+
/** The cursor for the next page, or null on the last page. */
|
|
5
|
+
readonly cursor: string | null;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* The `checkDefaultNetworkContactAdmission` result for one email
|
|
9
|
+
* (`primitive agent-networks check-default-network-contact-admission`).
|
|
10
|
+
*/
|
|
11
|
+
export type NetworkAdmission = {
|
|
12
|
+
readonly allowed: boolean;
|
|
13
|
+
readonly allowed_since: string | null;
|
|
14
|
+
readonly pending: boolean;
|
|
15
|
+
readonly member_policy_required: boolean;
|
|
16
|
+
readonly sender_relation?: "owner" | "member" | undefined;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Reads the policy from the API as the connected address. A reader that hits
|
|
20
|
+
* a temporary failure, such as a rate limit, a 5xx response or a dropped
|
|
21
|
+
* connection, throws `new WakePolicyError("policy_read_failed")`. Any other
|
|
22
|
+
* error from a reader makes the policy unavailable.
|
|
23
|
+
*/
|
|
24
|
+
export type WakePolicyOptions = {
|
|
25
|
+
/** The connected address that receives the mail. */
|
|
26
|
+
readonly recipient: string;
|
|
27
|
+
/**
|
|
28
|
+
* Admit first mail from unknown senders as `request` when the owner allows
|
|
29
|
+
* contact requests. Defaults to false.
|
|
30
|
+
*/
|
|
31
|
+
readonly contactRequests?: boolean | undefined;
|
|
32
|
+
/** The `data` of `getAgentContactPolicy` for the recipient. */
|
|
33
|
+
readonly readContactPolicy: (signal: AbortSignal) => Promise<unknown>;
|
|
34
|
+
/** One page of the recipient's contacts, 100 rows at most. */
|
|
35
|
+
readonly readContactPage: (cursor: string | undefined, signal: AbortSignal) => Promise<ContactPage>;
|
|
36
|
+
/** The network admission decision for one exact email. */
|
|
37
|
+
readonly readNetworkAdmission: (emailId: string, sender: string, signal: AbortSignal) => Promise<NetworkAdmission>;
|
|
38
|
+
};
|
|
39
|
+
/** The facts of one received email, from the email detail. */
|
|
40
|
+
export type InboundEmail = {
|
|
41
|
+
readonly emailId: string;
|
|
42
|
+
/** The authenticated sender address. Check it before admission. */
|
|
43
|
+
readonly sender: string;
|
|
44
|
+
readonly receivedAt: string;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* `allowed` may wake the session. `request` is a first-contact request from
|
|
48
|
+
* an unknown sender: show it as a request, never as a task.
|
|
49
|
+
*/
|
|
50
|
+
export type WakeAdmission = (InboundEmail & {
|
|
51
|
+
readonly kind: "allowed";
|
|
52
|
+
}) | (InboundEmail & {
|
|
53
|
+
readonly kind: "request";
|
|
54
|
+
});
|
|
55
|
+
/** `denied` must not wake the session. */
|
|
56
|
+
export type WakeDecision = WakeAdmission | {
|
|
57
|
+
readonly kind: "denied";
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Call synchronously immediately before you wake the session. It throws
|
|
61
|
+
* `WakePolicyError` with `permission_changed` when the permission it confirms
|
|
62
|
+
* was refreshed or is older than 30 seconds; recheck and try again.
|
|
63
|
+
*/
|
|
64
|
+
export type ConfirmWake = () => void;
|
|
65
|
+
export type WakePolicy = {
|
|
66
|
+
/** Decide whether one email may wake the session. */
|
|
67
|
+
admit(email: InboundEmail, signal: AbortSignal): Promise<WakeDecision>;
|
|
68
|
+
/**
|
|
69
|
+
* Read the policy again for an admission from this policy's `admit`, right
|
|
70
|
+
* before dispatch. Throws `permission_changed` if the admission no longer
|
|
71
|
+
* holds.
|
|
72
|
+
*/
|
|
73
|
+
recheck(admission: WakeAdmission, signal: AbortSignal): Promise<ConfirmWake>;
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* - `policy_read_failed`: a policy read failed temporarily. Retry later; the
|
|
77
|
+
* policy paces repeated reads itself.
|
|
78
|
+
* - `network_admission_pending`: the server has not settled network admission
|
|
79
|
+
* for this email. Retry in a few seconds.
|
|
80
|
+
* - `permission_changed`: permission changed or expired before dispatch.
|
|
81
|
+
* Admit the email again.
|
|
82
|
+
* - `policy_unavailable`: the policy is invalid or access is lost. Do not
|
|
83
|
+
* wake; retrying will not help until access is restored.
|
|
84
|
+
*/
|
|
85
|
+
export type WakePolicyErrorCode = "policy_read_failed" | "network_admission_pending" | "permission_changed" | "policy_unavailable";
|
|
86
|
+
export declare class WakePolicyError extends Error {
|
|
87
|
+
readonly code: WakePolicyErrorCode;
|
|
88
|
+
/** Whether the same email may be admitted later without operator action. */
|
|
89
|
+
readonly retryable: boolean;
|
|
90
|
+
constructor(code: WakePolicyErrorCode, options?: {
|
|
91
|
+
cause?: unknown;
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
/** Create the contact admission policy for one connected address. */
|
|
95
|
+
export declare function createWakePolicy(options: WakePolicyOptions): WakePolicy;
|