perplexity-user-mcp 0.8.39 → 0.8.44

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.
Files changed (133) hide show
  1. package/README.md +5 -0
  2. package/dist/attachments.d.ts +10 -20
  3. package/dist/browser-window.d.ts +1 -0
  4. package/dist/cf-warmup.d.ts +32 -0
  5. package/dist/checks/browser.d.ts +12 -100
  6. package/dist/checks/config.d.ts +25 -91
  7. package/dist/checks/ide.d.ts +31 -89
  8. package/dist/checks/mcp.d.ts +12 -61
  9. package/dist/checks/native-deps.d.ts +46 -131
  10. package/dist/checks/network.d.ts +13 -71
  11. package/dist/checks/probe.d.ts +20 -92
  12. package/dist/checks/profiles.d.ts +13 -99
  13. package/dist/checks/profiles.mjs +35 -0
  14. package/dist/checks/runtime.d.ts +24 -89
  15. package/dist/checks/vault.d.ts +13 -142
  16. package/dist/checks/vault.mjs +6 -11
  17. package/dist/{chunk-T6ARJK2P.mjs → chunk-2B5OQUXR.mjs} +6 -6
  18. package/dist/{chunk-2FPGJKCA.mjs → chunk-2EE7MNP2.mjs} +2 -2
  19. package/dist/{chunk-NJX4RBO6.mjs → chunk-2OVLCZHU.mjs} +28 -3
  20. package/dist/{chunk-WDIW33DA.mjs → chunk-3LUO5ATM.mjs} +1 -1
  21. package/dist/{chunk-B65IJQZJ.mjs → chunk-6E6XTHTG.mjs} +1 -1
  22. package/dist/{chunk-S677V2JU.mjs → chunk-C5I7KXHK.mjs} +32 -2
  23. package/dist/{chunk-TDXETAQT.mjs → chunk-DKEJZ4FI.mjs} +1 -1
  24. package/dist/{chunk-U7QPUNRH.mjs → chunk-DXR6EEZH.mjs} +26 -7
  25. package/dist/{chunk-HJIXH6CL.mjs → chunk-E3GRJXXJ.mjs} +2 -0
  26. package/dist/{chunk-RK4EBZJ3.mjs → chunk-E75J42W5.mjs} +11 -8
  27. package/dist/{chunk-452DK6OS.mjs → chunk-FNHYUE22.mjs} +2 -2
  28. package/dist/{chunk-D254EFYB.mjs → chunk-GBI2U336.mjs} +1 -1
  29. package/dist/chunk-GPUGKWXH.mjs +17 -0
  30. package/dist/{chunk-HNSPNCFH.mjs → chunk-KSNV3ZVY.mjs} +1 -1
  31. package/dist/{chunk-XTRJSV72.mjs → chunk-LGH5BSUY.mjs} +1 -1
  32. package/dist/{chunk-KJFX2ZXR.mjs → chunk-NMKNEEZB.mjs} +1 -1
  33. package/dist/{chunk-FKQ3HP4Q.mjs → chunk-TIWHN4IW.mjs} +1 -1
  34. package/dist/{chunk-V4U3JM4R.mjs → chunk-TSLRTZYR.mjs} +1 -1
  35. package/dist/{chunk-DQQISMYN.mjs → chunk-V4LHDNWJ.mjs} +2 -2
  36. package/dist/{chunk-C3HPFFTD.mjs → chunk-WHVJ724K.mjs} +84 -44
  37. package/dist/cli.d.ts +14 -1298
  38. package/dist/cli.mjs +35 -27
  39. package/dist/client.d.ts +27 -24
  40. package/dist/client.mjs +6 -6
  41. package/dist/cloud-sync.d.ts +65 -42
  42. package/dist/cloud-sync.mjs +8 -8
  43. package/dist/config.d.ts +35 -39
  44. package/dist/config.mjs +3 -3
  45. package/dist/cookie-jar.d.ts +77 -0
  46. package/dist/daemon/attach.d.ts +10 -11
  47. package/dist/daemon/attach.mjs +19 -17
  48. package/dist/daemon/audit.d.ts +5 -7
  49. package/dist/daemon/audit.mjs +2 -2
  50. package/dist/daemon/client-http.d.ts +10 -16
  51. package/dist/daemon/client-http.mjs +17 -17
  52. package/dist/daemon/index.d.ts +17 -14
  53. package/dist/daemon/index.mjs +18 -18
  54. package/dist/daemon/install-tunnel.d.ts +8 -34
  55. package/dist/daemon/install-tunnel.mjs +2 -2
  56. package/dist/daemon/launcher.d.ts +24 -29
  57. package/dist/daemon/launcher.mjs +16 -16
  58. package/dist/daemon/local-tokens.d.ts +23 -0
  59. package/dist/daemon/lockfile.d.ts +10 -12
  60. package/dist/daemon/lockfile.mjs +2 -2
  61. package/dist/daemon/oauth-consent-cache.d.ts +86 -0
  62. package/dist/daemon/oauth-provider.d.ts +132 -0
  63. package/dist/daemon/public-pages.d.ts +9 -0
  64. package/dist/daemon/security.d.ts +52 -0
  65. package/dist/daemon/server.d.ts +12 -83
  66. package/dist/daemon/server.mjs +11 -11
  67. package/dist/daemon/token.d.ts +7 -9
  68. package/dist/daemon/token.mjs +2 -2
  69. package/dist/daemon/tunnel-providers/cloudflared-named-setup.d.ts +140 -0
  70. package/dist/daemon/tunnel-providers/cloudflared-named.d.ts +45 -0
  71. package/dist/daemon/tunnel-providers/cloudflared-quick.d.ts +8 -0
  72. package/dist/daemon/tunnel-providers/index.d.ts +16 -327
  73. package/dist/daemon/tunnel-providers/index.mjs +3 -3
  74. package/dist/daemon/tunnel-providers/ngrok-config.d.ts +18 -0
  75. package/dist/daemon/tunnel-providers/ngrok.d.ts +68 -0
  76. package/dist/daemon/tunnel-providers/types.d.ts +56 -0
  77. package/dist/daemon/tunnel.d.ts +5 -7
  78. package/dist/debug-tracer.d.ts +2 -0
  79. package/dist/doctor-report.d.ts +17 -22
  80. package/dist/doctor.d.ts +12 -44
  81. package/dist/doctor.mjs +2 -2
  82. package/dist/export.d.ts +11 -18
  83. package/dist/export.mjs +4 -4
  84. package/dist/format.d.ts +52 -0
  85. package/dist/fs-utils.d.ts +8 -0
  86. package/dist/health-check.d.ts +1 -108
  87. package/dist/health-check.mjs +3 -3
  88. package/dist/history-store.d.ts +29 -65
  89. package/dist/history-store.mjs +2 -2
  90. package/dist/impit-login-runner.d.ts +1 -469
  91. package/dist/impit-login-runner.mjs +4 -4
  92. package/dist/index.d.ts +25 -149
  93. package/dist/index.mjs +22 -20
  94. package/dist/is-main-module.d.ts +9 -0
  95. package/dist/login-runner.d.ts +1 -333
  96. package/dist/login-runner.mjs +13 -13
  97. package/dist/login.d.ts +5 -0
  98. package/dist/logout.d.ts +2 -28
  99. package/dist/logout.mjs +3 -2
  100. package/dist/manual-login-runner.d.ts +1 -150
  101. package/dist/manual-login-runner.mjs +11 -11
  102. package/dist/{native-deps-IE4B55EL.mjs → native-deps-FCSYDL4W.mjs} +4 -4
  103. package/dist/native-deps.d.ts +36 -0
  104. package/dist/package-version.d.ts +1 -0
  105. package/dist/profiles.d.ts +41 -41
  106. package/dist/profiles.mjs +1 -1
  107. package/dist/prompts.d.ts +2 -0
  108. package/dist/redact.d.ts +14 -142
  109. package/dist/refresh.d.ts +11 -16
  110. package/dist/refresh.mjs +4 -4
  111. package/dist/reinit-watcher.d.ts +15 -24
  112. package/dist/reinit-watcher.mjs +2 -2
  113. package/dist/resources.d.ts +5 -0
  114. package/dist/safe-write.d.ts +16 -0
  115. package/dist/session-metadata.d.ts +45 -0
  116. package/dist/tool-config.d.ts +10 -0
  117. package/dist/tools.d.ts +23 -0
  118. package/dist/tty-prompt.d.ts +18 -34
  119. package/dist/vault.d.ts +114 -34
  120. package/dist/vault.mjs +6 -4
  121. package/dist/viewer-detect.d.ts +2 -4
  122. package/dist/viewers.d.ts +13 -18
  123. package/dist/viewers.mjs +1 -1
  124. package/package.json +3 -3
  125. package/dist/cloud-sync.d-Cqt6y18U.d.ts +0 -42
  126. package/dist/doctor.d-CXmUqOXX.d.ts +0 -43
  127. package/dist/history-store.d-BzjBF2m3.d.ts +0 -65
  128. package/dist/native-deps-BNThFHxa.d.ts +0 -175
  129. package/dist/profiles.d-DqS1oZWr.d.ts +0 -41
  130. package/dist/session-metadata-B9aV_n5g.d.ts +0 -148
  131. package/dist/vault.d-BSJWDLhp.d.ts +0 -37
  132. package/dist/viewer-detect.d-HWGnyFAA.d.ts +0 -4
  133. package/dist/viewers.d-BGCK6sw6.d.ts +0 -10
