@primitivedotdev/cli 0.32.1 → 0.34.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.
@@ -1,12 +1,106 @@
1
- import { existsSync } from "node:fs";
1
+ import { b as normalizeApiBaseUrl1, c as resolveConfigEnvironment, i as loadCliConfig } from "../cli-config-D9nB6fOW.js";
2
+ import { existsSync, readFileSync } from "node:fs";
2
3
  import { join } from "node:path";
3
4
  import { homedir } from "node:os";
4
5
  //#region src/oclif/root-signup-hint.ts
5
6
  const CREDENTIALS_FILE = "credentials.json";
7
+ const ROOT_AUTH_TIMEOUT_MS = 1e3;
6
8
  function activeConfigDir(env, home) {
7
9
  if (env.PRIMITIVE_CONFIG_DIR) return env.PRIMITIVE_CONFIG_DIR;
8
10
  return join(env.XDG_CONFIG_HOME || join(home, ".config"), "primitive");
9
11
  }
12
+ function readRootCredentials(configDir) {
13
+ let raw;
14
+ try {
15
+ raw = readFileSync(join(configDir, CREDENTIALS_FILE), "utf8");
16
+ } catch {
17
+ return null;
18
+ }
19
+ try {
20
+ const parsed = JSON.parse(raw);
21
+ if (parsed.auth_method !== "oauth") return null;
22
+ if (typeof parsed.access_token !== "string" || !parsed.access_token.trim()) return null;
23
+ if (typeof parsed.api_base_url_1 !== "string" || !parsed.api_base_url_1.trim()) return null;
24
+ return {
25
+ accessToken: parsed.access_token,
26
+ apiBaseUrl1: parsed.api_base_url_1.replace(/\/+$/, "")
27
+ };
28
+ } catch {
29
+ return null;
30
+ }
31
+ }
32
+ function accountEndpoint(apiBaseUrl1) {
33
+ return `${apiBaseUrl1.replace(/\/+$/, "")}/account`;
34
+ }
35
+ function parseRootAccount(payload) {
36
+ if (payload === null || typeof payload !== "object" || Array.isArray(payload)) return null;
37
+ const data = payload.data;
38
+ if (data === null || typeof data !== "object" || Array.isArray(data)) return null;
39
+ const account = data;
40
+ if (typeof account.email !== "string" || !account.email.trim()) return null;
41
+ if (typeof account.id !== "string" || !account.id.trim()) return null;
42
+ return {
43
+ email: account.email,
44
+ id: account.id
45
+ };
46
+ }
47
+ function rootAuthLine(account) {
48
+ return `Signed in as ${account.email} (org ${account.id})\n\n`;
49
+ }
50
+ function rootRequestConfig(configDir, env) {
51
+ const currentEnvironment = resolveConfigEnvironment(loadCliConfig(configDir));
52
+ const configuredApiBaseUrl1 = currentEnvironment?.config.api_base_url_1;
53
+ const envApiBaseUrl1 = env.PRIMITIVE_API_BASE_URL_1?.trim();
54
+ if (currentEnvironment !== null && currentEnvironment.name !== "default" && !envApiBaseUrl1 && !configuredApiBaseUrl1) return null;
55
+ return {
56
+ apiBaseUrl1: normalizeApiBaseUrl1(envApiBaseUrl1 || configuredApiBaseUrl1),
57
+ headers: currentEnvironment?.config.headers
58
+ };
59
+ }
60
+ async function fetchRootAccount(params) {
61
+ const controller = new AbortController();
62
+ const timer = setTimeout(() => controller.abort(), params.timeoutMs);
63
+ try {
64
+ const response = await params.fetch(accountEndpoint(params.apiBaseUrl1), {
65
+ headers: {
66
+ ...params.headers ?? {},
67
+ accept: "application/json",
68
+ authorization: `Bearer ${params.apiKey}`
69
+ },
70
+ signal: controller.signal
71
+ });
72
+ if (!response.ok) return null;
73
+ return parseRootAccount(await response.json().catch(() => null));
74
+ } catch {
75
+ return null;
76
+ } finally {
77
+ clearTimeout(timer);
78
+ }
79
+ }
80
+ async function rootSignedInSummary(options = {}) {
81
+ if ((options.argv ?? process.argv.slice(2)).length > 0) return null;
82
+ const env = options.env ?? process.env;
83
+ const configDir = activeConfigDir(env, options.home ?? homedir());
84
+ let requestConfig;
85
+ try {
86
+ requestConfig = rootRequestConfig(configDir, env);
87
+ } catch {
88
+ return null;
89
+ }
90
+ if (!requestConfig) return null;
91
+ const explicitApiKey = env.PRIMITIVE_API_KEY?.trim();
92
+ const stored = explicitApiKey ? null : readRootCredentials(configDir);
93
+ const apiKey = explicitApiKey || stored?.accessToken;
94
+ if (!apiKey) return null;
95
+ const account = await fetchRootAccount({
96
+ apiBaseUrl1: stored?.apiBaseUrl1 ?? requestConfig.apiBaseUrl1,
97
+ apiKey,
98
+ fetch: options.fetch ?? fetch,
99
+ headers: requestConfig.headers,
100
+ timeoutMs: options.timeoutMs ?? ROOT_AUTH_TIMEOUT_MS
101
+ });
102
+ return account ? rootAuthLine(account) : null;
103
+ }
10
104
  function shouldShowLoggedOutSignupHint(options = {}) {
11
105
  if ((options.argv ?? process.argv.slice(2)).length > 0) return false;
12
106
  const env = options.env ?? process.env;
@@ -27,5 +121,14 @@ function writeLoggedOutSignupHintIfNeeded(options = {}) {
27
121
  if (!shouldShowLoggedOutSignupHint(options)) return;
28
122
  (options.write ?? ((message) => process.stdout.write(message)))(loggedOutSignupHint());
29
123
  }
124
+ async function writeRootAuthContextIfNeeded(options = {}) {
125
+ const write = options.write ?? ((message) => process.stdout.write(message));
126
+ const signedIn = await rootSignedInSummary(options);
127
+ if (signedIn) {
128
+ write(signedIn);
129
+ return;
130
+ }
131
+ writeLoggedOutSignupHintIfNeeded(options);
132
+ }
30
133
  //#endregion
31
- export { loggedOutSignupHint, shouldShowLoggedOutSignupHint, writeLoggedOutSignupHintIfNeeded };
134
+ export { loggedOutSignupHint, rootSignedInSummary, shouldShowLoggedOutSignupHint, writeLoggedOutSignupHintIfNeeded, writeRootAuthContextIfNeeded };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@primitivedotdev/cli",
3
- "version": "0.32.1",
3
+ "version": "0.34.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,
@@ -35,6 +35,9 @@
35
35
  "message": "Primitive CLI update available from <%= chalk.greenBright(config.version) %> to <%= chalk.greenBright(latest) %>. Run `npm install -g @primitivedotdev/cli@latest` to update."
36
36
  },
37
37
  "topics": {
38
+ "chat": {
39
+ "description": "Chat with agents over email. Use `primitive chat <email> <message>` to start, `primitive chat reply <message>` to continue the active chat, or `primitive chat reply <id> <message>` to reply in a specific local chat."
40
+ },
38
41
  "cli": {
39
42
  "description": "CLI authentication"
40
43
  },