perplexity-user-mcp 0.8.42 → 0.8.47
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/dist/attachments.d.ts +10 -20
- package/dist/browser-window.d.ts +11 -0
- package/dist/cf-warmup.d.ts +32 -0
- package/dist/checks/browser.d.ts +12 -100
- package/dist/checks/config.d.ts +25 -91
- package/dist/checks/ide.d.ts +31 -89
- package/dist/checks/mcp.d.ts +12 -61
- package/dist/checks/native-deps.d.ts +46 -131
- package/dist/checks/network.d.ts +13 -71
- package/dist/checks/probe.d.ts +37 -92
- package/dist/checks/probe.mjs +29 -0
- package/dist/checks/profiles.d.ts +13 -99
- package/dist/checks/profiles.mjs +35 -0
- package/dist/checks/runtime.d.ts +24 -89
- package/dist/checks/vault.d.ts +13 -142
- package/dist/checks/vault.mjs +6 -11
- package/dist/{chunk-WDIW33DA.mjs → chunk-3LUO5ATM.mjs} +1 -1
- package/dist/{chunk-HNSPNCFH.mjs → chunk-6CAXNBDD.mjs} +1 -1
- package/dist/{chunk-B65IJQZJ.mjs → chunk-6E6XTHTG.mjs} +1 -1
- package/dist/{chunk-S677V2JU.mjs → chunk-C5I7KXHK.mjs} +32 -2
- package/dist/{chunk-RK4EBZJ3.mjs → chunk-D2ZQGKHM.mjs} +11 -8
- package/dist/{chunk-TDXETAQT.mjs → chunk-DKEJZ4FI.mjs} +1 -1
- package/dist/{chunk-U7QPUNRH.mjs → chunk-DXR6EEZH.mjs} +26 -7
- package/dist/{chunk-HJIXH6CL.mjs → chunk-E3GRJXXJ.mjs} +2 -0
- package/dist/{chunk-C3HPFFTD.mjs → chunk-GBHPJ7I7.mjs} +136 -48
- package/dist/{chunk-D254EFYB.mjs → chunk-GBI2U336.mjs} +1 -1
- package/dist/chunk-GPUGKWXH.mjs +17 -0
- package/dist/chunk-KVV3JBSN.mjs +32 -0
- package/dist/{chunk-XTRJSV72.mjs → chunk-LGH5BSUY.mjs} +1 -1
- package/dist/{chunk-KJFX2ZXR.mjs → chunk-NMKNEEZB.mjs} +1 -1
- package/dist/{chunk-T6ARJK2P.mjs → chunk-P6YOLJ5T.mjs} +6 -6
- package/dist/{chunk-452DK6OS.mjs → chunk-QXYMYCHC.mjs} +2 -2
- package/dist/{chunk-Z4OLYVB2.mjs → chunk-SCZQCV7M.mjs} +1 -1
- package/dist/{chunk-FKQ3HP4Q.mjs → chunk-TIWHN4IW.mjs} +1 -1
- package/dist/{chunk-V4U3JM4R.mjs → chunk-TSLRTZYR.mjs} +1 -1
- package/dist/{chunk-DQQISMYN.mjs → chunk-V4LHDNWJ.mjs} +2 -2
- package/dist/{chunk-2FPGJKCA.mjs → chunk-YD25G5AD.mjs} +2 -2
- package/dist/cli.d.ts +14 -1317
- package/dist/cli.mjs +14 -21
- package/dist/client.d.ts +39 -24
- package/dist/client.mjs +9 -6
- package/dist/cloud-sync.d.ts +65 -42
- package/dist/cloud-sync.mjs +9 -8
- package/dist/config.d.ts +35 -39
- package/dist/config.mjs +3 -3
- package/dist/cookie-jar.d.ts +77 -0
- package/dist/daemon/attach.d.ts +5 -12
- package/dist/daemon/attach.mjs +18 -17
- package/dist/daemon/audit.d.ts +5 -7
- package/dist/daemon/audit.mjs +2 -2
- package/dist/daemon/client-http.d.ts +10 -16
- package/dist/daemon/client-http.mjs +18 -17
- package/dist/daemon/index.d.ts +17 -14
- package/dist/daemon/index.mjs +19 -18
- package/dist/daemon/install-tunnel.d.ts +8 -34
- package/dist/daemon/install-tunnel.mjs +2 -2
- package/dist/daemon/launcher.d.ts +24 -29
- package/dist/daemon/launcher.mjs +17 -16
- package/dist/daemon/local-tokens.d.ts +23 -0
- package/dist/daemon/lockfile.d.ts +10 -12
- package/dist/daemon/lockfile.mjs +2 -2
- package/dist/daemon/oauth-consent-cache.d.ts +86 -0
- package/dist/daemon/oauth-provider.d.ts +132 -0
- package/dist/daemon/public-pages.d.ts +9 -0
- package/dist/daemon/security.d.ts +52 -0
- package/dist/daemon/server.d.ts +12 -83
- package/dist/daemon/server.mjs +12 -11
- package/dist/daemon/token.d.ts +7 -9
- package/dist/daemon/token.mjs +2 -2
- package/dist/daemon/tunnel-providers/cloudflared-named-setup.d.ts +140 -0
- package/dist/daemon/tunnel-providers/cloudflared-named.d.ts +45 -0
- package/dist/daemon/tunnel-providers/cloudflared-quick.d.ts +8 -0
- package/dist/daemon/tunnel-providers/index.d.ts +16 -327
- package/dist/daemon/tunnel-providers/index.mjs +3 -3
- package/dist/daemon/tunnel-providers/ngrok-config.d.ts +18 -0
- package/dist/daemon/tunnel-providers/ngrok.d.ts +68 -0
- package/dist/daemon/tunnel-providers/types.d.ts +56 -0
- package/dist/daemon/tunnel.d.ts +5 -7
- package/dist/debug-tracer.d.ts +2 -0
- package/dist/doctor-report.d.ts +17 -22
- package/dist/doctor.d.ts +12 -44
- package/dist/doctor.mjs +2 -2
- package/dist/export.d.ts +11 -18
- package/dist/export.mjs +4 -4
- package/dist/format.d.ts +52 -0
- package/dist/fs-utils.d.ts +44 -0
- package/dist/health-check.d.ts +1 -108
- package/dist/health-check.mjs +3 -3
- package/dist/history-store.d.ts +29 -65
- package/dist/history-store.mjs +2 -2
- package/dist/impit-login-runner.d.ts +1 -469
- package/dist/impit-login-runner.mjs +4 -4
- package/dist/index.d.ts +25 -149
- package/dist/index.mjs +23 -20
- package/dist/is-main-module.d.ts +9 -0
- package/dist/login-runner.d.ts +1 -333
- package/dist/login-runner.mjs +18 -38
- package/dist/login.d.ts +5 -0
- package/dist/logout.d.ts +2 -28
- package/dist/logout.mjs +3 -2
- package/dist/manual-login-runner.d.ts +1 -150
- package/dist/manual-login-runner.mjs +11 -11
- package/dist/{native-deps-IE4B55EL.mjs → native-deps-FCSYDL4W.mjs} +4 -4
- package/dist/native-deps.d.ts +36 -0
- package/dist/package-version.d.ts +1 -0
- package/dist/profiles.d.ts +41 -41
- package/dist/profiles.mjs +1 -1
- package/dist/prompts.d.ts +2 -0
- package/dist/redact.d.ts +14 -142
- package/dist/refresh.d.ts +11 -16
- package/dist/refresh.mjs +4 -4
- package/dist/reinit-watcher.d.ts +15 -24
- package/dist/reinit-watcher.mjs +2 -2
- package/dist/resources.d.ts +5 -0
- package/dist/safe-write.d.ts +16 -0
- package/dist/session-metadata.d.ts +45 -0
- package/dist/tool-config.d.ts +10 -0
- package/dist/tools.d.ts +23 -0
- package/dist/tty-prompt.d.ts +18 -34
- package/dist/vault.d.ts +114 -34
- package/dist/vault.mjs +6 -4
- package/dist/viewer-detect.d.ts +2 -4
- package/dist/viewers.d.ts +13 -18
- package/dist/viewers.mjs +1 -1
- package/package.json +2 -2
- package/dist/cloud-sync.d-Cqt6y18U.d.ts +0 -42
- package/dist/doctor.d-CXmUqOXX.d.ts +0 -43
- package/dist/history-store.d-BzjBF2m3.d.ts +0 -65
- package/dist/native-deps-BNThFHxa.d.ts +0 -175
- package/dist/profiles.d-DqS1oZWr.d.ts +0 -41
- package/dist/session-metadata-B9aV_n5g.d.ts +0 -148
- package/dist/vault.d-BSJWDLhp.d.ts +0 -37
- package/dist/viewer-detect.d-HWGnyFAA.d.ts +0 -4
- package/dist/viewers.d-BGCK6sw6.d.ts +0 -10
package/dist/checks/runtime.d.ts
CHANGED
|
@@ -1,89 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
if (baseDir) {
|
|
26
|
-
candidates.push(join(baseDir, "mcp", "package.json"));
|
|
27
|
-
candidates.push(join(baseDir, "package.json"));
|
|
28
|
-
}
|
|
29
|
-
const metaUrl = import.meta.url ?? null;
|
|
30
|
-
if (metaUrl) {
|
|
31
|
-
try {
|
|
32
|
-
candidates.push(fileURLToPath(new URL("../../package.json", metaUrl)));
|
|
33
|
-
} catch {}
|
|
34
|
-
try {
|
|
35
|
-
candidates.push(fileURLToPath(new URL("../package.json", metaUrl)));
|
|
36
|
-
} catch {}
|
|
37
|
-
}
|
|
38
|
-
return candidates;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
async function run(opts = {}) {
|
|
42
|
-
const results = [];
|
|
43
|
-
const nodeVersion = opts.nodeVersionOverride ?? process.version;
|
|
44
|
-
const major = parseMajor(nodeVersion);
|
|
45
|
-
results.push({
|
|
46
|
-
category: CATEGORY,
|
|
47
|
-
name: "node-version",
|
|
48
|
-
status: major >= 20 ? "pass" : "fail",
|
|
49
|
-
message: `Node.js ${nodeVersion}`,
|
|
50
|
-
hint: major >= 20 ? undefined : "Upgrade to Node 20 or later (https://nodejs.org).",
|
|
51
|
-
});
|
|
52
|
-
results.push({ category: CATEGORY, name: "platform", status: "pass", message: `${process.platform} ${process.arch}` });
|
|
53
|
-
results.push({ category: CATEGORY, name: "arch", status: "pass", message: process.arch });
|
|
54
|
-
|
|
55
|
-
let version = "0.0.0";
|
|
56
|
-
for (const pkgPath of getPackageJsonCandidates(opts.baseDir)) {
|
|
57
|
-
try {
|
|
58
|
-
const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
|
|
59
|
-
if (pkg.name === "perplexity-user-mcp" && pkg.version) {
|
|
60
|
-
version = pkg.version;
|
|
61
|
-
break;
|
|
62
|
-
}
|
|
63
|
-
} catch {}
|
|
64
|
-
}
|
|
65
|
-
results.push({
|
|
66
|
-
category: CATEGORY,
|
|
67
|
-
name: "package-version",
|
|
68
|
-
status: "pass",
|
|
69
|
-
message: `perplexity-user-mcp ${version}`,
|
|
70
|
-
detail: { version },
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
const gitDir = opts.gitDirOverride ?? join(process.cwd(), ".git");
|
|
74
|
-
const resolver = opts.gitShaResolverOverride ?? defaultGitShaResolver;
|
|
75
|
-
if (!existsSync(gitDir)) {
|
|
76
|
-
results.push({ category: CATEGORY, name: "git-sha", status: "skip", message: "not a git checkout" });
|
|
77
|
-
} else {
|
|
78
|
-
const sha = await resolver(process.cwd());
|
|
79
|
-
if (sha) {
|
|
80
|
-
results.push({ category: CATEGORY, name: "git-sha", status: "pass", message: sha });
|
|
81
|
-
} else {
|
|
82
|
-
results.push({ category: CATEGORY, name: "git-sha", status: "skip", message: "git not on PATH" });
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
return results;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
export { run };
|
|
1
|
+
export function run(opts?: {}): Promise<({
|
|
2
|
+
category: string;
|
|
3
|
+
name: string;
|
|
4
|
+
status: string;
|
|
5
|
+
message: string;
|
|
6
|
+
hint: string | undefined;
|
|
7
|
+
detail?: undefined;
|
|
8
|
+
} | {
|
|
9
|
+
category: string;
|
|
10
|
+
name: string;
|
|
11
|
+
status: string;
|
|
12
|
+
message: string;
|
|
13
|
+
detail: {
|
|
14
|
+
version: string;
|
|
15
|
+
};
|
|
16
|
+
hint?: undefined;
|
|
17
|
+
} | {
|
|
18
|
+
category: string;
|
|
19
|
+
name: string;
|
|
20
|
+
status: string;
|
|
21
|
+
message: any;
|
|
22
|
+
hint?: undefined;
|
|
23
|
+
detail?: undefined;
|
|
24
|
+
})[]>;
|
package/dist/checks/vault.d.ts
CHANGED
|
@@ -1,142 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
+
})[]>;
|
package/dist/checks/vault.mjs
CHANGED
|
@@ -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
|
|
22
|
+
const kc = await probeKeychainState();
|
|
28
23
|
if (existsSync(plain)) {
|
|
29
24
|
results.push({
|
|
30
25
|
category: CATEGORY,
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
} from "./chunk-MTDFKNXX.mjs";
|
|
4
4
|
import {
|
|
5
5
|
getProfilePaths
|
|
6
|
-
} from "./chunk-
|
|
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
|
-
|
|
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,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getTunnelProvider,
|
|
3
3
|
readTunnelSettings
|
|
4
|
-
} from "./chunk-
|
|
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-
|
|
12
|
+
} from "./chunk-NMKNEEZB.mjs";
|
|
13
13
|
import {
|
|
14
14
|
getPackageVersion,
|
|
15
15
|
startDaemonServer
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-P6YOLJ5T.mjs";
|
|
17
17
|
import {
|
|
18
18
|
ensureToken,
|
|
19
19
|
getTokenPath,
|
|
20
20
|
readToken
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-DKEJZ4FI.mjs";
|
|
22
22
|
import {
|
|
23
23
|
watchActiveProfile,
|
|
24
24
|
watchReinit
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-3LUO5ATM.mjs";
|
|
26
26
|
import {
|
|
27
27
|
PerplexityClient
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-GBHPJ7I7.mjs";
|
|
29
29
|
import {
|
|
30
30
|
getActiveName,
|
|
31
31
|
getConfigDir
|
|
32
|
-
} from "./chunk-
|
|
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
|
-
...
|
|
681
|
+
...env,
|
|
679
682
|
PERPLEXITY_CONFIG_DIR: options.configDir
|
|
680
683
|
}
|
|
681
684
|
});
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Vault
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-C5I7KXHK.mjs";
|
|
4
4
|
import {
|
|
5
5
|
getActiveName,
|
|
6
6
|
getProfilePaths
|
|
7
|
-
} from "./chunk-
|
|
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
|
|
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 ${
|
|
200
|
+
console.error(`[vault] getSavedCookies failed for profile '${profile}': ${msg}`);
|
|
198
201
|
return null;
|
|
199
202
|
});
|
|
200
|
-
if (!raw)
|
|
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
|
-
|
|
204
|
-
|
|
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"),
|