@@ -1,142 +1,13 @@
1
- import { existsSync } from 'node:fs';
2
- import { join } from 'node:path';
3
-
4
- const CATEGORY = "vault";
5
-
6
- async function tryKeychain() {
7
- try {
8
- const mod = await import('keytar');
9
- const keytar = mod.default ?? mod;
10
- const hex = await keytar.getPassword("perplexity-user-mcp", "vault-master-key");
11
- return { available: true, hasKey: !!hex };
12
- } catch {
13
- return { available: false, hasKey: false };
14
- }
15
- }
16
-
17
- function keychainExpected() {
18
- return process.platform === "win32" || process.platform === "darwin" ||
19
- (process.platform === "linux" && !process.env.CI);
20
- }
21
-
22
- async function run(opts = {}) {
23
- const results = [];
24
- const dir = opts.configDir;
25
- const profile = opts.profile ?? "default";
26
- const enc = join(dir, "profiles", profile, "vault.enc");
27
- const plain = join(dir, "profiles", profile, "vault.json");
28
- const envPass = process.env.PERPLEXITY_VAULT_PASSPHRASE;
29
- const kc = await tryKeychain();
30
-
31
- // Encryption mode (separate from unseal path so plaintext opt-out is always a warn, not a skip).
32
- if (existsSync(plain)) {
33
- results.push({
34
- category: CATEGORY,
35
- name: "encryption",
36
- status: "warn",
37
- message: "plaintext vault.json (security.encryptCookies=false)",
38
- hint: "Re-run login without --plain-cookies to enable AES-256-GCM at rest.",
39
- });
40
- } else if (existsSync(enc)) {
41
- results.push({ category: CATEGORY, name: "encryption", status: "pass", message: "AES-256-GCM (vault.enc)" });
42
- } else {
43
- results.push({ category: CATEGORY, name: "encryption", status: "skip", message: "no vault yet" });
44
- }
45
-
46
- // Unseal path resolution, matching vault.js getMasterKey() priority.
47
- if (kc.hasKey) {
48
- results.push({ category: CATEGORY, name: "unseal-path", status: "pass", message: "OS keychain holds master key" });
49
- if (envPass) {
50
- results.push({
51
- category: CATEGORY,
52
- name: "keychain-preferred",
53
- status: "warn",
54
- message: "PERPLEXITY_VAULT_PASSPHRASE is also set — keychain wins, but consider removing the env var",
55
- });
56
- }
57
- } else if (envPass) {
58
- const hasKc = kc.available;
59
- results.push({
60
- category: CATEGORY,
61
- name: "unseal-path",
62
- status: "pass",
63
- message: `env var ${hasKc ? "(keychain available but empty)" : "(keychain unavailable — expected on headless Linux)"}`,
64
- });
65
- if (hasKc) {
66
- results.push({
67
- category: CATEGORY,
68
- name: "keychain-preferred",
69
- status: "warn",
70
- message: "keychain is available — moving the master key there would remove the passphrase from IDE config files",
71
- hint: "Run `npx perplexity-user-mcp login` once with the env var unset; the key will be written to keychain.",
72
- });
73
- } else {
74
- results.push({ category: CATEGORY, name: "keychain-preferred", status: "skip", message: "keychain not applicable" });
75
- }
76
- } else {
77
- // No keychain, no env var.
78
- if (!existsSync(enc) && !existsSync(plain)) {
79
- results.push({ category: CATEGORY, name: "unseal-path", status: "skip", message: "no vault to unseal yet" });
80
- } else if (existsSync(plain)) {
81
- results.push({ category: CATEGORY, name: "unseal-path", status: "pass", message: "plaintext — no key required" });
82
- } else {
83
- const ttyLikely = process.stdin?.isTTY === true;
84
- results.push({
85
- category: CATEGORY,
86
- name: "unseal-path",
87
- status: ttyLikely ? "warn" : "fail",
88
- message: ttyLikely
89
- ? "no keychain, no env var — TTY prompt will be required on next use"
90
- : "vault locked: no keychain, no env var, no TTY",
91
- hint: keychainExpected()
92
- ? "Install libsecret+gnome-keyring (Linux), or set PERPLEXITY_VAULT_PASSPHRASE."
93
- : "Set PERPLEXITY_VAULT_PASSPHRASE in your MCP config env.",
94
- });
95
- }
96
- }
97
-
98
- // Active-decrypt verification — only when an encrypted vault.enc actually
99
- // exists. This catches the "user has both keychain + passphrase set, but
100
- // vault.enc was written with one and the read path now prefers the other"
101
- // failure mode that surfaces as "Vault decrypt failed: wrong passphrase
102
- // or corrupted ciphertext" mid-login. A status check that just reports
103
- // "OS keychain holds master key" is misleading if the key can't actually
104
- // open the on-disk blob.
105
- if (existsSync(enc) && (kc.hasKey || envPass)) {
106
- try {
107
- const { Vault, __resetKeyCache } = await import('../vault.d-BSJWDLhp.d.ts');
108
- // Use a fresh resolution context so the doctor's verification doesn't
109
- // pollute the cached unseal material for the rest of the process.
110
- __resetKeyCache();
111
- // Vault.get returns null for absent keys without throwing; only a
112
- // genuine decrypt failure throws.
113
- await new Vault().get(profile, "cookies");
114
- results.push({
115
- category: CATEGORY,
116
- name: "unseal-verify",
117
- status: "pass",
118
- message: "vault.enc decrypts cleanly with the active unseal material",
119
- });
120
- } catch (err) {
121
- const msg = err instanceof Error ? err.message : String(err);
122
- const isDecryptFailure = /wrong passphrase or corrupted ciphertext|Vault decrypt failed/.test(msg);
123
- results.push({
124
- category: CATEGORY,
125
- name: "unseal-verify",
126
- status: "fail",
127
- message: isDecryptFailure
128
- ? "vault.enc cannot be decrypted with any available unseal material"
129
- : `vault.enc unreadable: ${msg}`,
130
- hint: isDecryptFailure
131
- ? (kc.hasKey && envPass
132
- ? "Both keychain and PERPLEXITY_VAULT_PASSPHRASE are set, but neither matches the blob. The blob was likely written under a since-rotated passphrase or a different keychain key. Run 'perplexity-user-mcp logout --purge' on this profile and log in again to write a fresh vault."
133
- : "The unseal material has changed since this blob was written. Restore the original passphrase, or run 'perplexity-user-mcp logout --purge' on this profile and log in again.")
134
- : "Inspect the file at the path under 'profiles' check; consider restoring from backup or purging.",
135
- });
136
- }
137
- }
138
-
139
- return results;
140
- }
141
-
142
- export { run };
1
+ export function run(opts?: {}): Promise<({
2
+ category: string;
3
+ name: string;
4
+ status: string;
5
+ message: string;
6
+ hint: string;
7
+ } | {
8
+ category: string;
9
+ name: string;
10
+ status: string;
11
+ message: string;
12
+ hint?: undefined;
13
+ })[]>;
@@ -1,19 +1,14 @@
1
+ import {
2
+ probeKeychainState
3
+ } from "../chunk-C5I7KXHK.mjs";
4
+ import "../chunk-MTDFKNXX.mjs";
5
+ import "../chunk-E3GRJXXJ.mjs";
1
6
  import "../chunk-4UEJOM6W.mjs";
