@quantiya/codevibe-core 2.0.49 → 2.0.50

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.
@@ -61,6 +61,22 @@ export declare function markKeytarUsed(): void;
61
61
  * pinned down here rather than only through a (non-deterministic) init path.
62
62
  */
63
63
  export declare function fileStoreHasCredentials(): boolean;
64
+ /**
65
+ * Did keytar fail to load because its NATIVE BINARY is missing? That is the exact
66
+ * 2026-09-23 failure: an installer skipped keytar's install script, so the package
67
+ * was present with no build/Release/keytar.node and require() threw
68
+ * "Cannot find module '../build/Release/keytar.node'". It is an installation
69
+ * defect, not a keyring or sign-in problem, and rebuilding the module repairs it.
70
+ * Deliberately narrow — any other load error keeps its existing message.
71
+ */
72
+ export declare function isKeytarBinaryMissing(loadError: string | null): boolean;
73
+ /**
74
+ * The message for a keytar whose native binary is missing. `codevibe update`
75
+ * repairs the Claude Code plugin; the explicit rebuild works for every install
76
+ * layout (plugin cache and global npm install), fetching keytar's prebuilt
77
+ * binary as a normal install does.
78
+ */
79
+ export declare function keytarBinaryMissingMessage(loadError: string, installRoot: string | null, migratedToKeyring?: boolean): string;
64
80
  /** True if the file backend was auto-selected (no OS keyring service present). */
65
81
  export declare function wasAutoFileFallback(): boolean;
66
82
  /**
@@ -62,7 +62,7 @@ export declare class CliEntitlementError extends Error {
62
62
  constructor(message: string, cause?: unknown);
63
63
  }
64
64
  /** Both Companion and Orchestration require a verified signed-in account. */
65
- export declare function requireCliAuthentication(client: Pick<AppSyncClient, 'authenticateWithStoredTokens' | 'getLastAuthFailureKind'>): Promise<void>;
65
+ export declare function requireCliAuthentication(client: Pick<AppSyncClient, 'authenticateWithStoredTokens' | 'getLastAuthFailureKind'> & Partial<Pick<AppSyncClient, 'getLastAuthFailureDetail'>>): Promise<void>;
66
66
  export interface ParsedCliArgs {
67
67
  agent?: 'CLAUDE' | 'CODEX' | 'ANTIGRAVITY';
68
68
  help: boolean;
@@ -1696,6 +1696,34 @@ function fileStoreHasCredentials() {
1696
1696
  return !1;
1697
1697
  }
1698
1698
  }
