perplexity-user-mcp 0.8.36
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 +192 -0
- package/dist/attachments.d.ts +20 -0
- package/dist/attachments.mjs +43 -0
- package/dist/checks/browser.d.ts +100 -0
- package/dist/checks/browser.mjs +89 -0
- package/dist/checks/config.d.ts +91 -0
- package/dist/checks/config.mjs +88 -0
- package/dist/checks/ide.d.ts +89 -0
- package/dist/checks/ide.mjs +80 -0
- package/dist/checks/mcp.d.ts +61 -0
- package/dist/checks/mcp.mjs +56 -0
- package/dist/checks/native-deps.d.ts +131 -0
- package/dist/checks/native-deps.mjs +115 -0
- package/dist/checks/network.d.ts +71 -0
- package/dist/checks/network.mjs +70 -0
- package/dist/checks/probe.d.ts +93 -0
- package/dist/checks/probe.mjs +82 -0
- package/dist/checks/profiles.d.ts +99 -0
- package/dist/checks/profiles.mjs +90 -0
- package/dist/checks/runtime.d.ts +89 -0
- package/dist/checks/runtime.mjs +90 -0
- package/dist/checks/vault.d.ts +101 -0
- package/dist/checks/vault.mjs +90 -0
- package/dist/chunk-3B276PGG.mjs +115 -0
- package/dist/chunk-4UEJOM6W.mjs +9 -0
- package/dist/chunk-6EP2BLTV.mjs +205 -0
- package/dist/chunk-6YMQVLFX.mjs +146 -0
- package/dist/chunk-7JL36EBH.mjs +118 -0
- package/dist/chunk-DPGMKSSA.mjs +57 -0
- package/dist/chunk-H4BUAPPO.mjs +1950 -0
- package/dist/chunk-HMKLWVXB.mjs +109 -0
- package/dist/chunk-HTUAQRKH.mjs +125 -0
- package/dist/chunk-HU5B4FXS.mjs +139 -0
- package/dist/chunk-KCXM2M4B.mjs +1006 -0
- package/dist/chunk-LKJMLGFP.mjs +237 -0
- package/dist/chunk-LZPLNZ5U.mjs +67 -0
- package/dist/chunk-MTDFKNXX.mjs +19 -0
- package/dist/chunk-OF4DMAPJ.mjs +511 -0
- package/dist/chunk-PE23RMXY.mjs +43 -0
- package/dist/chunk-Q2VY4R5F.mjs +175 -0
- package/dist/chunk-S5VD7WTU.mjs +2540 -0
- package/dist/chunk-SVPRB62V.mjs +106 -0
- package/dist/chunk-TQLCLE4L.mjs +345 -0
- package/dist/chunk-U3DGFLXZ.mjs +43 -0
- package/dist/chunk-X45O6YD3.mjs +688 -0
- package/dist/chunk-XKSWCEGI.mjs +168 -0
- package/dist/chunk-Z7DAACGZ.mjs +534 -0
- package/dist/chunk-ZQFUZPLO.mjs +257 -0
- package/dist/cli.d.ts +952 -0
- package/dist/cli.mjs +827 -0
- package/dist/client.d.ts +355 -0
- package/dist/client.mjs +27 -0
- package/dist/cloud-sync.d-Cqt6y18U.d.ts +42 -0
- package/dist/cloud-sync.d.ts +42 -0
- package/dist/cloud-sync.mjs +17 -0
- package/dist/config.d.ts +186 -0
- package/dist/config.mjs +54 -0
- package/dist/daemon/attach.d.ts +36 -0
- package/dist/daemon/attach.mjs +25 -0
- package/dist/daemon/audit.d.ts +23 -0
- package/dist/daemon/audit.mjs +12 -0
- package/dist/daemon/client-http.d.ts +42 -0
- package/dist/daemon/client-http.mjs +29 -0
- package/dist/daemon/index.d.ts +14 -0
- package/dist/daemon/index.mjs +110 -0
- package/dist/daemon/install-tunnel.d.ts +46 -0
- package/dist/daemon/install-tunnel.mjs +14 -0
- package/dist/daemon/launcher.d.ts +163 -0
- package/dist/daemon/launcher.mjs +50 -0
- package/dist/daemon/lockfile.d.ts +29 -0
- package/dist/daemon/lockfile.mjs +18 -0
- package/dist/daemon/server.d.ts +159 -0
- package/dist/daemon/server.mjs +20 -0
- package/dist/daemon/token.d.ts +17 -0
- package/dist/daemon/token.mjs +17 -0
- package/dist/daemon/tunnel-providers/index.d.ts +330 -0
- package/dist/daemon/tunnel-providers/index.mjs +57 -0
- package/dist/daemon/tunnel.d.ts +23 -0
- package/dist/daemon/tunnel.mjs +9 -0
- package/dist/doctor-report.d.ts +24 -0
- package/dist/doctor-report.mjs +14 -0
- package/dist/doctor.d-CXmUqOXX.d.ts +43 -0
- package/dist/doctor.d.ts +44 -0
- package/dist/doctor.mjs +16 -0
- package/dist/export.d.ts +19 -0
- package/dist/export.mjs +15 -0
- package/dist/health-check.d.ts +108 -0
- package/dist/health-check.mjs +92 -0
- package/dist/history-store.d-BzjBF2m3.d.ts +65 -0
- package/dist/history-store.d.ts +65 -0
- package/dist/history-store.mjs +48 -0
- package/dist/impit-login-runner.d.ts +469 -0
- package/dist/impit-login-runner.mjs +685 -0
- package/dist/index.d.ts +159 -0
- package/dist/index.mjs +236 -0
- package/dist/login-runner.d.ts +333 -0
- package/dist/login-runner.mjs +320 -0
- package/dist/logout.d.ts +28 -0
- package/dist/logout.mjs +45 -0
- package/dist/manual-login-runner.d.ts +150 -0
- package/dist/manual-login-runner.mjs +146 -0
- package/dist/native-deps-BNThFHxa.d.ts +175 -0
- package/dist/native-deps-YNKXITRY.mjs +139 -0
- package/dist/profiles.d-DqS1oZWr.d.ts +41 -0
- package/dist/profiles.d.ts +41 -0
- package/dist/profiles.mjs +33 -0
- package/dist/redact.d.ts +159 -0
- package/dist/redact.mjs +11 -0
- package/dist/refresh.d.ts +118 -0
- package/dist/refresh.mjs +21 -0
- package/dist/reinit-watcher.d.ts +15 -0
- package/dist/reinit-watcher.mjs +8 -0
- package/dist/session-metadata-B9aV_n5g.d.ts +148 -0
- package/dist/tty-prompt.d.ts +44 -0
- package/dist/tty-prompt.mjs +39 -0
- package/dist/vault.d-BtRSLZiM.d.ts +8 -0
- package/dist/vault.d.ts +37 -0
- package/dist/vault.mjs +21 -0
- package/dist/viewer-detect.d-HWGnyFAA.d.ts +4 -0
- package/dist/viewer-detect.d.ts +4 -0
- package/dist/viewer-detect.mjs +37 -0
- package/dist/viewers.d-BGCK6sw6.d.ts +10 -0
- package/dist/viewers.d.ts +18 -0
- package/dist/viewers.mjs +122 -0
- package/package.json +152 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
const CATEGORY = "ide";
|
|
2
|
+
|
|
3
|
+
async function run(opts = {}) {
|
|
4
|
+
const results = [];
|
|
5
|
+
const statuses = opts.ideStatuses;
|
|
6
|
+
|
|
7
|
+
if (!statuses) {
|
|
8
|
+
results.push({
|
|
9
|
+
category: CATEGORY,
|
|
10
|
+
name: "ide-audit",
|
|
11
|
+
status: "skip",
|
|
12
|
+
message: "IDE audit requires the VS Code extension (or pass ideStatuses explicitly).",
|
|
13
|
+
});
|
|
14
|
+
return results;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
for (const [id, s] of Object.entries(statuses)) {
|
|
18
|
+
if (!s.detected) {
|
|
19
|
+
results.push({ category: CATEGORY, name: id, status: "skip", message: `${s.displayName} not installed` });
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
if (!s.configured) {
|
|
23
|
+
results.push({
|
|
24
|
+
category: CATEGORY,
|
|
25
|
+
name: id,
|
|
26
|
+
status: "warn",
|
|
27
|
+
message: `${s.displayName} installed but Perplexity MCP is not configured.`,
|
|
28
|
+
hint: "Open the IDEs dashboard tab and click Configure.",
|
|
29
|
+
action: { label: "Configure", commandId: "Perplexity.generateConfigs", args: [id] },
|
|
30
|
+
});
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
// Order of evaluation: stale-args (the launcher path no longer exists)
|
|
34
|
+
// wins over a bad-command warning. A stale launcher is the higher-impact
|
|
35
|
+
// breakage — the IDE will fail to spawn anything at all — so the doctor
|
|
36
|
+
// surfaces that first and elides the command-health note for the same row.
|
|
37
|
+
if (s.health === "stale") {
|
|
38
|
+
results.push({
|
|
39
|
+
category: CATEGORY,
|
|
40
|
+
name: id,
|
|
41
|
+
status: "warn",
|
|
42
|
+
message: `${s.displayName} config is stale.`,
|
|
43
|
+
hint: "Click Configure to refresh.",
|
|
44
|
+
action: { label: "Refresh config", commandId: "Perplexity.generateConfigs", args: [id] },
|
|
45
|
+
});
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (s.commandHealth && s.commandHealth !== "ok") {
|
|
49
|
+
results.push({
|
|
50
|
+
category: CATEGORY,
|
|
51
|
+
name: id,
|
|
52
|
+
status: "warn",
|
|
53
|
+
message: `${s.displayName} configured but command path is ${s.commandHealth} — re-run 'Configure for All' to refresh.`,
|
|
54
|
+
hint: "The MCP config's `command` field doesn't look like a Node.js binary. Re-running Configure rewrites it with a resolved Node path.",
|
|
55
|
+
action: { label: "Refresh config", commandId: "Perplexity.generateConfigs", args: [id] },
|
|
56
|
+
});
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
results.push({ category: CATEGORY, name: id, status: "pass", message: `${s.displayName} configured` });
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
const { detectAllViewers } = await import('../viewer-detect.d-HWGnyFAA.d.ts');
|
|
64
|
+
const viewers = await detectAllViewers();
|
|
65
|
+
const detected = Object.entries(viewers)
|
|
66
|
+
.filter(([, present]) => present)
|
|
67
|
+
.map(([id]) => id);
|
|
68
|
+
results.push({
|
|
69
|
+
category: CATEGORY,
|
|
70
|
+
name: "mdViewers",
|
|
71
|
+
status: "pass",
|
|
72
|
+
message: detected.length > 0
|
|
73
|
+
? `Detected MD viewers: ${detected.join(", ")}`
|
|
74
|
+
: "No external MD viewers detected (VS Code preview and Rich View remain available).",
|
|
75
|
+
detail: { viewers },
|
|
76
|
+
});
|
|
77
|
+
} catch (err) {
|
|
78
|
+
results.push({
|
|
79
|
+
category: CATEGORY,
|
|
80
|
+
name: "mdViewers",
|
|
81
|
+
status: "warn",
|
|
82
|
+
message: `Viewer detection failed: ${(err instanceof Error ? err.message : String(err))}`,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return results;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export { run };
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import "../chunk-4UEJOM6W.mjs";
|
|
2
|
+
|
|
3
|
+
// src/checks/ide.js
|
|
4
|
+
var CATEGORY = "ide";
|
|
5
|
+
async function run(opts = {}) {
|
|
6
|
+
const results = [];
|
|
7
|
+
const statuses = opts.ideStatuses;
|
|
8
|
+
if (!statuses) {
|
|
9
|
+
results.push({
|
|
10
|
+
category: CATEGORY,
|
|
11
|
+
name: "ide-audit",
|
|
12
|
+
status: "skip",
|
|
13
|
+
message: "IDE audit requires the VS Code extension (or pass ideStatuses explicitly)."
|
|
14
|
+
});
|
|
15
|
+
return results;
|
|
16
|
+
}
|
|
17
|
+
for (const [id, s] of Object.entries(statuses)) {
|
|
18
|
+
if (!s.detected) {
|
|
19
|
+
results.push({ category: CATEGORY, name: id, status: "skip", message: `${s.displayName} not installed` });
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
if (!s.configured) {
|
|
23
|
+
results.push({
|
|
24
|
+
category: CATEGORY,
|
|
25
|
+
name: id,
|
|
26
|
+
status: "warn",
|
|
27
|
+
message: `${s.displayName} installed but Perplexity MCP is not configured.`,
|
|
28
|
+
hint: "Open the IDEs dashboard tab and click Configure.",
|
|
29
|
+
action: { label: "Configure", commandId: "Perplexity.generateConfigs", args: [id] }
|
|
30
|
+
});
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
if (s.health === "stale") {
|
|
34
|
+
results.push({
|
|
35
|
+
category: CATEGORY,
|
|
36
|
+
name: id,
|
|
37
|
+
status: "warn",
|
|
38
|
+
message: `${s.displayName} config is stale.`,
|
|
39
|
+
hint: "Click Configure to refresh.",
|
|
40
|
+
action: { label: "Refresh config", commandId: "Perplexity.generateConfigs", args: [id] }
|
|
41
|
+
});
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if (s.commandHealth && s.commandHealth !== "ok") {
|
|
45
|
+
results.push({
|
|
46
|
+
category: CATEGORY,
|
|
47
|
+
name: id,
|
|
48
|
+
status: "warn",
|
|
49
|
+
message: `${s.displayName} configured but command path is ${s.commandHealth} \u2014 re-run 'Configure for All' to refresh.`,
|
|
50
|
+
hint: "The MCP config's `command` field doesn't look like a Node.js binary. Re-running Configure rewrites it with a resolved Node path.",
|
|
51
|
+
action: { label: "Refresh config", commandId: "Perplexity.generateConfigs", args: [id] }
|
|
52
|
+
});
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
results.push({ category: CATEGORY, name: id, status: "pass", message: `${s.displayName} configured` });
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
const { detectAllViewers } = await import("../viewer-detect.mjs");
|
|
59
|
+
const viewers = await detectAllViewers();
|
|
60
|
+
const detected = Object.entries(viewers).filter(([, present]) => present).map(([id]) => id);
|
|
61
|
+
results.push({
|
|
62
|
+
category: CATEGORY,
|
|
63
|
+
name: "mdViewers",
|
|
64
|
+
status: "pass",
|
|
65
|
+
message: detected.length > 0 ? `Detected MD viewers: ${detected.join(", ")}` : "No external MD viewers detected (VS Code preview and Rich View remain available).",
|
|
66
|
+
detail: { viewers }
|
|
67
|
+
});
|
|
68
|
+
} catch (err) {
|
|
69
|
+
results.push({
|
|
70
|
+
category: CATEGORY,
|
|
71
|
+
name: "mdViewers",
|
|
72
|
+
status: "warn",
|
|
73
|
+
message: `Viewer detection failed: ${err instanceof Error ? err.message : String(err)}`
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
return results;
|
|
77
|
+
}
|
|
78
|
+
export {
|
|
79
|
+
run
|
|
80
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
|
|
4
|
+
const CATEGORY = "mcp";
|
|
5
|
+
const KNOWN_PROFILES = new Set(["read-only", "full", "custom"]);
|
|
6
|
+
|
|
7
|
+
async function run(opts = {}) {
|
|
8
|
+
const results = [];
|
|
9
|
+
const dir = opts.configDir;
|
|
10
|
+
const toolCfgPath = join(dir, "tools-config.json");
|
|
11
|
+
|
|
12
|
+
if (!existsSync(toolCfgPath)) {
|
|
13
|
+
results.push({
|
|
14
|
+
category: CATEGORY,
|
|
15
|
+
name: "tool-config",
|
|
16
|
+
status: "skip",
|
|
17
|
+
message: "no tools-config.json (default: full)",
|
|
18
|
+
});
|
|
19
|
+
results.push({
|
|
20
|
+
category: CATEGORY,
|
|
21
|
+
name: "enabled-tools",
|
|
22
|
+
status: "pass",
|
|
23
|
+
message: "default profile 'full'",
|
|
24
|
+
});
|
|
25
|
+
return results;
|
|
26
|
+
}
|
|
27
|
+
let cfg;
|
|
28
|
+
try {
|
|
29
|
+
cfg = JSON.parse(readFileSync(toolCfgPath, "utf8"));
|
|
30
|
+
} catch (err) {
|
|
31
|
+
results.push({
|
|
32
|
+
category: CATEGORY,
|
|
33
|
+
name: "tool-config",
|
|
34
|
+
status: "fail",
|
|
35
|
+
message: `tools-config.json malformed: ${err.message}`,
|
|
36
|
+
hint: "Delete the file to restore defaults.",
|
|
37
|
+
});
|
|
38
|
+
return results;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (!KNOWN_PROFILES.has(cfg.profile)) {
|
|
42
|
+
results.push({
|
|
43
|
+
category: CATEGORY,
|
|
44
|
+
name: "tool-config",
|
|
45
|
+
status: "warn",
|
|
46
|
+
message: `unknown profile '${cfg.profile}' — falling back to 'full'`,
|
|
47
|
+
});
|
|
48
|
+
} else {
|
|
49
|
+
results.push({ category: CATEGORY, name: "tool-config", status: "pass", message: `profile=${cfg.profile}` });
|
|
50
|
+
}
|
|
51
|
+
const count = cfg.profile === "custom"
|
|
52
|
+
? (cfg.customEnabled?.length ?? 0)
|
|
53
|
+
: cfg.profile === "read-only"
|
|
54
|
+
? 9
|
|
55
|
+
: 11;
|
|
56
|
+
results.push({ category: CATEGORY, name: "enabled-tools", status: "pass", message: `${count} tools enabled` });
|
|
57
|
+
|
|
58
|
+
return results;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export { run };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import "../chunk-4UEJOM6W.mjs";
|
|
2
|
+
|
|
3
|
+
// src/checks/mcp.js
|
|
4
|
+
import { existsSync, readFileSync } from "fs";
|
|
5
|
+
import { join } from "path";
|
|
6
|
+
var CATEGORY = "mcp";
|
|
7
|
+
var KNOWN_PROFILES = /* @__PURE__ */ new Set(["read-only", "full", "custom"]);
|
|
8
|
+
async function run(opts = {}) {
|
|
9
|
+
const results = [];
|
|
10
|
+
const dir = opts.configDir;
|
|
11
|
+
const toolCfgPath = join(dir, "tools-config.json");
|
|
12
|
+
if (!existsSync(toolCfgPath)) {
|
|
13
|
+
results.push({
|
|
14
|
+
category: CATEGORY,
|
|
15
|
+
name: "tool-config",
|
|
16
|
+
status: "skip",
|
|
17
|
+
message: "no tools-config.json (default: full)"
|
|
18
|
+
});
|
|
19
|
+
results.push({
|
|
20
|
+
category: CATEGORY,
|
|
21
|
+
name: "enabled-tools",
|
|
22
|
+
status: "pass",
|
|
23
|
+
message: "default profile 'full'"
|
|
24
|
+
});
|
|
25
|
+
return results;
|
|
26
|
+
}
|
|
27
|
+
let cfg;
|
|
28
|
+
try {
|
|
29
|
+
cfg = JSON.parse(readFileSync(toolCfgPath, "utf8"));
|
|
30
|
+
} catch (err) {
|
|
31
|
+
results.push({
|
|
32
|
+
category: CATEGORY,
|
|
33
|
+
name: "tool-config",
|
|
34
|
+
status: "fail",
|
|
35
|
+
message: `tools-config.json malformed: ${err.message}`,
|
|
36
|
+
hint: "Delete the file to restore defaults."
|
|
37
|
+
});
|
|
38
|
+
return results;
|
|
39
|
+
}
|
|
40
|
+
if (!KNOWN_PROFILES.has(cfg.profile)) {
|
|
41
|
+
results.push({
|
|
42
|
+
category: CATEGORY,
|
|
43
|
+
name: "tool-config",
|
|
44
|
+
status: "warn",
|
|
45
|
+
message: `unknown profile '${cfg.profile}' \u2014 falling back to 'full'`
|
|
46
|
+
});
|
|
47
|
+
} else {
|
|
48
|
+
results.push({ category: CATEGORY, name: "tool-config", status: "pass", message: `profile=${cfg.profile}` });
|
|
49
|
+
}
|
|
50
|
+
const count = cfg.profile === "custom" ? cfg.customEnabled?.length ?? 0 : cfg.profile === "read-only" ? 9 : 11;
|
|
51
|
+
results.push({ category: CATEGORY, name: "enabled-tools", status: "pass", message: `${count} tools enabled` });
|
|
52
|
+
return results;
|
|
53
|
+
}
|
|
54
|
+
export {
|
|
55
|
+
run
|
|
56
|
+
};
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
|
|
6
|
+
const CATEGORY = "native-deps";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Build a `require` that resolves as if invoked from `baseDir`. Falls back
|
|
10
|
+
* to this module's own file when no baseDir is supplied. The fallback works
|
|
11
|
+
* in plain Node ESM (CLI mode). In tsup-bundled CJS, `import.meta.url` is
|
|
12
|
+
* polyfilled to undefined, so the extension MUST pass a baseDir derived
|
|
13
|
+
* from `vscode.ExtensionContext.extensionUri` (e.g. `<extensionUri>/dist`).
|
|
14
|
+
*/
|
|
15
|
+
function makeRequire(baseDir) {
|
|
16
|
+
if (baseDir) {
|
|
17
|
+
return createRequire(join(baseDir, "_resolver.js"));
|
|
18
|
+
}
|
|
19
|
+
const self = import.meta.url ?? null;
|
|
20
|
+
if (!self) return null;
|
|
21
|
+
try {
|
|
22
|
+
// Resolve against this module's own file, which works in native Node ESM.
|
|
23
|
+
return createRequire(self);
|
|
24
|
+
} catch {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function resolveGotScrapingChain(baseDir) {
|
|
30
|
+
const req = makeRequire(baseDir);
|
|
31
|
+
if (!req) throw new Error("no resolver context (pass baseDir)");
|
|
32
|
+
const hg = req.resolve("header-generator");
|
|
33
|
+
const hgReq = createRequire(hg);
|
|
34
|
+
const dp = hgReq.resolve("dot-prop");
|
|
35
|
+
const dpReq = createRequire(dp);
|
|
36
|
+
const io = dpReq.resolve("is-obj");
|
|
37
|
+
return { hg, dp, io };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function getImpitRuntimeDirFallback() {
|
|
41
|
+
return join(process.env.PERPLEXITY_CONFIG_DIR || join(homedir(), ".perplexity-mcp"), "native-deps");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function run(opts = {}) {
|
|
45
|
+
const results = [];
|
|
46
|
+
const baseDir = opts.baseDir;
|
|
47
|
+
|
|
48
|
+
// patchright — required
|
|
49
|
+
try {
|
|
50
|
+
const req = makeRequire(baseDir);
|
|
51
|
+
if (!req) throw new Error("no resolver context");
|
|
52
|
+
const pkgPath = req.resolve("patchright/package.json");
|
|
53
|
+
const { version } = JSON.parse(readFileSync(pkgPath, "utf8"));
|
|
54
|
+
results.push({ category: CATEGORY, name: "patchright", status: "pass", message: `patchright ${version}` });
|
|
55
|
+
} catch {
|
|
56
|
+
results.push({
|
|
57
|
+
category: CATEGORY,
|
|
58
|
+
name: "patchright",
|
|
59
|
+
status: "fail",
|
|
60
|
+
message: "patchright not resolvable",
|
|
61
|
+
hint: "Run `pnpm install` or reinstall the VSIX.",
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// got-scraping packaging chain — carry-over #5 detector
|
|
66
|
+
const resolveChain = opts.resolveChainOverride ?? (() => resolveGotScrapingChain(baseDir));
|
|
67
|
+
try {
|
|
68
|
+
const chain = resolveChain();
|
|
69
|
+
results.push({
|
|
70
|
+
category: CATEGORY,
|
|
71
|
+
name: "got-scraping-chain",
|
|
72
|
+
status: "pass",
|
|
73
|
+
message: "header-generator -> dot-prop -> is-obj resolves",
|
|
74
|
+
detail: chain,
|
|
75
|
+
});
|
|
76
|
+
} catch (err) {
|
|
77
|
+
results.push({
|
|
78
|
+
category: CATEGORY,
|
|
79
|
+
name: "got-scraping-chain",
|
|
80
|
+
status: "warn",
|
|
81
|
+
message: "got-scraping packaging chain is broken — runtime will fall back to browser tier",
|
|
82
|
+
detail: { chainError: err.message },
|
|
83
|
+
hint: "Add the missing package to rootPackages in packages/extension/scripts/prepare-package-deps.mjs and rebuild the VSIX.",
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// impit (optional speed boost)
|
|
88
|
+
let impitStatus = opts.impitStatusOverride;
|
|
89
|
+
if (!impitStatus) {
|
|
90
|
+
try {
|
|
91
|
+
const { getImpitRuntimeDir } = await import('../refresh.d.ts');
|
|
92
|
+
const runtimeDir = typeof getImpitRuntimeDir === "function" ? getImpitRuntimeDir() : getImpitRuntimeDirFallback();
|
|
93
|
+
const marker = join(runtimeDir, "native-deps-state.json");
|
|
94
|
+
const pkgPath = join(runtimeDir, "node_modules", "impit", "package.json");
|
|
95
|
+
const state = existsSync(marker) ? JSON.parse(readFileSync(marker, "utf8")) : null;
|
|
96
|
+
if (existsSync(pkgPath)) {
|
|
97
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
|
|
98
|
+
impitStatus = {
|
|
99
|
+
installed: true,
|
|
100
|
+
version: pkg.version ?? state?.version ?? null,
|
|
101
|
+
installedAt: state?.installedAt ?? null,
|
|
102
|
+
};
|
|
103
|
+
} else {
|
|
104
|
+
impitStatus = { installed: false, version: state?.version ?? null, installedAt: state?.installedAt ?? null };
|
|
105
|
+
}
|
|
106
|
+
} catch {
|
|
107
|
+
impitStatus = { installed: false, version: null };
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (impitStatus.installed) {
|
|
111
|
+
results.push({
|
|
112
|
+
category: CATEGORY,
|
|
113
|
+
name: "impit",
|
|
114
|
+
status: "pass",
|
|
115
|
+
message: `impit ${impitStatus.version ?? "(unknown version)"}${impitStatus.installedAt ? ` - installed ${impitStatus.installedAt}` : ""}`,
|
|
116
|
+
});
|
|
117
|
+
} else {
|
|
118
|
+
results.push({
|
|
119
|
+
category: CATEGORY,
|
|
120
|
+
name: "impit",
|
|
121
|
+
status: "skip",
|
|
122
|
+
message: "not installed (optional — skips browser launches for sync, hydrate, retrieve, export, models, login)",
|
|
123
|
+
hint: "Install with: `npx perplexity-user-mcp install-speed-boost` — or click 'Install Speed Boost' in the VS Code extension dashboard.",
|
|
124
|
+
action: { label: "Install Speed Boost", commandId: "Perplexity.installSpeedBoost" },
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return results;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export { run };
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import "../chunk-4UEJOM6W.mjs";
|
|
2
|
+
|
|
3
|
+
// src/checks/native-deps.js
|
|
4
|
+
import { createRequire } from "module";
|
|
5
|
+
import { existsSync, readFileSync } from "fs";
|
|
6
|
+
import { homedir } from "os";
|
|
7
|
+
import { join } from "path";
|
|
8
|
+
var CATEGORY = "native-deps";
|
|
9
|
+
function makeRequire(baseDir) {
|
|
10
|
+
if (baseDir) {
|
|
11
|
+
return createRequire(join(baseDir, "_resolver.js"));
|
|
12
|
+
}
|
|
13
|
+
const self = import.meta.url ?? null;
|
|
14
|
+
if (!self) return null;
|
|
15
|
+
try {
|
|
16
|
+
return createRequire(self);
|
|
17
|
+
} catch {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function resolveGotScrapingChain(baseDir) {
|
|
22
|
+
const req = makeRequire(baseDir);
|
|
23
|
+
if (!req) throw new Error("no resolver context (pass baseDir)");
|
|
24
|
+
const hg = req.resolve("header-generator");
|
|
25
|
+
const hgReq = createRequire(hg);
|
|
26
|
+
const dp = hgReq.resolve("dot-prop");
|
|
27
|
+
const dpReq = createRequire(dp);
|
|
28
|
+
const io = dpReq.resolve("is-obj");
|
|
29
|
+
return { hg, dp, io };
|
|
30
|
+
}
|
|
31
|
+
function getImpitRuntimeDirFallback() {
|
|
32
|
+
return join(process.env.PERPLEXITY_CONFIG_DIR || join(homedir(), ".perplexity-mcp"), "native-deps");
|
|
33
|
+
}
|
|
34
|
+
async function run(opts = {}) {
|
|
35
|
+
const results = [];
|
|
36
|
+
const baseDir = opts.baseDir;
|
|
37
|
+
try {
|
|
38
|
+
const req = makeRequire(baseDir);
|
|
39
|
+
if (!req) throw new Error("no resolver context");
|
|
40
|
+
const pkgPath = req.resolve("patchright/package.json");
|
|
41
|
+
const { version } = JSON.parse(readFileSync(pkgPath, "utf8"));
|
|
42
|
+
results.push({ category: CATEGORY, name: "patchright", status: "pass", message: `patchright ${version}` });
|
|
43
|
+
} catch {
|
|
44
|
+
results.push({
|
|
45
|
+
category: CATEGORY,
|
|
46
|
+
name: "patchright",
|
|
47
|
+
status: "fail",
|
|
48
|
+
message: "patchright not resolvable",
|
|
49
|
+
hint: "Run `pnpm install` or reinstall the VSIX."
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
const resolveChain = opts.resolveChainOverride ?? (() => resolveGotScrapingChain(baseDir));
|
|
53
|
+
try {
|
|
54
|
+
const chain = resolveChain();
|
|
55
|
+
results.push({
|
|
56
|
+
category: CATEGORY,
|
|
57
|
+
name: "got-scraping-chain",
|
|
58
|
+
status: "pass",
|
|
59
|
+
message: "header-generator -> dot-prop -> is-obj resolves",
|
|
60
|
+
detail: chain
|
|
61
|
+
});
|
|
62
|
+
} catch (err) {
|
|
63
|
+
results.push({
|
|
64
|
+
category: CATEGORY,
|
|
65
|
+
name: "got-scraping-chain",
|
|
66
|
+
status: "warn",
|
|
67
|
+
message: "got-scraping packaging chain is broken \u2014 runtime will fall back to browser tier",
|
|
68
|
+
detail: { chainError: err.message },
|
|
69
|
+
hint: "Add the missing package to rootPackages in packages/extension/scripts/prepare-package-deps.mjs and rebuild the VSIX."
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
let impitStatus = opts.impitStatusOverride;
|
|
73
|
+
if (!impitStatus) {
|
|
74
|
+
try {
|
|
75
|
+
const { getImpitRuntimeDir } = await import("../refresh.mjs");
|
|
76
|
+
const runtimeDir = typeof getImpitRuntimeDir === "function" ? getImpitRuntimeDir() : getImpitRuntimeDirFallback();
|
|
77
|
+
const marker = join(runtimeDir, "native-deps-state.json");
|
|
78
|
+
const pkgPath = join(runtimeDir, "node_modules", "impit", "package.json");
|
|
79
|
+
const state = existsSync(marker) ? JSON.parse(readFileSync(marker, "utf8")) : null;
|
|
80
|
+
if (existsSync(pkgPath)) {
|
|
81
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
|
|
82
|
+
impitStatus = {
|
|
83
|
+
installed: true,
|
|
84
|
+
version: pkg.version ?? state?.version ?? null,
|
|
85
|
+
installedAt: state?.installedAt ?? null
|
|
86
|
+
};
|
|
87
|
+
} else {
|
|
88
|
+
impitStatus = { installed: false, version: state?.version ?? null, installedAt: state?.installedAt ?? null };
|
|
89
|
+
}
|
|
90
|
+
} catch {
|
|
91
|
+
impitStatus = { installed: false, version: null };
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (impitStatus.installed) {
|
|
95
|
+
results.push({
|
|
96
|
+
category: CATEGORY,
|
|
97
|
+
name: "impit",
|
|
98
|
+
status: "pass",
|
|
99
|
+
message: `impit ${impitStatus.version ?? "(unknown version)"}${impitStatus.installedAt ? ` - installed ${impitStatus.installedAt}` : ""}`
|
|
100
|
+
});
|
|
101
|
+
} else {
|
|
102
|
+
results.push({
|
|
103
|
+
category: CATEGORY,
|
|
104
|
+
name: "impit",
|
|
105
|
+
status: "skip",
|
|
106
|
+
message: "not installed (optional \u2014 skips browser launches for sync, hydrate, retrieve, export, models, login)",
|
|
107
|
+
hint: "Install with: `npx perplexity-user-mcp install-speed-boost` \u2014 or click 'Install Speed Boost' in the VS Code extension dashboard.",
|
|
108
|
+
action: { label: "Install Speed Boost", commandId: "Perplexity.installSpeedBoost" }
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
return results;
|
|
112
|
+
}
|
|
113
|
+
export {
|
|
114
|
+
run
|
|
115
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { lookup } from 'node:dns/promises';
|
|
2
|
+
import { request } from 'node:https';
|
|
3
|
+
|
|
4
|
+
const CATEGORY = "network";
|
|
5
|
+
const DEFAULT_HOST = "www.perplexity.ai";
|
|
6
|
+
|
|
7
|
+
function httpsHead(url, { timeoutMs = 5000 } = {}) {
|
|
8
|
+
return new Promise((resolve, reject) => {
|
|
9
|
+
const req = request(url, { method: "HEAD", timeout: timeoutMs }, (res) => {
|
|
10
|
+
resolve({ statusCode: res.statusCode, headers: res.headers });
|
|
11
|
+
res.resume();
|
|
12
|
+
});
|
|
13
|
+
req.on("timeout", () => { req.destroy(new Error("HTTPS HEAD timeout")); });
|
|
14
|
+
req.on("error", reject);
|
|
15
|
+
req.end();
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async function run(opts = {}) {
|
|
20
|
+
const results = [];
|
|
21
|
+
const host = opts.host ?? DEFAULT_HOST;
|
|
22
|
+
const dns = opts.dnsLookupOverride ?? lookup;
|
|
23
|
+
const head = opts.httpsHeadOverride ?? ((u) => httpsHead(u));
|
|
24
|
+
|
|
25
|
+
let addr = null;
|
|
26
|
+
try {
|
|
27
|
+
addr = await dns(host);
|
|
28
|
+
results.push({ category: CATEGORY, name: "dns", status: "pass", message: `${host} -> ${addr.address}` });
|
|
29
|
+
} catch (err) {
|
|
30
|
+
results.push({
|
|
31
|
+
category: CATEGORY,
|
|
32
|
+
name: "dns",
|
|
33
|
+
status: "fail",
|
|
34
|
+
message: `DNS lookup failed: ${err.message}`,
|
|
35
|
+
hint: "Check internet connection / proxy / VPN.",
|
|
36
|
+
});
|
|
37
|
+
return results;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
let headRes;
|
|
41
|
+
try {
|
|
42
|
+
headRes = await head(`https://${host}${process.env.PERPLEXITY_LOGIN_PATH || "/account"}`);
|
|
43
|
+
results.push({ category: CATEGORY, name: "https", status: "pass", message: `HEAD / status ${headRes.statusCode}` });
|
|
44
|
+
} catch (err) {
|
|
45
|
+
results.push({
|
|
46
|
+
category: CATEGORY,
|
|
47
|
+
name: "https",
|
|
48
|
+
status: "fail",
|
|
49
|
+
message: `HTTPS failed: ${err.message}`,
|
|
50
|
+
hint: "TLS/MITM proxy? Corporate firewall?",
|
|
51
|
+
});
|
|
52
|
+
return results;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const isCf = String(headRes.headers?.server ?? "").toLowerCase().includes("cloudflare") && headRes.statusCode === 503;
|
|
56
|
+
if (isCf) {
|
|
57
|
+
results.push({
|
|
58
|
+
category: CATEGORY,
|
|
59
|
+
name: "cf-challenge",
|
|
60
|
+
status: "warn",
|
|
61
|
+
message: "Cloudflare challenge active — logins may need manual captcha.",
|
|
62
|
+
hint: "Try login --mode manual if auto mode fails.",
|
|
63
|
+
});
|
|
64
|
+
} else {
|
|
65
|
+
results.push({ category: CATEGORY, name: "cf-challenge", status: "pass", message: "no challenge detected" });
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return results;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export { run };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import "../chunk-4UEJOM6W.mjs";
|
|
2
|
+
|
|
3
|
+
// src/checks/network.js
|
|
4
|
+
import { lookup } from "dns/promises";
|
|
5
|
+
import { request } from "https";
|
|
6
|
+
var CATEGORY = "network";
|
|
7
|
+
var DEFAULT_HOST = "www.perplexity.ai";
|
|
8
|
+
function httpsHead(url, { timeoutMs = 5e3 } = {}) {
|
|
9
|
+
return new Promise((resolve, reject) => {
|
|
10
|
+
const req = request(url, { method: "HEAD", timeout: timeoutMs }, (res) => {
|
|
11
|
+
resolve({ statusCode: res.statusCode, headers: res.headers });
|
|
12
|
+
res.resume();
|
|
13
|
+
});
|
|
14
|
+
req.on("timeout", () => {
|
|
15
|
+
req.destroy(new Error("HTTPS HEAD timeout"));
|
|
16
|
+
});
|
|
17
|
+
req.on("error", reject);
|
|
18
|
+
req.end();
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
async function run(opts = {}) {
|
|
22
|
+
const results = [];
|
|
23
|
+
const host = opts.host ?? DEFAULT_HOST;
|
|
24
|
+
const dns = opts.dnsLookupOverride ?? lookup;
|
|
25
|
+
const head = opts.httpsHeadOverride ?? ((u) => httpsHead(u));
|
|
26
|
+
let addr = null;
|
|
27
|
+
try {
|
|
28
|
+
addr = await dns(host);
|
|
29
|
+
results.push({ category: CATEGORY, name: "dns", status: "pass", message: `${host} -> ${addr.address}` });
|
|
30
|
+
} catch (err) {
|
|
31
|
+
results.push({
|
|
32
|
+
category: CATEGORY,
|
|
33
|
+
name: "dns",
|
|
34
|
+
status: "fail",
|
|
35
|
+
message: `DNS lookup failed: ${err.message}`,
|
|
36
|
+
hint: "Check internet connection / proxy / VPN."
|
|
37
|
+
});
|
|
38
|
+
return results;
|
|
39
|
+
}
|
|
40
|
+
let headRes;
|
|
41
|
+
try {
|
|
42
|
+
headRes = await head(`https://${host}${process.env.PERPLEXITY_LOGIN_PATH || "/account"}`);
|
|
43
|
+
results.push({ category: CATEGORY, name: "https", status: "pass", message: `HEAD / status ${headRes.statusCode}` });
|
|
44
|
+
} catch (err) {
|
|
45
|
+
results.push({
|
|
46
|
+
category: CATEGORY,
|
|
47
|
+
name: "https",
|
|
48
|
+
status: "fail",
|
|
49
|
+
message: `HTTPS failed: ${err.message}`,
|
|
50
|
+
hint: "TLS/MITM proxy? Corporate firewall?"
|
|
51
|
+
});
|
|
52
|
+
return results;
|
|
53
|
+
}
|
|
54
|
+
const isCf = String(headRes.headers?.server ?? "").toLowerCase().includes("cloudflare") && headRes.statusCode === 503;
|
|
55
|
+
if (isCf) {
|
|
56
|
+
results.push({
|
|
57
|
+
category: CATEGORY,
|
|
58
|
+
name: "cf-challenge",
|
|
59
|
+
status: "warn",
|
|
60
|
+
message: "Cloudflare challenge active \u2014 logins may need manual captcha.",
|
|
61
|
+
hint: "Try login --mode manual if auto mode fails."
|
|
62
|
+
});
|
|
63
|
+
} else {
|
|
64
|
+
results.push({ category: CATEGORY, name: "cf-challenge", status: "pass", message: "no challenge detected" });
|
|
65
|
+
}
|
|
66
|
+
return results;
|
|
67
|
+
}
|
|
68
|
+
export {
|
|
69
|
+
run
|
|
70
|
+
};
|