@pharaoh-so/mcp 0.3.4 → 0.3.5
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/auth.d.ts +3 -6
- package/dist/auth.js +37 -13
- package/dist/index.js +17 -8
- package/dist/install-skills.d.ts +3 -1
- package/dist/install-skills.js +30 -25
- package/dist/setup.d.ts +3 -1
- package/dist/setup.js +6 -5
- package/package.json +1 -1
package/dist/auth.d.ts
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Device flow client for Pharaoh MCP proxy (RFC 8628).
|
|
3
|
-
* All user-visible output goes to stderr — stdout is reserved for JSON-RPC.
|
|
4
|
-
*/
|
|
5
1
|
/** Response from POST /device. */
|
|
6
2
|
export interface DeviceCodeResponse {
|
|
7
3
|
device_code: string;
|
|
@@ -36,9 +32,10 @@ export declare function requestDeviceCode(baseUrl: string): Promise<DeviceCodeRe
|
|
|
36
32
|
export declare function pollForToken(baseUrl: string, deviceCode: string, interval: number): Promise<TokenResponse>;
|
|
37
33
|
/**
|
|
38
34
|
* Print the device activation prompt to stderr.
|
|
39
|
-
* Shows the user code and verification URI in a visible box
|
|
35
|
+
* Shows the user code and verification URI in a visible box,
|
|
36
|
+
* and opens the verification URL in the default browser.
|
|
40
37
|
*/
|
|
41
|
-
export declare function printActivationPrompt(userCode: string, verificationUri: string): void;
|
|
38
|
+
export declare function printActivationPrompt(userCode: string, verificationUri: string, verificationUriComplete?: string): void;
|
|
42
39
|
/**
|
|
43
40
|
* Print authentication success message to stderr.
|
|
44
41
|
*/
|
package/dist/auth.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Device flow client for Pharaoh MCP proxy (RFC 8628).
|
|
3
3
|
* All user-visible output goes to stderr — stdout is reserved for JSON-RPC.
|
|
4
4
|
*/
|
|
5
|
+
import { execFile } from "node:child_process";
|
|
5
6
|
/**
|
|
6
7
|
* Request a device code from the Pharaoh server (RFC 8628 §3.1).
|
|
7
8
|
* Returns the device code, user code, and verification URIs.
|
|
@@ -55,31 +56,54 @@ export async function pollForToken(baseUrl, deviceCode, interval) {
|
|
|
55
56
|
throw new Error(`Device token error: ${body.error} — ${body.error_description ?? ""}`);
|
|
56
57
|
}
|
|
57
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* Open a URL in the user's default browser.
|
|
61
|
+
* Uses platform-specific commands; fails silently if unavailable.
|
|
62
|
+
*/
|
|
63
|
+
function openBrowser(url) {
|
|
64
|
+
if (process.platform === "darwin") {
|
|
65
|
+
execFile("open", [url], () => { });
|
|
66
|
+
}
|
|
67
|
+
else if (process.platform === "win32") {
|
|
68
|
+
execFile("cmd.exe", ["/c", "start", "", url], () => { });
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
execFile("xdg-open", [url], () => { });
|
|
72
|
+
}
|
|
73
|
+
}
|
|
58
74
|
/**
|
|
59
75
|
* Print the device activation prompt to stderr.
|
|
60
|
-
* Shows the user code and verification URI in a visible box
|
|
76
|
+
* Shows the user code and verification URI in a visible box,
|
|
77
|
+
* and opens the verification URL in the default browser.
|
|
61
78
|
*/
|
|
62
|
-
export function printActivationPrompt(userCode, verificationUri) {
|
|
79
|
+
export function printActivationPrompt(userCode, verificationUri, verificationUriComplete) {
|
|
80
|
+
// Auto-open browser with the complete URI (pre-fills the code)
|
|
81
|
+
openBrowser(verificationUriComplete ?? verificationUri);
|
|
82
|
+
const W = 48;
|
|
83
|
+
const pad = (s) => `│ ${s.padEnd(W - 2)}│`;
|
|
84
|
+
const empty = `│${" ".repeat(W)}│`;
|
|
85
|
+
const top = `┌${"─".repeat(W)}┐`;
|
|
86
|
+
const bot = `└${"─".repeat(W)}┘`;
|
|
63
87
|
const lines = [
|
|
64
88
|
"",
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
"
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
89
|
+
top,
|
|
90
|
+
empty,
|
|
91
|
+
pad(`Your code: ${userCode}`),
|
|
92
|
+
empty,
|
|
93
|
+
pad("A browser window should open automatically."),
|
|
94
|
+
pad("If it didn't open, visit:"),
|
|
95
|
+
pad(verificationUri),
|
|
96
|
+
empty,
|
|
97
|
+
bot,
|
|
74
98
|
"",
|
|
75
99
|
];
|
|
76
|
-
process.stderr.write(lines.join("\n")
|
|
100
|
+
process.stderr.write(`${lines.join("\n")}\n`);
|
|
77
101
|
}
|
|
78
102
|
/**
|
|
79
103
|
* Print authentication success message to stderr.
|
|
80
104
|
*/
|
|
81
105
|
export function printAuthSuccess(login, tenant, repoCount) {
|
|
82
|
-
const parts = ["
|
|
106
|
+
const parts = ["✓ Authenticated"];
|
|
83
107
|
if (login)
|
|
84
108
|
parts.push(`as ${login}`);
|
|
85
109
|
if (tenant)
|
package/dist/index.js
CHANGED
|
@@ -12,9 +12,17 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { pollForToken, printActivationPrompt, printAuthSuccess, requestDeviceCode, } from "./auth.js";
|
|
14
14
|
import { deleteCredentials, isExpired, readCredentials, writeCredentials } from "./credentials.js";
|
|
15
|
-
import {
|
|
15
|
+
import { formatTtl, NPX_COMMAND, parseArgs, printLines, printUsage, resolveSseUrl, tokenToCredentials, } from "./helpers.js";
|
|
16
16
|
import { runInstallSkills } from "./install-skills.js";
|
|
17
17
|
import { startProxy, TenantSuspendedError, TokenExpiredError } from "./proxy.js";
|
|
18
|
+
const BANNER = [
|
|
19
|
+
"",
|
|
20
|
+
" ___ _ _ _ ___ _ ___ _ _ ",
|
|
21
|
+
" | _ \\| || | /_\\ | _ \\ /_\\ / _ \\| || |",
|
|
22
|
+
" | _/| __ |/ _ \\| / / _ \\| (_) | __ |",
|
|
23
|
+
" |_| |_||_/_/ \\_\\_|_\\/_/ \\_\\\\___/|_||_|",
|
|
24
|
+
"",
|
|
25
|
+
].join("\n");
|
|
18
26
|
async function main() {
|
|
19
27
|
const args = process.argv.slice(2);
|
|
20
28
|
if (args.includes("--help") || args.includes("-h")) {
|
|
@@ -45,11 +53,11 @@ async function main() {
|
|
|
45
53
|
// Full setup every time: fresh auth → register MCP → install skills → done.
|
|
46
54
|
// Running `npx @pharaoh-so/mcp` is the only command a user needs.
|
|
47
55
|
if (isInteractive) {
|
|
56
|
+
process.stderr.write(`${BANNER}\n`);
|
|
48
57
|
// Always re-authenticate for a fresh session
|
|
49
|
-
printLines("Pharaoh: starting device authorization...");
|
|
50
58
|
deleteCredentials();
|
|
51
59
|
const deviceCode = await requestDeviceCode(server);
|
|
52
|
-
printActivationPrompt(deviceCode.user_code, deviceCode.verification_uri);
|
|
60
|
+
printActivationPrompt(deviceCode.user_code, deviceCode.verification_uri, deviceCode.verification_uri_complete);
|
|
53
61
|
const token = await pollForToken(server, deviceCode.device_code, deviceCode.interval);
|
|
54
62
|
if (token.provisional) {
|
|
55
63
|
printLines(`Pharaoh: provisional access — install the GitHub App to map your repos: ${token.install_url ?? ""}`);
|
|
@@ -58,12 +66,13 @@ async function main() {
|
|
|
58
66
|
const newCreds = tokenToCredentials(token, sseUrl);
|
|
59
67
|
writeCredentials(newCreds);
|
|
60
68
|
printAuthSuccess(token.github_login ?? null, token.tenant_name ?? null, token.repos?.length ?? 0);
|
|
61
|
-
// Register MCP server
|
|
69
|
+
// Register MCP server + install skills (silent — user doesn't need internals)
|
|
70
|
+
process.stderr.write(" Setting up...");
|
|
62
71
|
const { runSetup } = await import("./setup.js");
|
|
63
|
-
runSetup();
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
printLines("", "Pharaoh is ready.
|
|
72
|
+
runSetup({ silent: true });
|
|
73
|
+
runInstallSkills(undefined, { silent: true });
|
|
74
|
+
process.stderr.write(" done.\n");
|
|
75
|
+
printLines("", "Pharaoh is ready. Try these in a new Claude Code conversation:", "", ' "What modules does this codebase have?"', ' "Search for functions related to authentication"', ' "What breaks if I change this file?"', "");
|
|
67
76
|
process.exit(0);
|
|
68
77
|
}
|
|
69
78
|
// ── Proxy mode (Claude Code spawned us as a stdio MCP server) ──
|
package/dist/install-skills.d.ts
CHANGED
|
@@ -30,4 +30,6 @@ export declare function mergeOpenClawConfig(home?: string): boolean;
|
|
|
30
30
|
*
|
|
31
31
|
* @param home - Home directory override (defaults to os.homedir()).
|
|
32
32
|
*/
|
|
33
|
-
export declare function runInstallSkills(home?: string
|
|
33
|
+
export declare function runInstallSkills(home?: string, options?: {
|
|
34
|
+
silent?: boolean;
|
|
35
|
+
}): void;
|
package/dist/install-skills.js
CHANGED
|
@@ -242,7 +242,8 @@ function configureClaudeCodePermissions(home = homedir()) {
|
|
|
242
242
|
*
|
|
243
243
|
* @param home - Home directory override (defaults to os.homedir()).
|
|
244
244
|
*/
|
|
245
|
-
export function runInstallSkills(home = homedir()) {
|
|
245
|
+
export function runInstallSkills(home = homedir(), options) {
|
|
246
|
+
const silent = options?.silent ?? false;
|
|
246
247
|
const hasClaudeCode = detectClaudeCode(home);
|
|
247
248
|
const hasOpenClaw = detectOpenClaw(home);
|
|
248
249
|
let installed = false;
|
|
@@ -251,21 +252,23 @@ export function runInstallSkills(home = homedir()) {
|
|
|
251
252
|
const count = installClaudeCodePlugin(home);
|
|
252
253
|
if (count >= 0) {
|
|
253
254
|
const regResult = registerClaudeCodePlugin(home);
|
|
254
|
-
const regMessages = {
|
|
255
|
-
added: "Plugin registered in installed_plugins.json",
|
|
256
|
-
updated: "Plugin version updated in installed_plugins.json",
|
|
257
|
-
current: "Plugin already registered and up-to-date",
|
|
258
|
-
error: "Could not update installed_plugins.json",
|
|
259
|
-
};
|
|
260
255
|
// Silently ensure Pharaoh tools auto-approve (no user prompt on first use)
|
|
261
256
|
configureClaudeCodePermissions(home);
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
257
|
+
if (!silent) {
|
|
258
|
+
const regMessages = {
|
|
259
|
+
added: "Plugin registered in installed_plugins.json",
|
|
260
|
+
updated: "Plugin version updated in installed_plugins.json",
|
|
261
|
+
current: "Plugin already registered and up-to-date",
|
|
262
|
+
error: "Could not update installed_plugins.json",
|
|
263
|
+
};
|
|
264
|
+
process.stderr.write([
|
|
265
|
+
`Pharaoh: installed ${count} skills as Claude Code plugin`,
|
|
266
|
+
` → ~/.claude/plugins/data/pharaoh/`,
|
|
267
|
+
` → ${regMessages[regResult]}`,
|
|
268
|
+
"",
|
|
269
|
+
...(regResult === "added" ? ["Restart Claude Code to pick up the new skills.", ""] : []),
|
|
270
|
+
].join("\n"));
|
|
271
|
+
}
|
|
269
272
|
installed = true;
|
|
270
273
|
}
|
|
271
274
|
}
|
|
@@ -273,20 +276,22 @@ export function runInstallSkills(home = homedir()) {
|
|
|
273
276
|
if (hasOpenClaw) {
|
|
274
277
|
const count = installSkills(home);
|
|
275
278
|
const configUpdated = mergeOpenClawConfig(home);
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
279
|
+
if (!silent) {
|
|
280
|
+
const configMsg = configUpdated
|
|
281
|
+
? "Pharaoh MCP server added to ~/.openclaw/openclaw.json"
|
|
282
|
+
: "Pharaoh already present in ~/.openclaw/openclaw.json — skipped";
|
|
283
|
+
process.stderr.write([
|
|
284
|
+
`Pharaoh: installed ${count} skills to ~/.openclaw/skills/`,
|
|
285
|
+
` → ${configMsg}`,
|
|
286
|
+
"",
|
|
287
|
+
"Restart OpenClaw to pick up the new skills.",
|
|
288
|
+
"",
|
|
289
|
+
].join("\n"));
|
|
290
|
+
}
|
|
286
291
|
installed = true;
|
|
287
292
|
}
|
|
288
293
|
// ── Neither detected ──
|
|
289
|
-
if (!installed) {
|
|
294
|
+
if (!installed && !silent) {
|
|
290
295
|
process.stderr.write([
|
|
291
296
|
"Pharaoh: no supported skill platform detected.",
|
|
292
297
|
"",
|
package/dist/setup.d.ts
CHANGED
package/dist/setup.js
CHANGED
|
@@ -46,12 +46,14 @@ function runClaude(args) {
|
|
|
46
46
|
*
|
|
47
47
|
* @returns true if setup succeeded, false if Claude CLI not found.
|
|
48
48
|
*/
|
|
49
|
-
export function runSetup() {
|
|
49
|
+
export function runSetup(options) {
|
|
50
|
+
const silent = options?.silent ?? false;
|
|
50
51
|
if (!hasClaude()) {
|
|
51
52
|
printLines("Pharaoh: Claude Code CLI not found.", "", "Install Claude Code first: https://claude.ai/download", `Then re-run: ${NPX_COMMAND}`, "");
|
|
52
53
|
return false;
|
|
53
54
|
}
|
|
54
|
-
|
|
55
|
+
if (!silent)
|
|
56
|
+
printLines("Pharaoh: setting up...");
|
|
55
57
|
// Step 1: Remove any stale entry (ignore failures — may not exist)
|
|
56
58
|
runClaude(["mcp", "remove", "pharaoh"]);
|
|
57
59
|
// Step 2: Register as global stdio MCP server
|
|
@@ -69,8 +71,7 @@ export function runSetup() {
|
|
|
69
71
|
printLines("Pharaoh: failed to register MCP server.", `Try manually: ${NPX_COMMAND}`, "");
|
|
70
72
|
return false;
|
|
71
73
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
// We just report the MCP registration success here.
|
|
74
|
+
if (!silent)
|
|
75
|
+
printLines("Pharaoh: registered as global MCP server (scope: user)");
|
|
75
76
|
return true;
|
|
76
77
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pharaoh-so/mcp",
|
|
3
3
|
"mcpName": "so.pharaoh/pharaoh",
|
|
4
|
-
"version": "0.3.
|
|
4
|
+
"version": "0.3.5",
|
|
5
5
|
"description": "MCP proxy for Pharaoh — maps codebases into queryable knowledge graphs for AI agents. Enables Claude Code in headless environments (VPS, SSH, CI) via device flow auth.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "dist/index.js",
|