1699
+ function isKeytarBinaryMissing(loadError) {
1700
+ return loadError !== null && /Cannot find module ['"][^'"]*keytar\.node['"]/.test(loadError);
1701
+ }
1702
+ function keytarInstallRoot() {
1703
+ try {
1704
+ let nodeRequire = eval("require"), packageDir = path4.dirname(nodeRequire.resolve("keytar/package.json"));
1705
+ return path4.dirname(path4.dirname(packageDir));
1706
+ } catch {
1707
+ return null;
1708
+ }
1709
+ }
1710
+ function keytarBinaryMissingMessage(loadError, installRoot, migratedToKeyring = !1) {
1711
+ return [
1712
+ "CodeVibe's keyring module (keytar) is installed without its native binary,",
1713
+ "so CodeVibe cannot read the credentials it keeps in the OS keyring.",
1714
+ "This is an incomplete installation, not a sign-in problem: `codevibe login`",
1715
+ "will not fix it. Repair the module with:",
1716
+ installRoot ? ` (cd "${installRoot}" && npm rebuild prebuild-install keytar)` : " npm rebuild prebuild-install keytar (in the directory whose node_modules holds keytar)",
1717
+ "(`codevibe update` also repairs this for the Claude Code plugin.)",
1718
+ // On a migrated machine the fail-closed guarantee must stay visible: file storage is
1719
+ // retired here, and using it would fork the device identity.
1720
+ ...migratedToKeyring ? ["Refusing to fall back to file storage \u2014 that would fork the device identity."] : [],
1721
+ // First line only: Node appends a multi-line "Require stack" that buries the fix.
1722
+ `(keytar load error: ${loadError.split(`
1723
+ `)[0]})`
1724
+ ].join(`
1725
+ `);
1726
+ }
1699
1727
  function autoSelectFileBackend(reason) {
1700
1728
  warnToStderr([
1701
1729
  "",
@@ -1790,7 +1818,15 @@ function initBackends() {
1790
1818
  backend = "keytar", logger.info("[keychain-backend] Using keytar (migrated-to-keyring tombstone present)"), markKeytarUsed();
1791
1819
  return;
1792
1820
  }
1793
- keytarModule = null, initError = new KeychainBackendUnavailableError(
1821
+ if (keytarModule = null, tombstoneKeytarError && isKeytarBinaryMissing(tombstoneKeytarError)) {
1822
+ initError = new KeychainBackendUnavailableError(
1823
+ keytarBinaryMissingMessage(tombstoneKeytarError, keytarInstallRoot(), !0)
1824
+ ), logger.warn(
1825
+ "[keychain-backend] migrated-to-keyring tombstone but keytar has no native binary \u2014 failing closed (incomplete installation)"
1826
+ );
1827
+ return;
1828
+ }
1829
+ initError = new KeychainBackendUnavailableError(
1794
1830
  [
1795
1831
  "This machine migrated its CodeVibe credentials to the OS keyring, but the",
1796
1832
  "keyring is not reachable in this session (no desktop session / D-Bus).",
@@ -1843,6 +1879,12 @@ function initBackends() {
1843
1879
  autoFileOrRefuse("keytar_load_failed");
1844
1880
  return;
1845
1881
  }
1882
+ if (keytarLoadError && isKeytarBinaryMissing(keytarLoadError)) {
1883
+ initError = new KeychainBackendUnavailableError(
1884
+ keytarBinaryMissingMessage(keytarLoadError, keytarInstallRoot())
1885
+ );
1886
+ return;
1887
+ }
1846
1888
  initError = new KeychainBackendUnavailableError(
1847
1889
  [
1848
1890
  "CodeVibe could not load the OS-native keyring (keytar).",
@@ -4659,6 +4701,20 @@ var RECONNECT_CONFIG = {
4659
4701
  function shouldDeliverSubscribedEvent(event, receiveDesktopEvents) {
4660
4702
  return !!(event.source === "MOBILE" /* MOBILE */ || receiveDesktopEvents && event.source === "DESKTOP" /* DESKTOP */);
4661
4703
  }
4704
+ var CREDENTIAL_STORAGE_UNAVAILABLE_EXIT_CODE = 78;
4705
+ function describeStoredAuthFailure(kind, detail) {
4706
+ return kind === "credential_storage_unavailable" ? {
4707
+ exitCode: CREDENTIAL_STORAGE_UNAVAILABLE_EXIT_CODE,
4708
+ message: [
4709
+ "CodeVibe could not read its stored credentials. This is not a sign-in problem.",
4710
+ detail ?? "The credential store is unavailable."
4711
+ ].join(`
4712
+ `)
4713
+ } : kind === "refresh_network" ? {
4714
+ exitCode: 1,
4715
+ message: "Could not reach the CodeVibe sign-in service to refresh your session. Check your network connection and try again; you are still signed in."
4716
+ } : { exitCode: 1, message: 'Not authenticated. Run "codevibe login" to sign in.' };
4717
+ }
4662
4718
  var DEFAULT_HEARTBEAT_INTERVAL_MS = 12e4, MIN_HEARTBEAT_INTERVAL_MS = 1e3, MAX_HEARTBEAT_INTERVAL_MS = 3e5;
4663
4719
  function isRecognizedNonProductionEnvironment(env = process.env) {
4664
4720
  let canonicalEnv = getEnvironment(env);
@@ -4685,6 +4741,11 @@ var AppSyncClient = class _AppSyncClient {
4685
4741
  * round-1 Codex M1.
4686
4742
  */
4687
4743
  this.lastAuthFailureKind = null;
4744
+ /**
4745
+ * The credential-store error message behind a `credential_storage_unavailable`
4746
+ * failure (it names the cause and the fix). `null` for every other outcome.
4747
+ */
4748
+ this.lastAuthFailureDetail = null;
4688
4749
  /**
4689
4750
  * Sentinel set inside `performRefresh` / `callCognitoRefresh` when
4690
4751
  * the refresh round-trip fails with a network-shaped error (DNS,
@@ -4801,6 +4862,10 @@ var AppSyncClient = class _AppSyncClient {
4801
4862
  getLastAuthFailureKind() {
4802
4863
  return this.lastAuthFailureKind;
4803
4864
  }
4865
+ /** The credential-store error message behind a `credential_storage_unavailable` failure. */
4866
+ getLastAuthFailureDetail() {
4867
+ return this.lastAuthFailureDetail;
4868
+ }
4804
4869
  /**
4805
4870
  * Heuristic — does the error message look like a transient network
4806
4871
  * failure rather than an auth-token rejection? Used for refresh-path
@@ -4815,13 +4880,13 @@ var AppSyncClient = class _AppSyncClient {
4815
4880
  * Authenticate using stored OAuth tokens from keychain
4816
4881
  */
4817
4882
  async authenticateWithStoredTokens() {
4818
- this.lastAuthFailureKind = null;
4883
+ this.lastAuthFailureKind = null, this.lastAuthFailureDetail = null;
4819
4884
  try {
4820
4885
  let tokens;
4821
4886
  try {
4822
4887
  tokens = await keychainManager.getTokens(this.environment);
4823
4888
  } catch (error) {
4824
- return logger.error("[AppSyncClient] Could not read stored authentication tokens:", error), this.lastAuthFailureKind = "credential_storage_unavailable", !1;
4889
+ return logger.error("[AppSyncClient] Could not read stored authentication tokens:", error), this.lastAuthFailureKind = "credential_storage_unavailable", this.lastAuthFailureDetail = error instanceof Error ? error.message : String(error), !1;
4825
4890
  }
4826
4891
  if (!tokens)
4827
4892
  return logger.debug("[AppSyncClient] No stored tokens found"), this.lastAuthFailureKind = "no_tokens", !1;
@@ -77273,7 +77338,7 @@ function renderPreflight(agents, auth, connectivity, orphans) {
77273
77338
  let reason = agent.error ? `(${agent.error})` : "(not in $PATH)";
77274
77339
  console.log(` [${colors.yellow}missing${colors.reset}] ${agent.name} ${colors.dim}${reason}${colors.reset}`);
77275
77340
  }
77276
- agents.filter((a) => a.installed).length === 0 && console.log(` ${colors.red}! At least one agent CLI (Claude, Codex, or Antigravity) is required.${colors.reset}`), console.log(), console.log(`${colors.bold}Authentication & Credentials:${colors.reset}`), auth.error ? console.log(` [${colors.red}error${colors.reset}] Auth check failed: ${auth.error}`) : !auth.authenticated && !auth.tokenExpired ? (console.log(` [${colors.yellow}missing${colors.reset}] Not authenticated.`), console.log(` ${colors.dim}Run '${colors.reset}${colors.bold}codevibe login${colors.reset}${colors.dim}' to sign in.${colors.reset}`)) : auth.tokenExpired ? (console.log(` [${colors.yellow}expired${colors.reset}] Token expired for ${auth.email ?? "user"}`), console.log(` ${colors.dim}Run '${colors.reset}${colors.bold}codevibe doctor --repair --yes${colors.reset}${colors.dim}' to refresh.${colors.reset}`)) : console.log(` [${colors.green}ok${colors.reset}] Authenticated as ${auth.email ?? "user"}${auth.expiresAt ? ` ${colors.dim}(valid until ${auth.expiresAt})${colors.reset}` : ""}`), auth.deviceIdentityError ? (console.log(` [${colors.red}error${colors.reset}] Device Identity: ${auth.deviceIdentityError}`), console.log(` ${colors.dim}Run '${colors.reset}${colors.bold}codevibe login${colors.reset}${colors.dim}' to re-establish device credentials.${colors.reset}`)) : auth.deviceIdentityPresent ? console.log(` [${colors.green}ok${colors.reset}] Device Identity ${auth.deviceIdentityId ? `${colors.dim}(${auth.deviceIdentityId})${colors.reset}` : ""}`) : (console.log(` [${colors.yellow}missing${colors.reset}] Device Identity not found`), console.log(` ${colors.dim}Run '${colors.reset}${colors.bold}codevibe login${colors.reset}${colors.dim}' to generate device credentials.${colors.reset}`));
77341
+ agents.filter((a) => a.installed).length === 0 && console.log(` ${colors.red}! At least one agent CLI (Claude, Codex, or Antigravity) is required.${colors.reset}`), console.log(), console.log(`${colors.bold}Authentication & Credentials:${colors.reset}`), auth.error ? console.log(` [${colors.red}error${colors.reset}] Auth check failed: ${auth.error}`) : !auth.authenticated && !auth.tokenExpired ? (console.log(` [${colors.yellow}missing${colors.reset}] Not authenticated.`), console.log(` ${colors.dim}Run '${colors.reset}${colors.bold}codevibe login${colors.reset}${colors.dim}' to sign in.${colors.reset}`)) : auth.tokenExpired ? (console.log(` [${colors.yellow}expired${colors.reset}] Token expired for ${auth.email ?? "user"}`), console.log(` ${colors.dim}Run '${colors.reset}${colors.bold}codevibe doctor --repair --yes${colors.reset}${colors.dim}' to refresh.${colors.reset}`)) : console.log(` [${colors.green}ok${colors.reset}] Authenticated as ${auth.email ?? "user"}${auth.expiresAt ? ` ${colors.dim}(valid until ${auth.expiresAt})${colors.reset}` : ""}`), auth.error ? console.log(` [${colors.yellow}unknown${colors.reset}] Device Identity: not checked (the credential store could not be read \u2014 see above)`) : auth.deviceIdentityError ? (console.log(` [${colors.red}error${colors.reset}] Device Identity: ${auth.deviceIdentityError}`), console.log(` ${colors.dim}Run '${colors.reset}${colors.bold}codevibe login${colors.reset}${colors.dim}' to re-establish device credentials.${colors.reset}`)) : auth.deviceIdentityPresent ? console.log(` [${colors.green}ok${colors.reset}] Device Identity ${auth.deviceIdentityId ? `${colors.dim}(${auth.deviceIdentityId})${colors.reset}` : ""}`) : (console.log(` [${colors.yellow}missing${colors.reset}] Device Identity not found`), console.log(` ${colors.dim}Run '${colors.reset}${colors.bold}codevibe login${colors.reset}${colors.dim}' to generate device credentials.${colors.reset}`));
77277
77342
  let backendName = auth.vendorKeys.custodyBackend === "keytar" ? "OS Keychain" : "File Store";
77278
77343
  if (console.log(` [${auth.vendorKeys.anthropic ? colors.green + "ok" : colors.dim + "none"}${colors.reset}] Anthropic Vendor Key ${colors.dim}(${auth.vendorKeys.anthropic ? backendName : "not set"})${colors.reset}`), console.log(` [${auth.vendorKeys.openai ? colors.green + "ok" : colors.dim + "none"}${colors.reset}] OpenAI Credential ${colors.dim}(${auth.vendorKeys.openai ? backendName : "not set"})${colors.reset}`), console.log(), console.log(`${colors.bold}Backend Connectivity:${colors.reset}`), connectivity.appsyncReachable ? console.log(` [${colors.green}ok${colors.reset}] AppSync API (${connectivity.latencyMs ?? 0}ms) ${colors.dim}${connectivity.appsyncUrl}${colors.reset}`) : console.log(` [${colors.red}unreachable${colors.reset}] AppSync API: ${connectivity.error ?? "unreachable"} ${colors.dim}(${connectivity.appsyncUrl})${colors.reset}`), console.log(), console.log(`${colors.bold}Workspace & Process State:${colors.reset}`), orphans.error ? console.log(` [${colors.red}error${colors.reset}] Orphan inspection failed: ${orphans.error}`) : orphans.orphanedShadowCount > 0 || orphans.deadProcessOwnersCount > 0 ? (console.log(` [${colors.yellow}residue${colors.reset}] ${orphans.orphanedShadowCount} orphaned worktree shadow(s), ${orphans.deadProcessOwnersCount} dead process registration(s)`), console.log(` ${colors.dim}Run '${colors.reset}${colors.bold}codevibe doctor --repair --yes${colors.reset}${colors.dim}' to prune.${colors.reset}`)) : console.log(` [${colors.green}ok${colors.reset}] Clean \u2014 0 orphaned shadows, 0 dead process registrations.`), orphans.retainedStateDiagnostics && orphans.retainedStateDiagnostics.length > 0)
77279
77344
  for (let diag of orphans.retainedStateDiagnostics)
@@ -80457,13 +80522,20 @@ async function requireCliAuthentication(client) {
80457
80522
  }
80458
80523
  if (authenticated) return;
80459
80524
  let failureKind = client.getLastAuthFailureKind();
80460
- throw failureKind === "refresh_network" ? new CliAuthenticationError(
80461
- "auth_unavailable",
80462
- "CodeVibe could not verify your sign-in because the authentication service is unreachable. Check your connection and try again."
80463
- ) : failureKind === "credential_storage_unavailable" ? new CliAuthenticationError(
80464
- "credential_storage_unavailable",
80465
- "CodeVibe could not read stored sign-in credentials. Unlock or repair your credential store, then try again."
80466
- ) : new CliAuthenticationError(
80525
+ if (failureKind === "refresh_network")
80526
+ throw new CliAuthenticationError(
80527
+ "auth_unavailable",
80528
+ "CodeVibe could not verify your sign-in because the authentication service is unreachable. Check your connection and try again."
80529
+ );
80530
+ if (failureKind === "credential_storage_unavailable") {
80531
+ let detail = client.getLastAuthFailureDetail?.() ?? null;
80532
+ throw new CliAuthenticationError(
80533
+ "credential_storage_unavailable",
80534
+ "CodeVibe could not read stored sign-in credentials. Unlock or repair your credential store, then try again." + (detail ? `
80535
+ ${detail}` : "")
80536
+ );
80537
+ }
80538
+ throw new CliAuthenticationError(
80467
80539
  "auth_required",
80468
80540
  "Not signed in. Run `codevibe login`, then launch CodeVibe again."
80469
80541
  );
@@ -81102,13 +81174,14 @@ Note: --export will overwrite any existing file at <path>.
81102
81174
  try {
81103
81175
  authenticated = await appsyncClient.authenticateWithStoredTokens();
81104
81176
  } catch (e) {
81105
- return err(
81106
- `Not signed in \u2014 run \`codevibe login\` first (${e?.message ?? "auth unavailable"}).
81107
- `
81108
- ), 2;
81177
+ return err(`CodeVibe could not verify your sign-in (${e?.message ?? "auth unavailable"}).
81178
+ `), 2;
81179
+ }
81180
+ if (!authenticated) {
81181
+ let kind = appsyncClient.getLastAuthFailureKind?.() ?? null;
81182
+ return kind === "credential_storage_unavailable" || kind === "refresh_network" ? (err(`${describeStoredAuthFailure(kind, appsyncClient.getLastAuthFailureDetail?.() ?? null).message}
81183
+ `), 2) : (err("Not signed in \u2014 run `codevibe login` first.\n"), 2);
81109
81184
  }
81110
- if (!authenticated)
81111
- return err("Not signed in \u2014 run `codevibe login` first.\n"), 2;
81112
81185
  let sessionId = parsed.sessionId ?? null;
81113
81186
  if (!sessionId) {
81114
81187
  let resolveSessionId = deps?.resolveSessionIdFn ?? resolveActiveSessionId;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quantiya/codevibe-core",
3
- "version": "2.0.49",
3
+ "version": "2.0.50",
4
4
  "description": "Core library for CodeVibe plugins - shared keychain, crypto, AppSync, and auth functionality",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",