2
7
 
3
8
  // src/checks/vault.js
4
9
  import { existsSync } from "fs";
5
10
  import { join } from "path";
6
11
  var CATEGORY = "vault";
7
- async function tryKeychain() {
8
- try {
9
- const mod = await import("keytar");
10
- const keytar = mod.default ?? mod;
11
- const hex = await keytar.getPassword("perplexity-user-mcp", "vault-master-key");
12
- return { available: true, hasKey: !!hex };
13
- } catch {
14
- return { available: false, hasKey: false };
15
- }
16
- }
17
12
  function keychainExpected() {
18
13
  return process.platform === "win32" || process.platform === "darwin" || process.platform === "linux" && !process.env.CI;
19
14
  }
@@ -24,7 +19,7 @@ async function run(opts = {}) {
24
19
  const enc = join(dir, "profiles", profile, "vault.enc");
25
20
  const plain = join(dir, "profiles", profile, "vault.json");
26
21
  const envPass = process.env.PERPLEXITY_VAULT_PASSPHRASE;
27
- const kc = await tryKeychain();
22
+ const kc = await probeKeychainState();
28
23
  if (existsSync(plain)) {
29
24
  results.push({
30
25
  category: CATEGORY,
@@ -2,22 +2,22 @@ import {
2
2
  appendAuditEntry,
3
3
  getAuditLogPath,
4
4
  readAuditTail
5
- } from "./chunk-V4U3JM4R.mjs";
5
+ } from "./chunk-TSLRTZYR.mjs";
6
6
  import {
7
7
  ensureToken,
8
8
  getTokenPath,
9
9
  rotateToken
10
- } from "./chunk-TDXETAQT.mjs";
10
+ } from "./chunk-DKEJZ4FI.mjs";
11
11
  import {
12
12
  hydrateCloudHistoryEntry,
13
13
  syncCloudHistory
14
- } from "./chunk-2FPGJKCA.mjs";
14
+ } from "./chunk-2EE7MNP2.mjs";
15
15
  import {
16
16
  PerplexityClient,
17
17
  exportThreadViaImpit,
18
18
  readCachedAccountInfoFromDisk,
19
19
  retrieveThreadViaImpit
20
- } from "./chunk-C3HPFFTD.mjs";
20
+ } from "./chunk-WHVJ724K.mjs";
21
21
  import {
22
22
  append,
23
23
  findPendingByThread,
@@ -26,13 +26,13 @@ import {
26
26
  getHistoryDir,
27
27
  list,
28
28
  update
29
- } from "./chunk-B65IJQZJ.mjs";
29
+ } from "./chunk-6E6XTHTG.mjs";
30
30
  import {
31
31
  safeAtomicWriteFileSync
32
32
  } from "./chunk-MTDFKNXX.mjs";
