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.
@@ -391,6 +391,7 @@ var LegacyApiKeyCredentialFormatError = class extends Error {
391
391
  };
392
392
  function parseCredentials(raw) {
393
393
  if (!isRecord$1(raw)) throw new Error(`Stored Primitive CLI credentials are malformed: expected a JSON object. ${MALFORMED_CREDENTIALS_HINT}`);
394
+ if (raw.auth_method === "user_grant") return parseUserGrantCredentials(raw);
394
395
  if (raw.auth_method !== "oauth") {
395
396
  if (typeof raw.api_key === "string" || typeof raw.key_id === "string" || typeof raw.base_url === "string") throw new LegacyApiKeyCredentialFormatError();
396
397
  throw new Error(`Stored Primitive CLI credentials are malformed: auth_method must be oauth. ${MALFORMED_CREDENTIALS_HINT}`);
@@ -412,6 +413,63 @@ function parseCredentials(raw) {
412
413
  created_at: requireString(raw, "created_at")
413
414
  };
414
415
  }
416
+ function malformed(detail) {
417
+ return /* @__PURE__ */ new Error(`Stored Primitive CLI credentials are malformed: ${detail}. ${MALFORMED_CREDENTIALS_HINT}`);
418
+ }
419
+ function requireText(value, key, options = {}) {
420
+ const raw = value[key];
421
+ if (typeof raw !== "string" || !options.allowEmpty && raw.trim().length === 0) throw malformed(`${key} must be a non-empty string`);
422
+ return raw;
423
+ }
424
+ function nullableText(value, key) {
425
+ const raw = value[key];
426
+ if (raw === void 0 || raw === null) return null;
427
+ if (typeof raw !== "string") throw malformed(`${key} must be a string or null`);
428
+ return raw;
429
+ }
430
+ function parseOrgToken(raw) {
431
+ if (!isRecord$1(raw)) throw malformed("user_grant.org_tokens entries must be objects");
432
+ return {
433
+ access_token: requireText(raw, "access_token"),
434
+ expires_at: requireText(raw, "expires_at"),
435
+ oauth_grant_id: requireText(raw, "oauth_grant_id"),
436
+ org_id: requireText(raw, "org_id"),
437
+ org_name: nullableText(raw, "org_name"),
438
+ role: nullableText(raw, "role")
439
+ };
440
+ }
441
+ function parseUserGrantCredentials(raw) {
442
+ const grantRaw = raw.user_grant;
443
+ if (!isRecord$1(grantRaw)) throw malformed("user_grant must be an object");
444
+ if (raw.token_type !== "Bearer") throw malformed("token_type must be Bearer");
445
+ const tokensRaw = grantRaw.org_tokens ?? {};
446
+ if (!isRecord$1(tokensRaw)) throw malformed("user_grant.org_tokens must be an object");
447
+ const orgTokens = {};
448
+ for (const [orgId, token] of Object.entries(tokensRaw)) orgTokens[orgId] = parseOrgToken(token);
449
+ const orgId = requireText(raw, "org_id", { allowEmpty: true });
450
+ return {
451
+ access_token: requireText(raw, "access_token", { allowEmpty: true }),
452
+ api_base_url: readStoredApiBaseUrl(raw),
453
+ auth_method: "user_grant",
454
+ created_at: requireText(raw, "created_at"),
455
+ expires_at: requireText(raw, "expires_at"),
456
+ oauth_client_id: requireText(raw, "oauth_client_id"),
457
+ oauth_grant_id: requireText(raw, "oauth_grant_id", { allowEmpty: true }),
458
+ org_id: orgId,
459
+ org_name: nullableText(raw, "org_name"),
460
+ refresh_token: requireText(raw, "refresh_token"),
461
+ token_type: "Bearer",
462
+ user_grant: {
463
+ access_token: requireText(grantRaw, "access_token"),
464
+ expires_at: requireText(grantRaw, "expires_at"),
465
+ org_role: nullableText(grantRaw, "org_role"),
466
+ org_tokens: orgTokens,
467
+ requested_grant: nullableText(grantRaw, "requested_grant"),
468
+ user_grant_id: requireText(grantRaw, "user_grant_id"),
469
+ user_id: requireText(grantRaw, "user_id")
470
+ }
471
+ };
472
+ }
415
473
  function credentialsPath(configDir) {
416
474
  return join(configDir, CREDENTIALS_FILE);
417
475
  }
@@ -674,21 +732,6 @@ function detectPrimitiveKeyEnvMisname(env = process.env) {
674
732
  if ((primitiveKey?.length ?? 0) > 0 && (primitiveApiKey?.length ?? 0) === 0) return "PRIMITIVE_KEY is set but the CLI reads PRIMITIVE_API_KEY. Rename your env var, or re-run with PRIMITIVE_API_KEY=$PRIMITIVE_KEY.";
675
733
  return null;
676
734
  }
677
- /**
678
- * True when a usable OAuth login session is saved on disk. Used by `pay-email`
679
- * to decide whether it can safely ignore an env-only `PRIMITIVE_API_KEY` in
680
- * favor of the payer's logged-in account (which owns the inbound challenge
681
- * inbox). Returns false when nothing is stored or the stored credential is
682
- * unreadable/legacy, so the caller falls back to whatever key did resolve
683
- * rather than silently dropping the user's only auth.
684
- */
685
- function hasStoredCliLogin(configDir) {
686
- try {
687
- return loadCliCredentials(configDir) !== null;
688
- } catch {
689
- return false;
690
- }
691
- }
692
735
  function resolveCliAuth(params) {
693
736
  const apiKey = params.apiKey?.trim();
694
737
  const apiBaseUrl = normalizeApiBaseUrl(params.apiBaseUrl);
@@ -903,4 +946,4 @@ function redactCliEnvironment(environment) {
903
946
  ...headers ? { headers } : {}
904
947
  };
905
948
  }
906
- export { saveActiveChatState as A, parseConnectedAgentProfile as B, resolveCliAuth as C, deleteChatState as D, chatStatePath as E, agentProfileName as F, PrimitiveApiClient as G, profileAlreadyConnectedMessage as H, agentProfilesDirectory as I, connectedAgentIdentity as L, AGENT_PROFILE_ENV as M, AgentConnectionSetupError as N, loadActiveChatState as O, agentProfileDirectory as P, connectedApiBaseUrl as R, normalizeApiBaseUrl as S, saveSignupCredentials as T, requireDefaultLoginProfile as U, parseOwnerMemberAddress as V, saveConnectedAgentProfile as W, deleteCliCredentials as _, normalizeCliEnvironmentName as a, hasStoredCliLogin as b, resolveConfigEnvironment as c, validateCliHeaderName as d, validateCliHeaderValue as f, credentialsPath as g, credentialsLockPath as h, loadCliConfig as i, AGENT_ADDRESS_ENV as j, loadChatConversationByLocalId as k, saveCliConfig as l, cliAccessTokenExpiresAt as m, deleteCliConfig as n, redactCliEnvironment as o, acquireCliCredentialsLock as p, emptyCliConfig as r, removeCliEnvironment as s, DEFAULT_ENVIRONMENT as t, upsertCliEnvironment as u, deleteCliCredentialsLock as v, saveCliCredentials as w, loadCliCredentials as x, detectPrimitiveKeyEnvMisname as y, loadConnectedAgentProfile as z };
949
+ export { AGENT_ADDRESS_ENV as A, parseOwnerMemberAddress as B, saveCliCredentials as C, loadActiveChatState as D, deleteChatState as E, agentProfilesDirectory as F, requireDefaultLoginProfile as H, connectedAgentIdentity as I, connectedApiBaseUrl as L, AgentConnectionSetupError as M, agentProfileDirectory as N, loadChatConversationByLocalId as O, agentProfileName as P, loadConnectedAgentProfile as R, resolveCliAuth as S, chatStatePath as T, saveConnectedAgentProfile as U, profileAlreadyConnectedMessage as V, PrimitiveApiClient as W, deleteCliCredentials as _, normalizeCliEnvironmentName as a, loadCliCredentials as b, resolveConfigEnvironment as c, validateCliHeaderName as d, validateCliHeaderValue as f, credentialsPath as g, credentialsLockPath as h, loadCliConfig as i, AGENT_PROFILE_ENV as j, saveActiveChatState as k, saveCliConfig as l, cliAccessTokenExpiresAt as m, deleteCliConfig as n, redactCliEnvironment as o, acquireCliCredentialsLock as p, emptyCliConfig as r, removeCliEnvironment as s, DEFAULT_ENVIRONMENT as t, upsertCliEnvironment as u, deleteCliCredentialsLock as v, saveSignupCredentials as w, normalizeApiBaseUrl as x, detectPrimitiveKeyEnvMisname as y, parseConnectedAgentProfile as z };
@@ -1,3 +1,4 @@
1
+ import { Flags } from "@oclif/core";
1
2
  import { format } from "node:util";
2
3
  // src/oclif/json-output.ts
3
4
  /**
@@ -22,6 +23,11 @@ import { format } from "node:util";
22
23
  * line per result on stdout, and on failure one more JSON line carrying
23
24
  * `error` and `exit_code`.
24
25
  */
26
+ /**
27
+ * The `--json` flag for a hand-rolled command whose output is already JSON.
28
+ * Declaring it is enough: the registry guards every command that has it.
29
+ */
30
+ const JSON_OUTPUT_FLAG = Flags.boolean({ description: "Print exactly one JSON document on stdout, on success and on failure, and nothing on stderr. A failure prints the error with exit_code." });
25
31
  const GUARDED = Symbol.for("primitive.cli.jsonOutputGuard");
26
32
  /** True when `--json` appears before any `--` separator. */
27
33
  function jsonOutputRequested(argv) {
@@ -139,11 +145,18 @@ function errorExitCode(error) {
139
145
  function isExitSignal(error) {
140
146
  return error?.code === "EEXIT";
141
147
  }
148
+ /**
149
+ * The `error` a `--json` document carries for a thrown error: its message,
150
+ * and its `code` and `details` when it has them (a refusal the CLI makes in
151
+ * an API error's shape, such as a send without mail:send).
152
+ */
142
153
  function thrownErrorBody(error) {
143
154
  if (error instanceof Error) {
144
155
  const body = { message: error.message };
145
156
  const code = error.code;
146
157
  if (typeof code === "string" && code !== "EEXIT") body.code = code;
158
+ const details = error.details;
159
+ if (isPlainObject(details)) body.details = details;
147
160
  return body;
148
161
  }
149
162
  return { message: String(error) };
@@ -318,4 +331,4 @@ function guardJsonOutputCommands(commands) {
318
331
  if (flags && "json" in flags || enableJsonFlag === true) guardJsonOutput(command);
319
332
  }
320
333
  }
321
- export { jsonOutputRequested as n, runStreamingJson as r, guardJsonOutputCommands as t };
334
+ export { thrownErrorBody as a, runStreamingJson as i, guardJsonOutputCommands as n, jsonOutputRequested as r, JSON_OUTPUT_FLAG as t };