@pharaoh-so/mcp 0.3.54 → 0.3.57
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/.mcp.json +1 -1
- package/CHANGELOG.md +36 -0
- package/LICENSE +1 -1
- package/NOTICE +28 -0
- package/README.md +5 -5
- package/commands/plan.md +11 -11
- package/commands/review.md +2 -2
- package/dist/auth.d.ts +5 -0
- package/dist/credentials.d.ts +8 -0
- package/dist/gateway.js +1 -1
- package/dist/helpers.d.ts +1 -1
- package/dist/helpers.js +15 -2
- package/dist/index.js +47 -28
- package/dist/install-skills.d.ts +4 -3
- package/dist/install-skills.js +12 -8
- package/dist/refresh.d.ts +8 -2
- package/dist/refresh.js +33 -6
- package/dist/setup.d.ts +5 -0
- package/dist/setup.js +66 -0
- package/inspect-tools.json +89 -36
- package/{skills → npx-skills}/brainstorm/SKILL.md +2 -1
- package/{skills → npx-skills}/debug/SKILL.md +2 -1
- package/{skills → npx-skills}/pharaoh/SKILL.md +13 -6
- package/{skills → npx-skills}/plan/SKILL.md +13 -14
- package/npx-skills/refactor/SKILL.md +38 -0
- package/{skills → npx-skills}/review/SKILL.md +4 -5
- package/{skills → npx-skills}/tdd/SKILL.md +2 -1
- package/{skills → npx-skills}/verify/SKILL.md +2 -1
- package/package.json +6 -4
- package/project-memory/bundle.mjs +137 -0
- package/project-memory/execute-turn.mjs +269 -0
- package/project-memory/hook-config.mjs +91 -0
- package/project-memory/hook-events.mjs +117 -0
- package/project-memory/local.mjs +480 -0
- package/project-memory/memory-api.mjs +200 -0
- package/project-memory/pharaoh-memory-hook.mjs +47 -0
- package/project-memory/pharaoh-memory.mjs +60 -0
- package/project-memory/setup.d.mts +14 -0
- package/project-memory/setup.mjs +151 -0
- package/project-memory/user-target.mjs +235 -0
- package/trace-app.html +222 -101
- package/skills/.gitkeep +0 -0
- package/skills/refactor/SKILL.md +0 -34
package/dist/refresh.js
CHANGED
|
@@ -41,10 +41,11 @@ const REFRESH_TIMEOUT_MS = 10_000;
|
|
|
41
41
|
* @param server Pharaoh server base URL (e.g. "https://mcp.pharaoh.so")
|
|
42
42
|
* @param path optional custom credentials path (for tests)
|
|
43
43
|
* @param timeoutMs how long the refresh request may take (for tests)
|
|
44
|
+
* @param strictOrigin require credentials from this origin and refuse refresh redirects
|
|
44
45
|
* @returns New or adopted credentials, or a classified failure. A lock held by
|
|
45
46
|
* another proxy for too long is `transient` (credentials untouched).
|
|
46
47
|
*/
|
|
47
|
-
export async function refreshIfNeeded(creds, server, path, timeoutMs = REFRESH_TIMEOUT_MS) {
|
|
48
|
+
export async function refreshIfNeeded(creds, server, path, timeoutMs = REFRESH_TIMEOUT_MS, strictOrigin = false) {
|
|
48
49
|
let release;
|
|
49
50
|
try {
|
|
50
51
|
release = await acquireCredentialsLock(path);
|
|
@@ -58,11 +59,13 @@ export async function refreshIfNeeded(creds, server, path, timeoutMs = REFRESH_T
|
|
|
58
59
|
}
|
|
59
60
|
try {
|
|
60
61
|
const current = readCredentials(path);
|
|
62
|
+
const source = current ?? creds;
|
|
63
|
+
if (strictOrigin && !matchesOrigin(source, server))
|
|
64
|
+
return originMismatch();
|
|
61
65
|
if (current && current.access_token !== creds.access_token && !isExpired(current)) {
|
|
62
66
|
return { ok: true, creds: current };
|
|
63
67
|
}
|
|
64
|
-
const
|
|
65
|
-
const outcome = await requestRefresh(source, server, timeoutMs, path);
|
|
68
|
+
const outcome = await requestRefresh(source, server, timeoutMs, path, strictOrigin);
|
|
66
69
|
if (outcome.ok || outcome.action !== "reauth")
|
|
67
70
|
return outcome;
|
|
68
71
|
const after = readCredentials(path);
|
|
@@ -70,6 +73,8 @@ export async function refreshIfNeeded(creds, server, path, timeoutMs = REFRESH_T
|
|
|
70
73
|
deleteCredentials(path);
|
|
71
74
|
return outcome;
|
|
72
75
|
}
|
|
76
|
+
if (strictOrigin && !matchesOrigin(after, server))
|
|
77
|
+
return originMismatch();
|
|
73
78
|
return isExpired(after) ? outcome : { ok: true, creds: after };
|
|
74
79
|
}
|
|
75
80
|
finally {
|
|
@@ -80,7 +85,7 @@ export async function refreshIfNeeded(creds, server, path, timeoutMs = REFRESH_T
|
|
|
80
85
|
* One refresh-grant round trip: POST the refresh token, persist and return the
|
|
81
86
|
* new credentials on success, or classify the failure. Caller holds the lock.
|
|
82
87
|
*/
|
|
83
|
-
async function requestRefresh(creds, server, timeoutMs, path) {
|
|
88
|
+
async function requestRefresh(creds, server, timeoutMs, path, strictOrigin = false) {
|
|
84
89
|
// Guard: refresh token itself expired. No point hitting the server — the
|
|
85
90
|
// grant will fail with invalid_grant. Short-circuit to reauth.
|
|
86
91
|
if (isRefreshExpired(creds)) {
|
|
@@ -101,6 +106,7 @@ async function requestRefresh(creds, server, timeoutMs, path) {
|
|
|
101
106
|
body: JSON.stringify({
|
|
102
107
|
refresh_token: creds.refresh_token,
|
|
103
108
|
}),
|
|
109
|
+
redirect: strictOrigin ? "error" : undefined,
|
|
104
110
|
signal: AbortSignal.timeout(timeoutMs),
|
|
105
111
|
});
|
|
106
112
|
}
|
|
@@ -192,15 +198,36 @@ async function requestRefresh(creds, server, timeoutMs, path) {
|
|
|
192
198
|
* Intended use: called at proxy startup to replace the current "die if expired"
|
|
193
199
|
* branch in index.ts.
|
|
194
200
|
*/
|
|
195
|
-
export async function loadAndRefresh(server, path) {
|
|
201
|
+
export async function loadAndRefresh(server, path, strictOrigin = false) {
|
|
196
202
|
const creds = readCredentials(path);
|
|
197
203
|
if (!creds)
|
|
198
204
|
return null;
|
|
205
|
+
if (strictOrigin && !matchesOrigin(creds, server))
|
|
206
|
+
return originMismatch();
|
|
199
207
|
// Access token still valid — no refresh needed.
|
|
200
208
|
const expiresAt = new Date(creds.expires_at).getTime();
|
|
201
209
|
const bufferMs = creds.expires_in * 1000 * 0.1;
|
|
202
210
|
if (Date.now() < expiresAt - bufferMs) {
|
|
203
211
|
return { ok: true, creds };
|
|
204
212
|
}
|
|
205
|
-
return refreshIfNeeded(creds, server, path);
|
|
213
|
+
return refreshIfNeeded(creds, server, path, undefined, strictOrigin);
|
|
214
|
+
}
|
|
215
|
+
/** A fixed-origin caller must never send credentials issued by another server. */
|
|
216
|
+
function matchesOrigin(creds, server) {
|
|
217
|
+
try {
|
|
218
|
+
return new URL(creds.sse_url).origin === new URL(server).origin;
|
|
219
|
+
}
|
|
220
|
+
catch {
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
function originMismatch() {
|
|
225
|
+
return { ok: false, action: "transient", message: "Credentials belong to a different server" };
|
|
226
|
+
}
|
|
227
|
+
/** Refresh for a client that accepts credentials only from its configured origin. */
|
|
228
|
+
export function originBoundRefresh(server, path) {
|
|
229
|
+
return {
|
|
230
|
+
load: () => loadAndRefresh(server, path, true),
|
|
231
|
+
renew: (creds) => refreshIfNeeded(creds, server, path, undefined, true),
|
|
232
|
+
};
|
|
206
233
|
}
|
package/dist/setup.d.ts
CHANGED
|
@@ -54,3 +54,8 @@ export declare function runSetup(options?: {
|
|
|
54
54
|
home?: string;
|
|
55
55
|
claude?: ClaudeCli;
|
|
56
56
|
}): boolean;
|
|
57
|
+
/** Detect the local Codex CLI before touching any settings. */
|
|
58
|
+
export declare function hasCodex(): boolean;
|
|
59
|
+
/** Preserve custom registrations and any existing disabled setting. */
|
|
60
|
+
export declare function runCodexSetup(): boolean;
|
|
61
|
+
export declare function cleanCodexSetup(): void;
|
package/dist/setup.js
CHANGED
|
@@ -185,3 +185,69 @@ export function runSetup(options) {
|
|
|
185
185
|
printLines(`Pharaoh: registered as global MCP server (scope: user) running ${spec}`);
|
|
186
186
|
return true;
|
|
187
187
|
}
|
|
188
|
+
/** Detect the local Codex CLI before touching any settings. */
|
|
189
|
+
export function hasCodex() {
|
|
190
|
+
try {
|
|
191
|
+
execFileSync("codex", ["--version"], { stdio: "pipe", timeout: 10_000 });
|
|
192
|
+
return true;
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
function codexMcp(args) {
|
|
199
|
+
return execFileSync("codex", ["mcp", ...args], {
|
|
200
|
+
encoding: "utf8",
|
|
201
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
202
|
+
timeout: 30_000,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
function configuredCodexPharaoh() {
|
|
206
|
+
try {
|
|
207
|
+
const { transport, enabled } = JSON.parse(codexMcp(["get", "pharaoh", "--json"]));
|
|
208
|
+
return {
|
|
209
|
+
owned: transport?.type === "stdio" &&
|
|
210
|
+
transport.command === "npx" &&
|
|
211
|
+
transport.args?.length === 1 &&
|
|
212
|
+
/^@pharaoh-so\/mcp@\d+\.\d+\.\d+$/.test(transport.args[0]) &&
|
|
213
|
+
!transport.env &&
|
|
214
|
+
!transport.env_vars?.length &&
|
|
215
|
+
!transport.cwd,
|
|
216
|
+
enabled,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
catch (error) {
|
|
220
|
+
if (error &&
|
|
221
|
+
typeof error === "object" &&
|
|
222
|
+
"stderr" in error &&
|
|
223
|
+
typeof error.stderr === "string" &&
|
|
224
|
+
error.stderr.includes("No MCP server named 'pharaoh' found."))
|
|
225
|
+
return null;
|
|
226
|
+
throw error;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
/** Preserve custom registrations and any existing disabled setting. */
|
|
230
|
+
export function runCodexSetup() {
|
|
231
|
+
try {
|
|
232
|
+
const existing = configuredCodexPharaoh();
|
|
233
|
+
if (existing && (!existing.owned || existing.enabled === false))
|
|
234
|
+
return true;
|
|
235
|
+
codexMcp(["add", "pharaoh", "--", "npx", pinnedPackageSpec()]);
|
|
236
|
+
return true;
|
|
237
|
+
}
|
|
238
|
+
catch {
|
|
239
|
+
printLines("Pharaoh: Codex setup could not update its MCP registration.");
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
export function cleanCodexSetup() {
|
|
244
|
+
if (!hasCodex())
|
|
245
|
+
return;
|
|
246
|
+
try {
|
|
247
|
+
if (configuredCodexPharaoh()?.owned)
|
|
248
|
+
codexMcp(["remove", "pharaoh"]);
|
|
249
|
+
}
|
|
250
|
+
catch {
|
|
251
|
+
printLines("Pharaoh: Codex setup could not remove its MCP registration.");
|
|
252
|
+
}
|
|
253
|
+
}
|
package/inspect-tools.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
|
-
"instructions": "Pharaoh
|
|
2
|
+
"instructions": "Pharaoh answers structural questions about mapped repos from a graph of each repo's default branch: functions, callers, modules, dependencies, endpoints, cron jobs and reachability, for TypeScript, JavaScript and Python. No source code is stored.\n\n## Which tool answers which question\n\nPharaoh answers these questions from the graph:\n\n| Question | Tool |\n|---|---|\n| Does X already exist? Where is Y implemented? | search_functions |\n| What calls X? What breaks if I change it? Which endpoints or cron jobs reach it? | get_blast_radius |\n| What's in this module, what does it depend on, who calls into it? | get_module_context |\n| Is this code dead or wired in? What can I delete? | get_unused_code |\n| How is the repo laid out? Which module owns this? What's the repo called? | get_codebase_map |\n| Several of these at once (planning a change, reviewing a PR) | pharaoh_recon |\n\nThe graph reflects the default branch at its last mapped push, and a response says when a newer push is still being mapped. Grep and file reads cover what it leaves out: code that isn't on the default branch yet (other branches, uncommitted edits), literal text (strings, error messages, config values, comments, non-code files) and renames, which change every reference, tests and mocks included.\n\n## Repos\n\nRepos are mapped through the Pharaoh GitHub App, installed on the account or org that owns them: `https://github.com/apps/pharaoh-so/installations/new`. The App reads the repositories it is installed on and the organization's membership; its only write permission is posting check results. Mapped repos re-map on every push. search_functions accepts any of the user's mapped repo names.\n\nTools take the short repo name in their `repo` parameter (e.g. \"pharaoh\", not \"org/pharaoh\"). Unambiguous short names resolve automatically. A name that doesn't resolve returns suggestions and the user's repos grouped by organization.\n\n## Account\n\npharaoh_account shows each workspace's plan. Every repo is mapped during the trial and on Pro; after the trial, get_codebase_map keeps answering and the other tools say what's needed. pharaoh_manage_repo queues a re-map of a repo now.",
|
|
3
3
|
"tools": [
|
|
4
4
|
{
|
|
5
5
|
"name": "get_codebase_map",
|
|
6
|
-
"
|
|
6
|
+
"title": "Codebase Map",
|
|
7
|
+
"description": "A repo's architecture in one call.\n\nCALL THIS WHEN:\n• Getting a repo's overall structure, or which module owns something\n• The repo's exact name in Pharaoh isn't known\n\nRETURNS: Modules with file counts and LOC, module dependencies with two-way ones flagged, the 5 files changed most in 90 days, endpoints with handler files (first 50), convention entry points (first 30), and risk signals (high-risk functions without direct test links, exact clones, cycles).",
|
|
7
8
|
"inputSchema": {
|
|
8
9
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
9
10
|
"type": "object",
|
|
@@ -13,7 +14,7 @@
|
|
|
13
14
|
"description": "Repository name — one of your connected repos."
|
|
14
15
|
},
|
|
15
16
|
"include_metrics": {
|
|
16
|
-
"description": "
|
|
17
|
+
"description": "List the 10 most-changed files instead of 5",
|
|
17
18
|
"type": "boolean"
|
|
18
19
|
}
|
|
19
20
|
},
|
|
@@ -22,9 +23,10 @@
|
|
|
22
23
|
]
|
|
23
24
|
},
|
|
24
25
|
"annotations": {
|
|
25
|
-
"title": "Codebase Architecture Map",
|
|
26
26
|
"readOnlyHint": true,
|
|
27
|
-
"destructiveHint": false
|
|
27
|
+
"destructiveHint": false,
|
|
28
|
+
"title": "Codebase Map",
|
|
29
|
+
"openWorldHint": false
|
|
28
30
|
},
|
|
29
31
|
"execution": {
|
|
30
32
|
"taskSupport": "forbidden"
|
|
@@ -38,7 +40,8 @@
|
|
|
38
40
|
},
|
|
39
41
|
{
|
|
40
42
|
"name": "pharaoh_recon",
|
|
41
|
-
"
|
|
43
|
+
"title": "Codebase Recon",
|
|
44
|
+
"description": "Several Pharaoh queries in one call, run in parallel: codebase map, module profiles, function searches, blast radius and module dependency paths.\n\nCALL THIS WHEN:\n• Planning a change, reviewing a PR or assessing architecture, when the modules and functions to check are known\n\nRETURNS: Each requested section in one response, as the single-purpose tools return it. Per call: up to 5 modules, 3 searches, 3 blast radius targets, 3 dependency pairs.",
|
|
42
45
|
"inputSchema": {
|
|
43
46
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
44
47
|
"type": "object",
|
|
@@ -52,21 +55,24 @@
|
|
|
52
55
|
"type": "boolean"
|
|
53
56
|
},
|
|
54
57
|
"modules": {
|
|
55
|
-
"description": "Modules to profile
|
|
58
|
+
"description": "Modules to profile",
|
|
59
|
+
"maxItems": 5,
|
|
56
60
|
"type": "array",
|
|
57
61
|
"items": {
|
|
58
62
|
"type": "string"
|
|
59
63
|
}
|
|
60
64
|
},
|
|
61
65
|
"functions": {
|
|
62
|
-
"description": "Function searches
|
|
66
|
+
"description": "Function searches",
|
|
67
|
+
"maxItems": 3,
|
|
63
68
|
"type": "array",
|
|
64
69
|
"items": {
|
|
65
70
|
"type": "string"
|
|
66
71
|
}
|
|
67
72
|
},
|
|
68
73
|
"blast_radius": {
|
|
69
|
-
"description": "Blast radius targets
|
|
74
|
+
"description": "Blast radius targets",
|
|
75
|
+
"maxItems": 3,
|
|
70
76
|
"type": "array",
|
|
71
77
|
"items": {
|
|
72
78
|
"type": "object",
|
|
@@ -91,7 +97,8 @@
|
|
|
91
97
|
}
|
|
92
98
|
},
|
|
93
99
|
"dependencies": {
|
|
94
|
-
"description": "Module pairs to trace a dependency path between
|
|
100
|
+
"description": "Module pairs to trace a dependency path between",
|
|
101
|
+
"maxItems": 3,
|
|
95
102
|
"type": "array",
|
|
96
103
|
"items": {
|
|
97
104
|
"type": "object",
|
|
@@ -115,9 +122,10 @@
|
|
|
115
122
|
]
|
|
116
123
|
},
|
|
117
124
|
"annotations": {
|
|
118
|
-
"title": "Codebase Recon",
|
|
119
125
|
"readOnlyHint": true,
|
|
120
|
-
"destructiveHint": false
|
|
126
|
+
"destructiveHint": false,
|
|
127
|
+
"title": "Codebase Recon",
|
|
128
|
+
"openWorldHint": false
|
|
121
129
|
},
|
|
122
130
|
"execution": {
|
|
123
131
|
"taskSupport": "forbidden"
|
|
@@ -131,7 +139,8 @@
|
|
|
131
139
|
},
|
|
132
140
|
{
|
|
133
141
|
"name": "get_module_context",
|
|
134
|
-
"
|
|
142
|
+
"title": "Module Context",
|
|
143
|
+
"description": "One module's profile: what it contains, depends on and is called by.\n\nCALL THIS WHEN:\n• Changing code in a module, or planning a change to it\n• Finding what a module exports, depends on, or which code calls into it\n\nRETURNS: Files, LOC, exported signatures with complexity, imports in and out, DB tables, endpoints, cron jobs, env vars, and callers in other modules, grouped by module.",
|
|
135
144
|
"inputSchema": {
|
|
136
145
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
137
146
|
"type": "object",
|
|
@@ -151,9 +160,10 @@
|
|
|
151
160
|
]
|
|
152
161
|
},
|
|
153
162
|
"annotations": {
|
|
154
|
-
"title": "Module Deep Dive",
|
|
155
163
|
"readOnlyHint": true,
|
|
156
|
-
"destructiveHint": false
|
|
164
|
+
"destructiveHint": false,
|
|
165
|
+
"title": "Module Context",
|
|
166
|
+
"openWorldHint": false
|
|
157
167
|
},
|
|
158
168
|
"execution": {
|
|
159
169
|
"taskSupport": "forbidden"
|
|
@@ -167,7 +177,8 @@
|
|
|
167
177
|
},
|
|
168
178
|
{
|
|
169
179
|
"name": "get_blast_radius",
|
|
170
|
-
"
|
|
180
|
+
"title": "Blast Radius",
|
|
181
|
+
"description": "What a change to a function, file or module reaches.\n\nCALL THIS WHEN:\n• Changing a signature, refactoring or deleting code\n• Finding the callers or detected endpoints a change reaches\n\nRETURNS: Risk, production callers by module/file, endpoints, cron jobs and DB operations, through direct and indirect calls. Hops are the shortest detected path within the requested depth (1–5). Test-file callers are excluded.",
|
|
171
182
|
"inputSchema": {
|
|
172
183
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
173
184
|
"type": "object",
|
|
@@ -203,9 +214,10 @@
|
|
|
203
214
|
]
|
|
204
215
|
},
|
|
205
216
|
"annotations": {
|
|
206
|
-
"title": "Change Blast Radius",
|
|
207
217
|
"readOnlyHint": true,
|
|
208
|
-
"destructiveHint": false
|
|
218
|
+
"destructiveHint": false,
|
|
219
|
+
"title": "Blast Radius",
|
|
220
|
+
"openWorldHint": false
|
|
209
221
|
},
|
|
210
222
|
"execution": {
|
|
211
223
|
"taskSupport": "forbidden"
|
|
@@ -219,7 +231,8 @@
|
|
|
219
231
|
},
|
|
220
232
|
{
|
|
221
233
|
"name": "search_functions",
|
|
222
|
-
"
|
|
234
|
+
"title": "Search Functions",
|
|
235
|
+
"description": "Find functions by name or concept across the whole codebase.\n\nCALL THIS WHEN:\n• Checking whether a function, helper or utility already exists\n• Finding where something is implemented (e.g. \"retry\", \"validate\", \"notify\")\n\nRETURNS: Matching functions with file path, line range, module, signature, export status and complexity. Matches name parts (camelCase, snake_case) and file paths, not comments; test code ranks last. SCREAMING_SNAKE queries, and queries no function matches, return matching constants with up to 80 characters of each value.",
|
|
223
236
|
"inputSchema": {
|
|
224
237
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
225
238
|
"type": "object",
|
|
@@ -247,11 +260,15 @@
|
|
|
247
260
|
},
|
|
248
261
|
"offset": {
|
|
249
262
|
"description": "Results to skip (default 0)",
|
|
250
|
-
"type": "
|
|
263
|
+
"type": "integer",
|
|
264
|
+
"minimum": 0,
|
|
265
|
+
"maximum": 9007199254740991
|
|
251
266
|
},
|
|
252
267
|
"limit": {
|
|
253
|
-
"description": "Max results (default 20
|
|
254
|
-
"type": "
|
|
268
|
+
"description": "Max results (default 20)",
|
|
269
|
+
"type": "integer",
|
|
270
|
+
"minimum": 1,
|
|
271
|
+
"maximum": 50
|
|
255
272
|
}
|
|
256
273
|
},
|
|
257
274
|
"required": [
|
|
@@ -260,9 +277,10 @@
|
|
|
260
277
|
]
|
|
261
278
|
},
|
|
262
279
|
"annotations": {
|
|
263
|
-
"title": "Function Search",
|
|
264
280
|
"readOnlyHint": true,
|
|
265
|
-
"destructiveHint": false
|
|
281
|
+
"destructiveHint": false,
|
|
282
|
+
"title": "Search Functions",
|
|
283
|
+
"openWorldHint": false
|
|
266
284
|
},
|
|
267
285
|
"execution": {
|
|
268
286
|
"taskSupport": "forbidden"
|
|
@@ -276,7 +294,8 @@
|
|
|
276
294
|
},
|
|
277
295
|
{
|
|
278
296
|
"name": "get_unused_code",
|
|
279
|
-
"
|
|
297
|
+
"title": "Unused Code",
|
|
298
|
+
"description": "Find code nothing runs: functions no production entry point (endpoint, CLI command, cron job, event handler, worker, entry file) reaches.\n\nCALL THIS WHEN:\n• Cleaning up a module or deleting a function\n• Confirming new code is reached from an entry point\n\nRETURNS: Reachability through the call graph, not text references.\n• Dead: unreached, named in no other file, and no import of its file could reach it.\n• Possibly unused: unreached, but named in other files (string dispatch, dynamic loading) or an import of its file could reach it. Listed with the files that name it.\n• Used only by tests: exported functions and class methods only test files reference.\nWith `functions`: each one's status, and the call path from an entry point when it's reachable.",
|
|
280
299
|
"inputSchema": {
|
|
281
300
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
282
301
|
"type": "object",
|
|
@@ -303,9 +322,10 @@
|
|
|
303
322
|
]
|
|
304
323
|
},
|
|
305
324
|
"annotations": {
|
|
306
|
-
"title": "Unused Code",
|
|
307
325
|
"readOnlyHint": true,
|
|
308
|
-
"destructiveHint": false
|
|
326
|
+
"destructiveHint": false,
|
|
327
|
+
"title": "Unused Code",
|
|
328
|
+
"openWorldHint": false
|
|
309
329
|
},
|
|
310
330
|
"execution": {
|
|
311
331
|
"taskSupport": "forbidden"
|
|
@@ -319,7 +339,38 @@
|
|
|
319
339
|
},
|
|
320
340
|
{
|
|
321
341
|
"name": "pharaoh_account",
|
|
322
|
-
"
|
|
342
|
+
"title": "Account Status",
|
|
343
|
+
"description": "Your Pharaoh plan and mapped repos in each workspace. Changes nothing.\n\nCALL THIS WHEN:\n• Checking which plan a workspace is on\n• A tool says the plan doesn't include it, or a repo isn't mapped\n• Finding the setup page or the billing page\n\nRETURNS: Each workspace you can access with its plan and tracked-repo count, whether its repos are mapped on every push, the setup page, and the billing page when a workspace has a billing account.",
|
|
344
|
+
"inputSchema": {
|
|
345
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
346
|
+
"type": "object",
|
|
347
|
+
"properties": {
|
|
348
|
+
"action": {
|
|
349
|
+
"description": "Only status; pharaoh_manage_repo re-maps a repo",
|
|
350
|
+
"type": "string",
|
|
351
|
+
"const": "status"
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
},
|
|
355
|
+
"annotations": {
|
|
356
|
+
"readOnlyHint": true,
|
|
357
|
+
"destructiveHint": false,
|
|
358
|
+
"title": "Account Status",
|
|
359
|
+
"openWorldHint": false
|
|
360
|
+
},
|
|
361
|
+
"execution": {
|
|
362
|
+
"taskSupport": "forbidden"
|
|
363
|
+
},
|
|
364
|
+
"_meta": {
|
|
365
|
+
"ui": {
|
|
366
|
+
"resourceUri": "ui://pharaoh/trace/v1.1.html"
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
},
|
|
370
|
+
{
|
|
371
|
+
"name": "pharaoh_manage_repo",
|
|
372
|
+
"title": "Refresh Repo",
|
|
373
|
+
"description": "Re-map a repo now. Every repo is mapped during the trial and on Pro, and re-maps on every push.\n\n• refresh_repo { repo, full? }: queue a re-map of one repo.\n• set_free_repo { repo }: retired; it changes nothing, since there is no live repo to choose.\n\nCALL THIS WHEN:\n• A repo's graph looks out of date, or needs a full rebuild\n\nRETURNS: The queued job.",
|
|
323
374
|
"inputSchema": {
|
|
324
375
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
325
376
|
"type": "object",
|
|
@@ -327,29 +378,31 @@
|
|
|
327
378
|
"action": {
|
|
328
379
|
"type": "string",
|
|
329
380
|
"enum": [
|
|
330
|
-
"status",
|
|
331
381
|
"set_free_repo",
|
|
332
382
|
"refresh_repo"
|
|
333
383
|
],
|
|
334
|
-
"description": "Which
|
|
384
|
+
"description": "Which change to make"
|
|
335
385
|
},
|
|
336
386
|
"repo": {
|
|
337
|
-
"
|
|
338
|
-
"
|
|
387
|
+
"type": "string",
|
|
388
|
+
"minLength": 1,
|
|
389
|
+
"description": "Repo slug (owner/repo) or repo name"
|
|
339
390
|
},
|
|
340
391
|
"full": {
|
|
341
|
-
"description": "
|
|
392
|
+
"description": "refresh_repo only: rebuild the whole graph instead of a delta refresh",
|
|
342
393
|
"type": "boolean"
|
|
343
394
|
}
|
|
344
395
|
},
|
|
345
396
|
"required": [
|
|
346
|
-
"action"
|
|
397
|
+
"action",
|
|
398
|
+
"repo"
|
|
347
399
|
]
|
|
348
400
|
},
|
|
349
401
|
"annotations": {
|
|
350
|
-
"title": "Account Management",
|
|
351
402
|
"readOnlyHint": false,
|
|
352
|
-
"destructiveHint":
|
|
403
|
+
"destructiveHint": true,
|
|
404
|
+
"title": "Refresh Repo",
|
|
405
|
+
"openWorldHint": false
|
|
353
406
|
},
|
|
354
407
|
"execution": {
|
|
355
408
|
"taskSupport": "forbidden"
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
name: brainstorm
|
|
3
3
|
prompt-name: brainstorm
|
|
4
4
|
description: "Explore intent, requirements, and design before implementation. Collaborative dialogue to turn ideas into specs. Ask clarifying questions one at a time, propose 2-3 approaches with trade-offs, get approval before writing any code. Prevents wasted work from unexamined assumptions."
|
|
5
|
-
|
|
5
|
+
license: MIT. Adapted from obra/superpowers, Copyright (c) 2025 Jesse Vincent; see NOTICE in @pharaoh-so/mcp
|
|
6
|
+
version: 0.2.1
|
|
6
7
|
homepage: https://pharaoh.so
|
|
7
8
|
user-invocable: true
|
|
8
9
|
metadata: {"emoji": "☥", "tags": ["planning", "design", "brainstorming", "requirements", "architecture"]}
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
name: debug
|
|
3
3
|
prompt-name: systematic-debugging
|
|
4
4
|
description: "Systematic 4-phase debugging methodology. Root cause investigation before any fixes. Read errors carefully, reproduce consistently, trace data flow, form hypotheses, test minimally. If 3+ fixes fail, question the architecture. No guessing, no quick patches, no symptom fixes."
|
|
5
|
-
|
|
5
|
+
license: MIT. Adapted from obra/superpowers, Copyright (c) 2025 Jesse Vincent; see NOTICE in @pharaoh-so/mcp
|
|
6
|
+
version: 0.2.1
|
|
6
7
|
homepage: https://pharaoh.so
|
|
7
8
|
user-invocable: true
|
|
8
9
|
metadata: {"emoji": "☥", "tags": ["debugging", "root-cause", "investigation", "troubleshooting", "methodology"]}
|
|
@@ -2,12 +2,14 @@
|
|
|
2
2
|
name: pharaoh
|
|
3
3
|
prompt-name: pharaoh-core
|
|
4
4
|
description: "Codebase knowledge graph — gives AI agents full architectural awareness. Query architecture, dependencies, blast radius, module context, and function search instead of reading files one at a time. Code intelligence via MCP: understand any codebase in seconds."
|
|
5
|
-
version: 0.3.
|
|
5
|
+
version: 0.3.1
|
|
6
6
|
homepage: https://pharaoh.so
|
|
7
7
|
metadata: {"emoji": "☥", "openclaw": {"always": true}, "tags": ["code-intelligence", "architecture", "mcp", "knowledge-graph", "dependencies", "codebase-understanding"]}
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
-
Pharaoh
|
|
10
|
+
# Pharaoh Tool Guide
|
|
11
|
+
|
|
12
|
+
Pharaoh maps codebases into queryable knowledge graphs — functions, dependencies, modules, connections. No source code stored. For questions about how code connects, one Pharaoh call answers what grep and file reads take many turns to piece together.
|
|
11
13
|
|
|
12
14
|
## When to Use
|
|
13
15
|
|
|
@@ -26,13 +28,15 @@ This skill loads automatically in sessions where Pharaoh MCP tools are available
|
|
|
26
28
|
|
|
27
29
|
Ask Pharaoh first for these questions, then read the files you're about to change. The graph maps the default branch, so use grep for code that isn't there yet (your branch, uncommitted edits), for literal text (strings, error messages, config values, comments, non-code files) and for renames, which change every reference, tests and mocks included. Don't re-check a Pharaoh answer with grep; if a response says the latest push is still being mapped, re-check only the files that push changed.
|
|
28
30
|
|
|
31
|
+
If your client shows Pharaoh's tools by name only (behind tool search), load them before your first code search.
|
|
32
|
+
|
|
29
33
|
## CRITICAL: Surface insight blocks
|
|
30
34
|
|
|
31
|
-
Surface the facts in each ★ Pharaoh block in your visible response. Preserve its counts, labels and analysis limits.
|
|
35
|
+
Surface the facts in each ★ Pharaoh block in your visible response. Preserve its counts, labels and analysis limits. When a block says "Trace view available", do not reproduce the ASCII panel; summarize its findings and limits in plain language. Otherwise, if the client hides or breaks ASCII panels, present those facts as plain text or a table; do not rely on the raw tool panel being visible.
|
|
32
36
|
|
|
33
37
|
## Repos that aren't mapped
|
|
34
38
|
|
|
35
|
-
The only supported path is the Pharaoh GitHub App:
|
|
39
|
+
The only supported path is the Pharaoh GitHub App: Pro maps every repo, as does the trial (after the trial, get_codebase_map keeps answering and the other tools say what's needed), and mapped repos re-map on every push. Run `pharaoh_account` to get the exact install link for the user's account or org. Do not suggest workarounds for missing repos.
|
|
36
40
|
|
|
37
41
|
## Vision docs
|
|
38
42
|
|
|
@@ -45,6 +49,8 @@ with the user before coding.
|
|
|
45
49
|
|
|
46
50
|
**PR review:** `pharaoh_recon` (map + touched modules + blast radius) → `get_blast_radius` on the riskiest changed functions. Verdict: SHIP, SHIP WITH CHANGES, or BLOCK. Any PR touching code governed by a MUST-bullet should reference the assertion in the review.
|
|
47
51
|
|
|
52
|
+
**Cross-repo:** When the user has several mapped repos, check related repos when a change touches shared interfaces, APIs or types: `search_functions` takes any of your repo names.
|
|
53
|
+
|
|
48
54
|
**Vision maintenance:** When an architectural decision lands in a PR, update `docs/VISION.md` in the same commit — add an assertion if one is new, retire one if it no longer applies. Stale vision docs are worse than none.
|
|
49
55
|
|
|
50
56
|
## Using results
|
|
@@ -58,7 +64,8 @@ When asked what Pharaoh does: explain what you learned from the graph in this co
|
|
|
58
64
|
|
|
59
65
|
## Utilities
|
|
60
66
|
|
|
61
|
-
- `pharaoh_account` — plan
|
|
67
|
+
- `pharaoh_account` — plan and mapped repos in each workspace
|
|
68
|
+
- `pharaoh_manage_repo` — re-map a repo now
|
|
62
69
|
|
|
63
70
|
Full docs at [pharaoh.so/docs](https://pharaoh.so/docs).
|
|
64
71
|
|
|
@@ -71,5 +78,5 @@ npx @pharaoh-so/mcp
|
|
|
71
78
|
|
|
72
79
|
**URL** (Claude.ai, Cursor, ChatGPT — paste in settings):
|
|
73
80
|
```
|
|
74
|
-
https://mcp.pharaoh.so/
|
|
81
|
+
https://mcp.pharaoh.so/mcp
|
|
75
82
|
```
|