33
33
  import {
34
34
  getConfigDir
35
- } from "./chunk-HJIXH6CL.mjs";
35
+ } from "./chunk-E3GRJXXJ.mjs";
36
36
 
37
37
  // src/daemon/server.ts
38
38
  import { createServer } from "http";
@@ -2,11 +2,11 @@ import {
2
2
  PerplexityClient,
3
3
  getCloudThreadViaImpit,
4
4
  listCloudThreadsViaImpit
5
- } from "./chunk-C3HPFFTD.mjs";
5
+ } from "./chunk-WHVJ724K.mjs";
6
6
  import {
7
7
  hydrateCloudEntry,
8
8
  upsertFromCloud
9
- } from "./chunk-B65IJQZJ.mjs";
9
+ } from "./chunk-6E6XTHTG.mjs";
10
10
 
11
11
  // src/cloud-sync.js
12
12
  var DEFAULT_PAGE_SIZE = 1e3;
@@ -1,10 +1,26 @@
1
1
  import {
2
2
  ensureDaemon
3
- } from "./chunk-RK4EBZJ3.mjs";
3
+ } from "./chunk-E75J42W5.mjs";
4
4
 
5
5
  // src/daemon/attach.ts
6
6
  import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
7
7
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
8
+ var DaemonAttachError = class extends Error {
9
+ code = "DAEMON_UNREACHABLE";
10
+ remediation;
11
+ cause;
12
+ constructor(message, remediation, cause) {
13
+ super(message);
14
+ this.name = "DaemonAttachError";
15
+ this.remediation = remediation;
16
+ if (cause !== void 0) this.cause = cause;
17
+ }
18
+ };
19
+ var DEFAULT_REMEDIATION = [
20
+ "Reload the VS Code window so the extension restarts the daemon.",
21
+ "In the VS Code Perplexity dashboard, switch this client's transport to http-loopback.",
22
+ "(Advanced) Set PERPLEXITY_NO_DAEMON=1 in this client's MCP env block, then run `npx perplexity-user-mcp setup-vault` once."
23
+ ];
8
24
  async function attachToDaemon(options = {}) {
9
25
  const ensure = options.dependencies?.ensureDaemon ?? ensureDaemon;
10
26
  const sourceIn = options.stdin ?? process.stdin;
@@ -20,7 +36,11 @@ async function attachToDaemon(options = {}) {
20
36
  await runFallback(error, options);
21
37
  return;
22
38
  }
23
- throw error;
39
+ throw new DaemonAttachError(
40
+ `Cannot reach the extension-managed daemon: ${asError(error).message}`,
41
+ DEFAULT_REMEDIATION,
42
+ error
43
+ );
24
44
  }
