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.
- package/README.md +5 -0
- package/dist/attachments.d.ts +10 -20
- package/dist/browser-window.d.ts +1 -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 +20 -92
- 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-T6ARJK2P.mjs → chunk-2B5OQUXR.mjs} +6 -6
- package/dist/{chunk-2FPGJKCA.mjs → chunk-2EE7MNP2.mjs} +2 -2
- package/dist/{chunk-NJX4RBO6.mjs → chunk-2OVLCZHU.mjs} +28 -3
- package/dist/{chunk-WDIW33DA.mjs → chunk-3LUO5ATM.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-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-RK4EBZJ3.mjs → chunk-E75J42W5.mjs} +11 -8
- package/dist/{chunk-452DK6OS.mjs → chunk-FNHYUE22.mjs} +2 -2
- package/dist/{chunk-D254EFYB.mjs → chunk-GBI2U336.mjs} +1 -1
- package/dist/chunk-GPUGKWXH.mjs +17 -0
- package/dist/{chunk-HNSPNCFH.mjs → chunk-KSNV3ZVY.mjs} +1 -1
- package/dist/{chunk-XTRJSV72.mjs → chunk-LGH5BSUY.mjs} +1 -1
- package/dist/{chunk-KJFX2ZXR.mjs → chunk-NMKNEEZB.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-C3HPFFTD.mjs → chunk-WHVJ724K.mjs} +84 -44
- package/dist/cli.d.ts +14 -1298
- package/dist/cli.mjs +35 -27
- package/dist/client.d.ts +27 -24
- package/dist/client.mjs +6 -6
- package/dist/cloud-sync.d.ts +65 -42
- package/dist/cloud-sync.mjs +8 -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 +10 -11
- package/dist/daemon/attach.mjs +19 -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 +17 -17
- package/dist/daemon/index.d.ts +17 -14
- package/dist/daemon/index.mjs +18 -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 +16 -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 +11 -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 +8 -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 +22 -20
- package/dist/is-main-module.d.ts +9 -0
- package/dist/login-runner.d.ts +1 -333
- package/dist/login-runner.mjs +13 -13
- 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 +3 -3
- 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
|
@@ -1,469 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { Vault } from './vault.d-BSJWDLhp.js';
|
|
3
|
-
import { recordLoginSuccess, getActiveName, getProfilePaths } from './profiles.d-DqS1oZWr.js';
|
|
4
|
-
import { redact } from './redact.js';
|
|
5
|
-
import { b as buildRuntimeEndpoints } from './session-metadata-B9aV_n5g.js';
|
|
6
|
-
import { PlaywrightCookie } from './config.js';
|
|
7
|
-
import { isImpitAvailable, loadImpit } from './refresh.js';
|
|
8
|
-
import 'patchright';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Minimal RFC 6265-style cookie jar for the impit-driven login flow.
|
|
12
|
-
*
|
|
13
|
-
* Identity = `(name, domain, path)` triple — same triple replaces. Domain
|
|
14
|
-
* matching honours leading-dot semantics; path matching is prefix-based with
|
|
15
|
-
* default-path derived from the request URL. Honours `Expires`, `Max-Age`
|
|
16
|
-
* (Max-Age wins), `Secure`, and `HttpOnly` (round-tripped, not enforced).
|
|
17
|
-
*
|
|
18
|
-
* Round-trips cleanly to/from the `PlaywrightCookie` shape used by
|
|
19
|
-
* `getSavedCookies()` and the vault, so the impit login output can replace
|
|
20
|
-
* Patchright's cookie array drop-in.
|
|
21
|
-
*/
|
|
22
|
-
declare class CookieJar {
|
|
23
|
-
constructor(initialCookies?: PlaywrightCookie[]);
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Apply one or more `Set-Cookie` headers from a response. Accepts either a
|
|
27
|
-
* single string (joined header) or an array of values, e.g. from
|
|
28
|
-
* `res.headers.getSetCookie?.()`. Cookies whose Max-Age is `<= 0` or whose
|
|
29
|
-
* Expires is in the past are *deleted* from the jar (server-driven delete);
|
|
30
|
-
* cookies that merely become stale via wall-clock drift remain in the jar
|
|
31
|
-
* but are filtered out of `buildCookieHeader`.
|
|
32
|
-
*/
|
|
33
|
-
consumeSetCookieHeader(header: string | string[] | null | undefined, requestUrl: string): void;
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Build a `Cookie:` header value for `requestUrl`. Returns `""` when no
|
|
37
|
-
* cookies match (so callers can `if (h) headers.cookie = h`). Filters out
|
|
38
|
-
* cookies whose Secure flag is set when the request URL is `http://`, and
|
|
39
|
-
* cookies whose Expires/Max-Age is in the past. Sorted by path length
|
|
40
|
-
* descending, per RFC 6265 §5.4.
|
|
41
|
-
*/
|
|
42
|
-
buildCookieHeader(requestUrl: string): string;
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Snapshot of every cookie in the jar (including expired ones — callers
|
|
46
|
-
* that persist to disk want the full set so a later refresh can simply
|
|
47
|
-
* overwrite).
|
|
48
|
-
*/
|
|
49
|
-
toPlaywrightShape(): PlaywrightCookie[];
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Explicit setter, mostly for tests and for callers that already have a
|
|
53
|
-
* fully-formed cookie record (e.g. seeding `cf_clearance` from the vault).
|
|
54
|
-
*/
|
|
55
|
-
set(
|
|
56
|
-
name: string,
|
|
57
|
-
value: string,
|
|
58
|
-
attributes?: Partial<PlaywrightCookie> & { hostOnly?: boolean },
|
|
59
|
-
): void;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
interface WarmCloudflareOptions {
|
|
63
|
-
/** Hard cap on the initial page.goto. Default 15_000ms. */
|
|
64
|
-
navigationTimeoutMs?: number;
|
|
65
|
-
/** How often to recheck context cookies for `cf_clearance`. Default 250ms. */
|
|
66
|
-
pollIntervalMs?: number;
|
|
67
|
-
/** Total wall-clock budget for the cookie poll loop after navigation. Default 10_000ms. */
|
|
68
|
-
cookieWaitMs?: number;
|
|
69
|
-
}
|
|
70
|
-
interface WarmCloudflareResult {
|
|
71
|
-
/**
|
|
72
|
-
* True iff the browser launched and navigation succeeded. May be true even
|
|
73
|
-
* when `hasCfClearance` is false — distinguishes "browser unusable" from
|
|
74
|
-
* "browser fine, CF just didn't issue clearance this time".
|
|
75
|
-
*/
|
|
76
|
-
ok: boolean;
|
|
77
|
-
/** All cookies present in the ephemeral context at teardown. Empty on launch failure. */
|
|
78
|
-
cookies: PlaywrightCookie[];
|
|
79
|
-
/** Whether `cf_clearance` was observed in `cookies`. */
|
|
80
|
-
hasCfClearance: boolean;
|
|
81
|
-
/** Wall-clock duration of the warmup attempt, in milliseconds. */
|
|
82
|
-
elapsedMs: number;
|
|
83
|
-
/** Populated when `ok=false`. Single-line, human-readable. */
|
|
84
|
-
error?: string;
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* Brief headless launch to capture cf_clearance for the impit-login flow.
|
|
88
|
-
*
|
|
89
|
-
* Always returns a result object — never throws. Caller falls back to the
|
|
90
|
-
* full browser-based login when ok=false or hasCfClearance=false.
|
|
91
|
-
*/
|
|
92
|
-
declare function warmCloudflare(opts?: WarmCloudflareOptions): Promise<WarmCloudflareResult>;
|
|
93
|
-
|
|
94
|
-
// Impit-driven Auto-OTP login runner. Same emit/IPC protocol as
|
|
95
|
-
// `login-runner.js` but drives the 6-step Perplexity email+OTP flow
|
|
96
|
-
// (csrf → sso check → signin/email → wait OTP → otp-redirect → callback)
|
|
97
|
-
// through impit (Rust HTTP client) instead of through a Patchright
|
|
98
|
-
// browser. The visible browser window is replaced with a brief headless
|
|
99
|
-
// CF warmup (only when the vault has no fresh `cf_clearance` cookie).
|
|
100
|
-
//
|
|
101
|
-
// Plan: docs/impit-coverage-plan.md §3 (Phase 1).
|
|
102
|
-
//
|
|
103
|
-
// Inputs (env):
|
|
104
|
-
// PERPLEXITY_EMAIL — required
|
|
105
|
-
// PERPLEXITY_PROFILE — profile name to write cookies to
|
|
106
|
-
// PERPLEXITY_OTP_TIMEOUT_MS — default 300_000
|
|
107
|
-
// PERPLEXITY_LOGIN_MAX_RETRIES — default 2
|
|
108
|
-
//
|
|
109
|
-
// Outputs:
|
|
110
|
-
// process.send({ phase: "awaiting_otp", attempt: N }) — IPC, parent prompts user
|
|
111
|
-
// process.stdin gets { otp: "123456" } — IPC, parent sends back
|
|
112
|
-
// process.stdout: JSON line `{ ok, ... }` final result
|
|
113
|
-
// exit codes: 0 success, 2 logical fail, 4 chrome/impit missing, 5 crash
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
const ORIGIN = process.env.PERPLEXITY_ORIGIN || "https://www.perplexity.ai";
|
|
117
|
-
const EMAIL = process.env.PERPLEXITY_EMAIL;
|
|
118
|
-
const OTP_TIMEOUT_MS = Number(process.env.PERPLEXITY_OTP_TIMEOUT_MS ?? 300_000);
|
|
119
|
-
const MAX_RETRIES = Number(process.env.PERPLEXITY_LOGIN_MAX_RETRIES ?? 2);
|
|
120
|
-
const USER_AGENT =
|
|
121
|
-
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36";
|
|
122
|
-
const CHROME_CLIENT_HINTS = {
|
|
123
|
-
"sec-ch-ua": '"Not)A;Brand";v="8", "Chromium";v="138", "Google Chrome";v="138"',
|
|
124
|
-
"sec-ch-ua-mobile": "?0",
|
|
125
|
-
"sec-ch-ua-platform": '"Windows"',
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
function resolveProfile() {
|
|
129
|
-
return process.env.PERPLEXITY_PROFILE || getActiveName() || "default";
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
function ipc(msg) { if (process.send) process.send(msg); }
|
|
133
|
-
function emit(obj) { process.stdout.write(JSON.stringify(obj) + "\n"); }
|
|
134
|
-
|
|
135
|
-
async function awaitOtp() {
|
|
136
|
-
return new Promise((resolve, reject) => {
|
|
137
|
-
const timer = setTimeout(() => {
|
|
138
|
-
process.removeListener("message", handler);
|
|
139
|
-
reject(new Error("otp_timeout"));
|
|
140
|
-
}, OTP_TIMEOUT_MS);
|
|
141
|
-
const handler = (m) => {
|
|
142
|
-
if (m && typeof m.otp === "string") {
|
|
143
|
-
clearTimeout(timer);
|
|
144
|
-
process.removeListener("message", handler);
|
|
145
|
-
resolve(m.otp);
|
|
146
|
-
}
|
|
147
|
-
};
|
|
148
|
-
process.on("message", handler);
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Wrap an impit instance in a small fetch helper that round-trips the
|
|
154
|
-
* cookie jar. Returns { status, headers, json, text }.
|
|
155
|
-
*/
|
|
156
|
-
async function impitJsonRequest(client, jar, url, init = {}) {
|
|
157
|
-
const cookieHeader = jar.buildCookieHeader(url);
|
|
158
|
-
const headers = {
|
|
159
|
-
"user-agent": USER_AGENT,
|
|
160
|
-
accept: "application/json, text/plain, */*",
|
|
161
|
-
"accept-language": "en-US,en;q=0.9",
|
|
162
|
-
...CHROME_CLIENT_HINTS,
|
|
163
|
-
...(cookieHeader ? { cookie: cookieHeader } : {}),
|
|
164
|
-
...(init.body !== undefined ? { "content-type": "application/json" } : {}),
|
|
165
|
-
referer: `${ORIGIN}/`,
|
|
166
|
-
origin: ORIGIN,
|
|
167
|
-
...(init.headers ?? {}),
|
|
168
|
-
};
|
|
169
|
-
const ctrl = new AbortController();
|
|
170
|
-
const to = setTimeout(() => ctrl.abort(), init.timeoutMs ?? 30_000);
|
|
171
|
-
try {
|
|
172
|
-
const res = await client.fetch(url, {
|
|
173
|
-
method: init.method ?? "GET",
|
|
174
|
-
headers,
|
|
175
|
-
body: init.body !== undefined ? JSON.stringify(init.body) : undefined,
|
|
176
|
-
signal: ctrl.signal,
|
|
177
|
-
redirect: init.redirect ?? "manual",
|
|
178
|
-
});
|
|
179
|
-
const text = await res.text();
|
|
180
|
-
// Capture Set-Cookie before reading body — Node Headers carries them.
|
|
181
|
-
const setCookies = readSetCookies(res.headers);
|
|
182
|
-
if (setCookies.length) jar.consumeSetCookieHeader(setCookies, url);
|
|
183
|
-
let json;
|
|
184
|
-
if (text) {
|
|
185
|
-
try { json = JSON.parse(text); } catch { /* leave undefined */ }
|
|
186
|
-
}
|
|
187
|
-
return { status: res.status, headers: res.headers, text, json };
|
|
188
|
-
} finally {
|
|
189
|
-
clearTimeout(to);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
function readSetCookies(headers) {
|
|
194
|
-
if (!headers) return [];
|
|
195
|
-
// Node 20+ standard
|
|
196
|
-
if (typeof headers.getSetCookie === "function") {
|
|
197
|
-
return headers.getSetCookie();
|
|
198
|
-
}
|
|
199
|
-
// Headers#raw() (undici)
|
|
200
|
-
if (typeof headers.raw === "function") {
|
|
201
|
-
const raw = headers.raw();
|
|
202
|
-
return raw["set-cookie"] ?? [];
|
|
203
|
-
}
|
|
204
|
-
// Plain object fallback
|
|
205
|
-
const lower = Object.keys(headers).find((k) => k.toLowerCase() === "set-cookie");
|
|
206
|
-
if (!lower) return [];
|
|
207
|
-
const v = headers[lower];
|
|
208
|
-
return Array.isArray(v) ? v : [v];
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
/**
|
|
212
|
-
* Follow redirects manually so we can capture Set-Cookie at every hop —
|
|
213
|
-
* the OTP callback chain depends on cookies set in 302 responses, which
|
|
214
|
-
* `redirect: "follow"` would swallow.
|
|
215
|
-
*/
|
|
216
|
-
async function followRedirectsManually(client, jar, startUrl, init = {}, maxHops = 10) {
|
|
217
|
-
let url = startUrl;
|
|
218
|
-
let lastStatus = 0;
|
|
219
|
-
for (let hop = 0; hop < maxHops; hop++) {
|
|
220
|
-
const result = await impitJsonRequest(client, jar, url, { ...init, redirect: "manual", method: hop === 0 ? init.method ?? "GET" : "GET" });
|
|
221
|
-
lastStatus = result.status;
|
|
222
|
-
if (result.status >= 300 && result.status < 400) {
|
|
223
|
-
const loc = readHeader(result.headers, "location");
|
|
224
|
-
if (!loc) return { ok: false, status: result.status, finalUrl: url };
|
|
225
|
-
url = new URL(loc, url).toString();
|
|
226
|
-
// Subsequent hops must not re-send the body
|
|
227
|
-
init.body = undefined;
|
|
228
|
-
continue;
|
|
229
|
-
}
|
|
230
|
-
return { ok: result.status >= 200 && result.status < 300, status: result.status, finalUrl: url, json: result.json, text: result.text };
|
|
231
|
-
}
|
|
232
|
-
return { ok: false, status: lastStatus, finalUrl: url, error: "max_redirects" };
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
function readHeader(headers, name) {
|
|
236
|
-
if (!headers) return null;
|
|
237
|
-
if (typeof headers.get === "function") return headers.get(name);
|
|
238
|
-
const key = Object.keys(headers).find((k) => k.toLowerCase() === name.toLowerCase());
|
|
239
|
-
return key ? headers[key] : null;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
/**
|
|
243
|
-
* Steps 1-3 of the auth flow: csrf → sso check → email signin.
|
|
244
|
-
* Returns either { kind: "live", redirectUrl } on success, or a structured
|
|
245
|
-
* failure that the caller maps to an exit reason.
|
|
246
|
-
*/
|
|
247
|
-
async function startEmailFlow(client, jar) {
|
|
248
|
-
const endpoints = buildRuntimeEndpoints(ORIGIN);
|
|
249
|
-
|
|
250
|
-
const csrf = await impitJsonRequest(client, jar, endpoints.csrf);
|
|
251
|
-
if (csrf.status !== 200 || !csrf.json?.csrfToken) {
|
|
252
|
-
return { kind: "unsupported", detail: { step: "csrf", status: csrf.status } };
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
const sso = await impitJsonRequest(client, jar, endpoints.ssoDetails, {
|
|
256
|
-
method: "POST",
|
|
257
|
-
body: { email: EMAIL },
|
|
258
|
-
});
|
|
259
|
-
if (sso.status === 200 && sso.json?.organization) {
|
|
260
|
-
return { kind: "sso_required" };
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
const redirectUrl = `${ORIGIN}/account?login-source=settings`;
|
|
264
|
-
const signIn = await impitJsonRequest(client, jar, endpoints.signInEmail, {
|
|
265
|
-
method: "POST",
|
|
266
|
-
body: {
|
|
267
|
-
email: EMAIL,
|
|
268
|
-
useNumericOtp: "true",
|
|
269
|
-
csrfToken: csrf.json.csrfToken,
|
|
270
|
-
callbackUrl: `${redirectUrl}#locale=en-US`,
|
|
271
|
-
json: "true",
|
|
272
|
-
},
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
if (signIn.status !== 200 || !signIn.json?.url) {
|
|
276
|
-
return {
|
|
277
|
-
kind: signIn.status >= 400 && signIn.status < 500 ? "email_rejected" : "unsupported",
|
|
278
|
-
detail: { step: "signin_email", status: signIn.status },
|
|
279
|
-
};
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
return { kind: "live", redirectUrl, csrfToken: csrf.json.csrfToken };
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
async function submitOtp(client, jar, flow, otp) {
|
|
286
|
-
const endpoints = buildRuntimeEndpoints(ORIGIN);
|
|
287
|
-
const redirectResp = await impitJsonRequest(client, jar, endpoints.otpRedirectLink, {
|
|
288
|
-
method: "POST",
|
|
289
|
-
body: {
|
|
290
|
-
email: EMAIL,
|
|
291
|
-
otp,
|
|
292
|
-
redirectUrl: flow.redirectUrl,
|
|
293
|
-
emailLoginMethod: "web-otp",
|
|
294
|
-
loginSource: null,
|
|
295
|
-
},
|
|
296
|
-
});
|
|
297
|
-
if (redirectResp.status !== 200 || !redirectResp.json?.redirect) {
|
|
298
|
-
return { ok: false };
|
|
299
|
-
}
|
|
300
|
-
// Follow the callback redirect chain manually to capture session cookies.
|
|
301
|
-
const callbackUrl = new URL(redirectResp.json.redirect, ORIGIN).toString();
|
|
302
|
-
const callback = await followRedirectsManually(client, jar, callbackUrl, { method: "GET" });
|
|
303
|
-
if (!callback.ok) return { ok: false };
|
|
304
|
-
// After the chain, the jar should have __Secure-next-auth.session-token.
|
|
305
|
-
const cookies = jar.toPlaywrightShape();
|
|
306
|
-
const hasSession = cookies.some((c) => c.name === "__Secure-next-auth.session-token");
|
|
307
|
-
if (!hasSession) return { ok: false };
|
|
308
|
-
return { ok: true, cookies };
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
/**
|
|
312
|
-
* Probe an authenticated endpoint to fetch session/user metadata after a
|
|
313
|
-
* successful OTP. We don't have a page to evaluate in, so this is a small
|
|
314
|
-
* direct fetch — reusing the same jar.
|
|
315
|
-
*/
|
|
316
|
-
async function fetchSessionInfo(client, jar) {
|
|
317
|
-
const session = await impitJsonRequest(client, jar, `${ORIGIN}/api/auth/session?version=2.18&source=default`);
|
|
318
|
-
return session.json ?? {};
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
async function fetchModelsCache(client, jar) {
|
|
322
|
-
// Mirrors what `refresh.ts` writes — but via this jar. Best-effort.
|
|
323
|
-
const result = {};
|
|
324
|
-
for (const [key, path] of [
|
|
325
|
-
["models", "/rest/configs/models?version=2.18&source=default"],
|
|
326
|
-
["asi", "/rest/configs/asi-access?version=2.18&source=default"],
|
|
327
|
-
["rateLimits", "/rest/rate-limits?version=2.18&source=default"],
|
|
328
|
-
["experiments", "/rest/experiments?version=2.18&source=default"],
|
|
329
|
-
["userInfo", "/rest/user/info?version=2.18&source=default"],
|
|
330
|
-
]) {
|
|
331
|
-
try {
|
|
332
|
-
const r = await impitJsonRequest(client, jar, `${ORIGIN}${path}`);
|
|
333
|
-
if (r.status === 200 && r.json) result[key] = r.json;
|
|
334
|
-
} catch { /* ignore — partial cache is fine */ }
|
|
335
|
-
}
|
|
336
|
-
return result;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
function deriveTier(modelsCache) {
|
|
340
|
-
if (modelsCache.userInfo?.subscription_tier === "enterprise") return "Enterprise";
|
|
341
|
-
if (modelsCache.userInfo?.subscription_tier === "max") return "Max";
|
|
342
|
-
if (modelsCache.userInfo?.subscription_tier === "pro") return "Pro";
|
|
343
|
-
if (modelsCache.experiments?.server_is_enterprise) return "Enterprise";
|
|
344
|
-
if (modelsCache.experiments?.server_is_max) return "Max";
|
|
345
|
-
if (modelsCache.experiments?.server_is_pro) return "Pro";
|
|
346
|
-
if (modelsCache.asi?.can_use_computer) return "Pro";
|
|
347
|
-
return "Authenticated";
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
async function main() {
|
|
351
|
-
if (!EMAIL) {
|
|
352
|
-
emit({ ok: false, reason: "no_email" });
|
|
353
|
-
process.exit(1);
|
|
354
|
-
}
|
|
355
|
-
if (!isImpitAvailable()) {
|
|
356
|
-
emit({ ok: false, reason: "impit_missing", error: "Speed Boost (impit) not installed" });
|
|
357
|
-
process.exit(4);
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
const PROFILE = resolveProfile();
|
|
361
|
-
|
|
362
|
-
// 1. Seed jar from existing vault cookies (if any). Brand-new logins
|
|
363
|
-
// get an empty jar; subsequent re-logins inherit cf_clearance etc.
|
|
364
|
-
const vault = new Vault();
|
|
365
|
-
const jar = new CookieJar([]);
|
|
366
|
-
try {
|
|
367
|
-
const stored = await vault.get(PROFILE, "cookies").catch(() => null);
|
|
368
|
-
if (stored) {
|
|
369
|
-
const parsed = JSON.parse(stored);
|
|
370
|
-
if (Array.isArray(parsed)) {
|
|
371
|
-
for (const c of parsed) jar.set?.(c.name, c.value, { domain: c.domain, path: c.path, expires: c.expires, secure: c.secure, httpOnly: c.httpOnly, sameSite: c.sameSite });
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
} catch { /* ignore — seed is best-effort */ }
|
|
375
|
-
|
|
376
|
-
// 2. CF warmup if jar has no cf_clearance. ~1-2s headless launch.
|
|
377
|
-
if (!jar.toPlaywrightShape().some((c) => c.name === "cf_clearance")) {
|
|
378
|
-
const warmup = await warmCloudflare();
|
|
379
|
-
if (warmup.cookies.length) {
|
|
380
|
-
for (const c of warmup.cookies) {
|
|
381
|
-
jar.set?.(c.name, c.value, { domain: c.domain, path: c.path, expires: c.expires, secure: c.secure, httpOnly: c.httpOnly, sameSite: c.sameSite });
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
if (!warmup.hasCfClearance) {
|
|
385
|
-
// No cf_clearance after warmup → CF is challenging this IP. Bail to
|
|
386
|
-
// browser fallback which has the headed CF solver.
|
|
387
|
-
emit({ ok: false, reason: "cf_blocked", detail: { warmupOk: warmup.ok } });
|
|
388
|
-
process.exit(3);
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
// 3. Load impit and run the email→OTP→callback flow.
|
|
393
|
-
const impitMod = await loadImpit();
|
|
394
|
-
if (!impitMod) {
|
|
395
|
-
emit({ ok: false, reason: "impit_load_failed" });
|
|
396
|
-
process.exit(4);
|
|
397
|
-
}
|
|
398
|
-
const client = new impitMod.Impit({ browser: "chrome", ignoreTlsErrors: false });
|
|
399
|
-
|
|
400
|
-
let authFlow;
|
|
401
|
-
try {
|
|
402
|
-
authFlow = await startEmailFlow(client, jar);
|
|
403
|
-
} catch (err) {
|
|
404
|
-
emit({ ok: false, reason: "auto_unsupported", detail: { step: "start", error: redact(String(err?.message ?? err)) } });
|
|
405
|
-
process.exit(2);
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
if (authFlow.kind === "sso_required") {
|
|
409
|
-
emit({ ok: false, reason: "sso_required" });
|
|
410
|
-
process.exit(2);
|
|
411
|
-
}
|
|
412
|
-
if (authFlow.kind === "email_rejected") {
|
|
413
|
-
emit({ ok: false, reason: "email_rejected", detail: authFlow.detail });
|
|
414
|
-
process.exit(2);
|
|
415
|
-
}
|
|
416
|
-
if (authFlow.kind !== "live") {
|
|
417
|
-
emit({ ok: false, reason: "auto_unsupported", detail: authFlow.detail });
|
|
418
|
-
process.exit(2);
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
// 4. OTP loop with retry.
|
|
422
|
-
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
423
|
-
ipc({ phase: "awaiting_otp", attempt });
|
|
424
|
-
let otp;
|
|
425
|
-
try {
|
|
426
|
-
otp = await awaitOtp();
|
|
427
|
-
} catch {
|
|
428
|
-
emit({ ok: false, reason: "otp_timeout" });
|
|
429
|
-
process.exit(2);
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
const submitResp = await submitOtp(client, jar, authFlow, otp);
|
|
433
|
-
if (submitResp.ok) {
|
|
434
|
-
// 5. Persist cookies + session metadata.
|
|
435
|
-
const sessionInfo = await fetchSessionInfo(client, jar).catch(() => ({}));
|
|
436
|
-
const modelsCache = await fetchModelsCache(client, jar).catch(() => ({}));
|
|
437
|
-
const tier = deriveTier(modelsCache);
|
|
438
|
-
|
|
439
|
-
await vault.set(PROFILE, "cookies", JSON.stringify(submitResp.cookies));
|
|
440
|
-
if (sessionInfo?.user?.email) await vault.set(PROFILE, "email", sessionInfo.user.email);
|
|
441
|
-
if (sessionInfo?.user?.id) await vault.set(PROFILE, "userId", sessionInfo.user.id);
|
|
442
|
-
|
|
443
|
-
const paths = getProfilePaths(PROFILE);
|
|
444
|
-
if (!existsSync(paths.dir)) mkdirSync(paths.dir, { recursive: true });
|
|
445
|
-
writeFileSync(paths.modelsCache, JSON.stringify(modelsCache, null, 2));
|
|
446
|
-
recordLoginSuccess(PROFILE, { tier, loginMode: "auto", lastLogin: new Date().toISOString() });
|
|
447
|
-
writeFileSync(paths.reinit, String(Date.now()));
|
|
448
|
-
|
|
449
|
-
emit({ ok: true, tier, modelCount: Object.keys(modelsCache?.models?.models ?? {}).length, transport: "impit" });
|
|
450
|
-
process.exit(0);
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
if (attempt === MAX_RETRIES) {
|
|
454
|
-
emit({ ok: false, reason: "otp_rejected" });
|
|
455
|
-
process.exit(2);
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
main().catch((err) => {
|
|
461
|
-
const msg = err?.message ?? err;
|
|
462
|
-
emit({
|
|
463
|
-
ok: false,
|
|
464
|
-
reason: "crash",
|
|
465
|
-
error: redact(String(msg ?? "unknown error")),
|
|
466
|
-
...(err?.stack ? { stack: redact(String(err.stack)) } : {}),
|
|
467
|
-
});
|
|
468
|
-
process.exit(5);
|
|
469
|
-
});
|
|
1
|
+
export {};
|
|
@@ -7,22 +7,22 @@ import {
|
|
|
7
7
|
import {
|
|
8
8
|
isImpitAvailable,
|
|
9
9
|
loadImpit
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-V4LHDNWJ.mjs";
|
|
11
11
|
import {
|
|
12
12
|
PERPLEXITY_URL,
|
|
13
13
|
findBrowser,
|
|
14
14
|
getOrCreateContext,
|
|
15
15
|
resolveBrowserExecutable
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-DXR6EEZH.mjs";
|
|
17
17
|
import {
|
|
18
18
|
Vault
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-C5I7KXHK.mjs";
|
|
20
20
|
import "./chunk-MTDFKNXX.mjs";
|
|
21
21
|
import {
|
|
22
22
|
getActiveName,
|
|
23
23
|
getProfilePaths,
|
|
24
24
|
recordLoginSuccess
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-E3GRJXXJ.mjs";
|
|
26
26
|
import "./chunk-4UEJOM6W.mjs";
|
|
27
27
|
|
|
28
28
|
// src/impit-login-runner.js
|
package/dist/index.d.ts
CHANGED
|
@@ -1,147 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
export { ensureDaemon, startDaemon } from './daemon/launcher.js';
|
|
4
|
-
export { attachToDaemon } from './daemon/attach.js';
|
|
5
|
-
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
6
|
-
import { SearchResult } from './config.js';
|
|
7
|
-
export { BrowserInfo, findBrowser } from './config.js';
|
|
8
|
-
export { append as appendHistory, countAll as countAllHistory, deleteEntry, findByBackendUuid, findPendingByThread, get, getAttachmentsDir, getAttachmentsRoot, getHistoryDir, getIndexPath as getHistoryPath, getMdPath, hydrateCloudEntry, pin, list as readHistory, rebuildIndex, tag, update, upsertFromCloud } from './history-store.d-BzjBF2m3.js';
|
|
9
|
-
export { hydrateCloudHistoryEntry, syncCloudHistory } from './cloud-sync.d-Cqt6y18U.js';
|
|
10
|
-
export { HistoryItem } from '@perplexity-user-mcp/shared';
|
|
11
|
-
export { RefreshOptions, RefreshResult, RefreshTier, getImpitRuntimeDir, getModelsCacheInfo, isImpitAvailable, refreshAccountInfo } from './refresh.js';
|
|
12
|
-
import { DoctorReport, DoctorCategory } from './doctor.d-CXmUqOXX.js';
|
|
13
|
-
export { CATEGORIES as DOCTOR_CATEGORIES, formatReportMarkdown, runAll as runDoctor } from './doctor.d-CXmUqOXX.js';
|
|
14
|
-
import 'patchright';
|
|
15
|
-
import './daemon/lockfile.js';
|
|
16
|
-
import 'node:stream';
|
|
17
|
-
|
|
18
|
-
type GetClient = () => Promise<PerplexityClient>;
|
|
19
|
-
interface ToolAuditEvent {
|
|
20
|
-
tool: string;
|
|
21
|
-
clientId: string;
|
|
22
|
-
source: "loopback" | "tunnel";
|
|
23
|
-
durationMs: number;
|
|
24
|
-
ok: boolean;
|
|
25
|
-
error?: string;
|
|
26
|
-
}
|
|
27
|
-
interface ToolProgressEvent {
|
|
28
|
-
tool: string;
|
|
29
|
-
clientId: string;
|
|
30
|
-
source: "loopback" | "tunnel";
|
|
31
|
-
progress: Record<string, unknown>;
|
|
32
|
-
}
|
|
33
|
-
interface ToolHooks {
|
|
34
|
-
onToolSettled?: (event: ToolAuditEvent) => void;
|
|
35
|
-
onToolProgress?: (event: ToolProgressEvent) => void;
|
|
36
|
-
}
|
|
37
|
-
declare function registerTools(server: McpServer, getClient: GetClient, enabledTools?: Set<string>, hooks?: ToolHooks): void;
|
|
38
|
-
|
|
39
|
-
declare function registerPrompts(server: McpServer): void;
|
|
40
|
-
|
|
41
|
-
interface AccountSnapshotProvider {
|
|
42
|
-
(): Record<string, unknown>;
|
|
43
|
-
}
|
|
44
|
-
declare function registerResources(server: McpServer, getAccountSnapshot?: AccountSnapshotProvider): void;
|
|
45
|
-
|
|
46
|
-
interface HistoryEntry {
|
|
47
|
-
tool: string;
|
|
48
|
-
query: string;
|
|
49
|
-
model: string | null;
|
|
50
|
-
mode: string | null;
|
|
51
|
-
language: string | null;
|
|
52
|
-
answerPreview: string;
|
|
53
|
-
sourceCount: number;
|
|
54
|
-
threadUrl?: string;
|
|
55
|
-
error?: string;
|
|
56
|
-
}
|
|
57
|
-
declare function formatResponse(result: SearchResult): string;
|
|
58
|
-
declare function buildAnswerPreview(result: SearchResult | null, error?: string): string;
|
|
59
|
-
declare function buildHistoryEntry(options: {
|
|
60
|
-
tool: string;
|
|
61
|
-
query: string;
|
|
62
|
-
model: string | null;
|
|
63
|
-
mode: string | null;
|
|
64
|
-
language: string | null;
|
|
65
|
-
result?: SearchResult;
|
|
66
|
-
error?: string;
|
|
67
|
-
}): HistoryEntry;
|
|
68
|
-
declare function buildHistoryBody(result: SearchResult | undefined, error?: string): string;
|
|
69
|
-
declare function buildStoredHistoryEntry(options: {
|
|
70
|
-
tool: string;
|
|
71
|
-
query: string;
|
|
72
|
-
model: string | null;
|
|
73
|
-
mode: string | null;
|
|
74
|
-
language: string | null;
|
|
75
|
-
tier?: "Max" | "Pro" | "Enterprise" | "Authenticated" | "Anonymous";
|
|
76
|
-
status?: "completed" | "pending" | "failed";
|
|
77
|
-
createdAt?: string;
|
|
78
|
-
completedAt?: string;
|
|
79
|
-
result?: SearchResult;
|
|
80
|
-
error?: string;
|
|
81
|
-
}): HistoryEntry & {
|
|
82
|
-
createdAt: string;
|
|
83
|
-
body: string;
|
|
84
|
-
status?: "completed" | "pending" | "failed";
|
|
85
|
-
completedAt?: string;
|
|
86
|
-
tier?: "Max" | "Pro" | "Enterprise" | "Authenticated" | "Anonymous";
|
|
87
|
-
threadSlug?: string | null;
|
|
88
|
-
backendUuid?: string | null;
|
|
89
|
-
readWriteToken?: string | null;
|
|
90
|
-
sources?: Array<{
|
|
91
|
-
n: number;
|
|
92
|
-
title: string;
|
|
93
|
-
url: string;
|
|
94
|
-
snippet?: string;
|
|
95
|
-
}>;
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
type ExportFormat = "pdf" | "markdown" | "docx";
|
|
99
|
-
|
|
100
|
-
interface ExportResult {
|
|
101
|
-
buffer: Buffer;
|
|
102
|
-
filename: string;
|
|
103
|
-
contentType: string;
|
|
104
|
-
}
|
|
105
|
-
declare function exportThread(options: {
|
|
106
|
-
entryUuid: string;
|
|
107
|
-
format: ExportFormat;
|
|
108
|
-
fetchImpl?: (input: string, init?: RequestInit) => Promise<Response>;
|
|
109
|
-
baseUrl?: string;
|
|
110
|
-
headers?: HeadersInit;
|
|
111
|
-
}): Promise<ExportResult>;
|
|
112
|
-
|
|
113
|
-
type ToolProfile = "read-only" | "full" | "custom";
|
|
114
|
-
interface ToolConfig {
|
|
115
|
-
profile: ToolProfile;
|
|
116
|
-
customEnabled?: string[];
|
|
117
|
-
}
|
|
118
|
-
declare function loadToolConfig(): ToolConfig;
|
|
119
|
-
declare function getEnabledTools(config: ToolConfig): Set<string>;
|
|
120
|
-
declare function saveToolConfig(config: ToolConfig): void;
|
|
121
|
-
declare function watchToolConfig(onChange: (config: ToolConfig) => void): void;
|
|
122
|
-
|
|
123
|
-
declare function buildIssueBody(input: {
|
|
124
|
-
report: DoctorReport;
|
|
125
|
-
stderrTail: string;
|
|
126
|
-
extVersion: string;
|
|
127
|
-
nodeVersion: string;
|
|
128
|
-
os: string;
|
|
129
|
-
activeTier?: string | null;
|
|
130
|
-
}): string;
|
|
131
|
-
|
|
132
|
-
declare function redactIssueBody(md: string): string;
|
|
133
|
-
|
|
134
|
-
declare function decideTransport(input: { bodyBytes: number }): "inline" | "file";
|
|
135
|
-
|
|
136
|
-
declare function buildIssueUrl(input: {
|
|
137
|
-
owner: string;
|
|
138
|
-
repo: string;
|
|
139
|
-
category: DoctorCategory | string;
|
|
140
|
-
check: string;
|
|
141
|
-
body: string;
|
|
142
|
-
}): string;
|
|
143
|
-
|
|
144
|
-
declare function __resetVaultPreflightForTests(): void;
|
|
2
|
+
export declare function __resetVaultPreflightForTests(): void;
|
|
145
3
|
/**
|
|
146
4
|
* Probe the vault unseal chain at startup. If unsealing succeeds, the result
|
|
147
5
|
* is cached inside `vault.js` for free — subsequent tool calls skip the
|
|
@@ -153,11 +11,29 @@ declare function __resetVaultPreflightForTests(): void;
|
|
|
153
11
|
* Never throws. The MCP server must continue to load and serve tools that
|
|
154
12
|
* don't need cookies (perplexity_doctor, anonymous perplexity_search).
|
|
155
13
|
*/
|
|
156
|
-
declare function runVaultPreflight(stderr?: NodeJS.WritableStream): Promise<void>;
|
|
157
|
-
declare function waitForStdioInputClose(stdin?: NodeJS.ReadableStream): Promise<void>;
|
|
158
|
-
declare function shutdownClientWithTimeout(c: {
|
|
14
|
+
export declare function runVaultPreflight(stderr?: NodeJS.WritableStream): Promise<void>;
|
|
15
|
+
export declare function waitForStdioInputClose(stdin?: NodeJS.ReadableStream): Promise<void>;
|
|
16
|
+
export declare function shutdownClientWithTimeout(c: {
|
|
159
17
|
shutdown: () => Promise<void>;
|
|
160
18
|
} | undefined, timeoutMs?: number): Promise<void>;
|
|
161
|
-
declare function main(): Promise<void>;
|
|
162
|
-
|
|
163
|
-
export {
|
|
19
|
+
export declare function main(): Promise<void>;
|
|
20
|
+
export { PerplexityClient } from "./client.js";
|
|
21
|
+
export { ensureDaemon, startDaemon } from "./daemon/launcher.js";
|
|
22
|
+
export { attachToDaemon } from "./daemon/attach.js";
|
|
23
|
+
export { registerTools } from "./tools.js";
|
|
24
|
+
export { registerPrompts } from "./prompts.js";
|
|
25
|
+
export { registerResources } from "./resources.js";
|
|
26
|
+
export { formatResponse, buildHistoryBody, buildHistoryEntry, buildStoredHistoryEntry, buildAnswerPreview } from "./format.js";
|
|
27
|
+
export { append as appendHistory, countAll as countAllHistory, deleteEntry, findPendingByThread, get, getAttachmentsDir, getAttachmentsRoot, getHistoryDir, getIndexPath as getHistoryPath, getMdPath, list as readHistory, pin, rebuildIndex, tag, update, findByBackendUuid, upsertFromCloud, hydrateCloudEntry, } from "./history-store.js";
|
|
28
|
+
export { syncCloudHistory, hydrateCloudHistoryEntry } from "./cloud-sync.js";
|
|
29
|
+
export { exportThread } from "./export.js";
|
|
30
|
+
export type { HistoryEntry } from "./format.js";
|
|
31
|
+
export type { HistoryItem } from "@perplexity-user-mcp/shared";
|
|
32
|
+
export { loadToolConfig, getEnabledTools, saveToolConfig, watchToolConfig } from "./tool-config.js";
|
|
33
|
+
export type { ToolProfile } from "./tool-config.js";
|
|
34
|
+
export { findBrowser } from "./config.js";
|
|
35
|
+
export type { BrowserInfo } from "./config.js";
|
|
36
|
+
export { refreshAccountInfo, getModelsCacheInfo, isImpitAvailable, getImpitRuntimeDir } from "./refresh.js";
|
|
37
|
+
export type { RefreshResult, RefreshTier, RefreshOptions } from "./refresh.js";
|
|
38
|
+
export { runAll as runDoctor, formatReportMarkdown, CATEGORIES as DOCTOR_CATEGORIES } from "./doctor.js";
|
|
39
|
+
export { buildIssueBody, redactIssueBody, buildIssueUrl, decideTransport } from "./doctor-report.js";
|