25
45
  const stdio = new StdioServerTransport(sourceIn, sourceOut);
26
46
  const http = new StreamableHTTPClientTransport(new URL(`${daemon.url}/mcp`), {
@@ -77,7 +97,11 @@ async function attachToDaemon(options = {}) {
77
97
  await runFallback(error, options);
78
98
  return;
79
99
  }
80
- throw error;
100
+ throw new DaemonAttachError(
101
+ `Daemon attached but transport failed to start: ${asError(error).message}`,
102
+ DEFAULT_REMEDIATION,
103
+ error
104
+ );
81
105
  }
82
106
  await completion;
83
107
  }
@@ -102,5 +126,6 @@ function asError(error) {
102
126
  }
103
127
 
104
128
  export {
129
+ DaemonAttachError,
105
130
  attachToDaemon
106
131
  };
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  getConfigDir,
3
3
  getProfilePaths
4
- } from "./chunk-HJIXH6CL.mjs";
4
+ } from "./chunk-E3GRJXXJ.mjs";
5
5
 
6
6
  // src/reinit-watcher.js
7
7
  import { existsSync, mkdirSync, watch } from "fs";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  getActiveName,
3
3
  getProfilePaths
4
- } from "./chunk-HJIXH6CL.mjs";
4
+ } from "./chunk-E3GRJXXJ.mjs";
5
5
 
6
6
  // src/history-store.js
7
7
  import { randomUUID } from "crypto";
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-MTDFKNXX.mjs";
4
4
  import {
5
5
  getProfilePaths
6
- } from "./chunk-HJIXH6CL.mjs";
6
+ } from "./chunk-E3GRJXXJ.mjs";
7
7
 
8
8
  // src/vault.js
9
9
  import { createCipheriv, createDecipheriv, randomBytes, hkdfSync, scrypt as nodeScrypt } from "crypto";
@@ -32,6 +32,7 @@ var V3_HEADER_FIXED_PREAMBLE = 4 + 1 + 1 + 1;
32
32
  var scryptAsync = promisify(nodeScrypt);
33
33
  var _kdfParamsOverride = null;
34
34
  var _kdfTestModeActive = false;
35
+ var _keytarModuleCache = null;
35
36
  function __setKdfParamsForTest(params) {
36
37
  if (!params || typeof params.logN !== "number" || typeof params.r !== "number" || typeof params.p !== "number") {
37
38
  throw new Error("__setKdfParamsForTest requires {logN, r, p} numbers.");
@@ -197,17 +198,30 @@ var KEYTAR_SERVICE = "perplexity-user-mcp";
197
198
  var KEYTAR_ACCOUNT = "vault-master-key";
198
199
  var _keyCache = null;
199
200
  var _unsealMaterialCache = null;
201
+ function isKeychainDisabled() {
202
+ return process.env.PERPLEXITY_DISABLE_KEYCHAIN === "1";
203
+ }
200
204
  function __resetKeyCache() {
201
205
  _keyCache = null;
202
206
  _unsealMaterialCache = null;
203
207
  _kdfParamsOverride = null;
204
208
  _kdfTestModeActive = false;
209
+ _keytarModuleCache = null;
205
210
  }
206
211
  async function tryKeytar() {
212
+ if (isKeychainDisabled()) return null;
213
+ if (_keytarModuleCache !== null) return _keytarModuleCache;
207
214
  try {
208
215
  const mod = await import("keytar");
209
- return mod.default ?? mod;
216
+ const keytar = mod.default ?? mod;
217
+ if (!keytar || typeof keytar.getPassword !== "function") {
218
+ _keytarModuleCache = false;
219
+ return null;
220
+ }
221
+ _keytarModuleCache = keytar;
222
+ return keytar;
210
223
  } catch {
224
+ _keytarModuleCache = false;
211
225
  return null;
212
226
  }
213
227
  }
@@ -228,6 +242,21 @@ async function keyFromKeychain() {
228
242
  return null;
229
243
  }
230
244
  }
245
+ async function probeKeychainState() {
246
+ if (isKeychainDisabled()) {
247
+ return { available: false, hasKey: false };
248
+ }
249
+ const keytar = await tryKeytar();
250
+ if (!keytar || typeof keytar.getPassword !== "function") {
251
+ return { available: false, hasKey: false };
252
+ }
253
+ try {
254
+ const hex = await keytar.getPassword(KEYTAR_SERVICE, KEYTAR_ACCOUNT);
255
+ return { available: true, hasKey: !!hex };
256
+ } catch {
257
+ return { available: true, hasKey: false };
258
+ }
259
+ }
231
260
  function isStdioServerMode() {
232
261
  return process.env.PERPLEXITY_MCP_STDIO === "1" || process.stdin && process.stdin.isTTY === false;
233
262
  }
@@ -383,6 +412,7 @@ export {
383
412
  encryptBlob,
384
413
  decryptBlob,
385
414
  __resetKeyCache,
415
+ probeKeychainState,
386
416
  getUnsealMaterial,
387
417
  getAllUnsealMaterials,
388
418
  getMasterKey,
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-MTDFKNXX.mjs";
4
4
  import {
5
5
  getConfigDir
6
- } from "./chunk-HJIXH6CL.mjs";
6
+ } from "./chunk-E3GRJXXJ.mjs";
7
7
 
8
8
  // src/daemon/token.ts
9
9
  import { randomBytes } from "crypto";
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  Vault
3
- } from "./chunk-S677V2JU.mjs";
3
+ } from "./chunk-C5I7KXHK.mjs";
4
4
  import {
5
5
  getActiveName,
6
6
  getProfilePaths
7
- } from "./chunk-HJIXH6CL.mjs";
7
+ } from "./chunk-E3GRJXXJ.mjs";
8
8
 
9
9
  // src/config.ts
10
10
  import { existsSync } from "fs";
@@ -192,16 +192,35 @@ async function getSavedCookies() {
192
192
  }
193
193
  return cookies;
194
194
  }
195
- const raw = await _vault.get(activeName(), "cookies").catch((err) => {
195
+ const profile = activeName();
196
+ let unsealFailed = false;
197
+ const raw = await _vault.get(profile, "cookies").catch((err) => {
198
+ unsealFailed = true;
196
199
  const msg = err instanceof Error ? err.message : String(err);
197
- console.error(`[vault] getSavedCookies failed for profile ${activeName()}: ${msg}`);
200
+ console.error(`[vault] getSavedCookies failed for profile '${profile}': ${msg}`);
198
201
  return null;
199
202
  });
200
- if (!raw) return [];
203
+ if (!raw) {
204
+ if (!unsealFailed) {
205
+ const paths = getProfilePaths(profile);
206
+ if (!existsSync(paths.vault)) {
207
+ console.error(`[vault] getSavedCookies: no vault.enc for profile '${profile}' \u2014 run login first`);
208
+ } else {
209
+ console.error(`[vault] getSavedCookies: vault.enc exists for profile '${profile}' but 'cookies' key is absent`);
210
+ }
211
+ }
212
+ return [];
213
+ }
201
214
  try {
202
215
  const parsed = JSON.parse(raw);
203
- return Array.isArray(parsed) ? parsed : [];
204
- } catch {
216
+ if (!Array.isArray(parsed)) {
217
+ console.error(`[vault] getSavedCookies: 'cookies' value for profile '${profile}' is not an array (${typeof parsed})`);
218
+ return [];
219
+ }
220
+ return parsed;
221
+ } catch (err) {
222
+ const msg = err instanceof Error ? err.message : String(err);
223
+ console.error(`[vault] getSavedCookies: JSON parse failed for profile '${profile}': ${msg}`);
205
224
  return [];
206
225
  }
207
226
  }
@@ -17,7 +17,9 @@ function getProfilePaths(name) {
17
17
  vault: join(dir, "vault.enc"),
18
18
  vaultPlain: join(dir, "vault.json"),
19
19
  browserData: join(dir, "browser-data"),
20
+ loginBrowserData: join(dir, "login-browser-data"),
20
21
  modelsCache: join(dir, "models-cache.json"),
22
+ daemonStatus: join(dir, "daemon-status.json"),
21
23
  history: join(dir, "history"),
22
24
  attachments: join(dir, "attachments"),
23
25
  researches: join(dir, "researches"),
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  getTunnelProvider,
3
3
  readTunnelSettings
4
- } from "./chunk-XTRJSV72.mjs";
4
+ } from "./chunk-LGH5BSUY.mjs";
5
5
  import {
6
6
  acquire,
7
7
  getLockfilePath,
@@ -9,27 +9,27 @@ import {
9
9
  read,
10
10
  release,
11
11
  replace
12
- } from "./chunk-KJFX2ZXR.mjs";
12
+ } from "./chunk-NMKNEEZB.mjs";
13
13
  import {
14
14
  getPackageVersion,
15
15
  startDaemonServer
16
- } from "./chunk-T6ARJK2P.mjs";
16
+ } from "./chunk-2B5OQUXR.mjs";
17
17
  import {
18
18
  ensureToken,
19
19
  getTokenPath,
20
20
  readToken
21
- } from "./chunk-TDXETAQT.mjs";
21
+ } from "./chunk-DKEJZ4FI.mjs";
22
22
  import {
23
23
  watchActiveProfile,
24
24
  watchReinit
25
- } from "./chunk-WDIW33DA.mjs";
25
+ } from "./chunk-3LUO5ATM.mjs";
26
26
  import {
27
27
  PerplexityClient
28
- } from "./chunk-C3HPFFTD.mjs";
28
+ } from "./chunk-WHVJ724K.mjs";
29
29
  import {
30
30
  getActiveName,
31
31
  getConfigDir
32
- } from "./chunk-HJIXH6CL.mjs";
32
+ } from "./chunk-E3GRJXXJ.mjs";
33
33
 
34
34
  // src/daemon/launcher.ts
35
35
  import { spawn } from "child_process";
@@ -671,11 +671,14 @@ async function spawnDetachedDaemon(options) {
671
671
  if (options.tunnel) {
672
672
  args.push("--tunnel");
673
673
  }
674
+ const env = { ...process.env };
675
+ delete env.PERPLEXITY_HEADLESS_ONLY;
676
+ delete env.PERPLEXITY_NO_DAEMON;
674
677
  const child = spawn(process.execPath, args, {
675
678
  detached: true,
676
679
  stdio: "ignore",
677
680
  env: {
678
- ...process.env,
681
+ ...env,
679
682
  PERPLEXITY_CONFIG_DIR: options.configDir
680
683
  }
681
684
  });
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  ensureDaemon
3
- } from "./chunk-RK4EBZJ3.mjs";
3
+ } from "./chunk-E75J42W5.mjs";
4
4
  import {
5
5
  getPackageVersion
6
- } from "./chunk-T6ARJK2P.mjs";
6
+ } from "./chunk-2B5OQUXR.mjs";
7
7
 
8
8
  // src/daemon/client-http.ts
9
9
  import { randomUUID } from "crypto";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  PERPLEXITY_URL
3
- } from "./chunk-U7QPUNRH.mjs";
3
+ } from "./chunk-DXR6EEZH.mjs";
4
4
 
5
5
  // src/export.js
6
6
  import { Buffer } from "buffer";
@@ -0,0 +1,17 @@
1
+ // src/is-main-module.js
2
+ import { realpathSync } from "fs";
3
+ import { fileURLToPath, pathToFileURL } from "url";
4
+ function isMainModule(metaUrl) {
5
+ if (!process.argv[1]) return false;
6
+ try {
7
+ const moduleReal = realpathSync(fileURLToPath(metaUrl));
8
+ const argvReal = realpathSync(process.argv[1]);
9
+ return moduleReal === argvReal;
10
+ } catch {
11
+ return metaUrl === pathToFileURL(process.argv[1]).href;
12
+ }
13
+ }
14
+
15
+ export {
16
+ isMainModule
17
+ };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getConfigDir
3
- } from "./chunk-HJIXH6CL.mjs";
3
+ } from "./chunk-E3GRJXXJ.mjs";
4
4
  import {
5
5
  __glob
6
6
  } from "./chunk-4UEJOM6W.mjs";
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-6YMQVLFX.mjs";
4
4
  import {
5
5
  getTunnelBinaryPath
6
- } from "./chunk-FKQ3HP4Q.mjs";
6
+ } from "./chunk-TIWHN4IW.mjs";
7
7
  import {
8
8
  safeAtomicWriteFileSync
9
9
  } from "./chunk-MTDFKNXX.mjs";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getConfigDir
3
- } from "./chunk-HJIXH6CL.mjs";
3
+ } from "./chunk-E3GRJXXJ.mjs";
4
4
 
5
5
  // src/daemon/lockfile.ts
6
6
  import { closeSync, existsSync, mkdirSync, openSync, readFileSync, renameSync, rmSync, writeFileSync } from "fs";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getConfigDir
3
- } from "./chunk-HJIXH6CL.mjs";
3
+ } from "./chunk-E3GRJXXJ.mjs";
4
4
 
5
5
  // src/daemon/install-tunnel.ts
6
6
  import { createHash } from "crypto";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getConfigDir
3
- } from "./chunk-HJIXH6CL.mjs";
3
+ } from "./chunk-E3GRJXXJ.mjs";
4
4
 
5
5
  // src/daemon/audit.ts
6
6
  import { appendFileSync, existsSync, mkdirSync, readFileSync, renameSync, rmSync, statSync } from "fs";
@@ -9,12 +9,12 @@ import {
9
9
  getOrCreateContext,
10
10
  getSavedCookies,
11
11
  resolveBrowserExecutable
12
- } from "./chunk-U7QPUNRH.mjs";
12
+ } from "./chunk-DXR6EEZH.mjs";
13
13
  import {
14
14
  getActiveName,
15
15
  getConfigDir,
16
16
  getProfilePaths
17
- } from "./chunk-HJIXH6CL.mjs";
17
+ } from "./chunk-E3GRJXXJ.mjs";
18
18
 
19
19
  // src/refresh.ts
20
20
  import { readFileSync, writeFileSync, existsSync, statSync, mkdirSync } from "fs";