mcp-walkthrough 0.1.6 → 0.2.1
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 +28 -13
- package/dist/bridge.d.ts +1 -0
- package/dist/bridge.d.ts.map +1 -1
- package/dist/bridge.js +92 -51
- package/dist/bridge.js.map +1 -1
- package/dist/code-cli.d.ts +4 -0
- package/dist/code-cli.d.ts.map +1 -0
- package/dist/code-cli.js +86 -0
- package/dist/code-cli.js.map +1 -0
- package/dist/socket.d.ts +3 -0
- package/dist/socket.d.ts.map +1 -0
- package/dist/socket.js +28 -0
- package/dist/socket.js.map +1 -0
- package/package.json +3 -2
- package/scripts/postinstall.cjs +98 -0
- package/vscode-extension/walkthrough-bridge.vsix +0 -0
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ Text in a terminal isn't enough when you want Claude to explain a solution. MCP
|
|
|
19
19
|
- **Selection Reading** — Claude can see what you've highlighted to discuss it further
|
|
20
20
|
- **Focus Preservation** — Opens files without stealing focus from your terminal
|
|
21
21
|
|
|
22
|
-
> **Note:** This MCP server requires VS Code. It includes a companion VS Code extension that is automatically installed when you `npm install`.
|
|
22
|
+
> **Note:** This MCP server requires VS Code, VS Code Insiders, or Cursor. It includes a companion VS Code extension that is automatically installed when you `npm install`. The CLI is auto-discovered even if `code` is not in your PATH.
|
|
23
23
|
|
|
24
24
|
## Installation
|
|
25
25
|
|
|
@@ -144,15 +144,16 @@ Explanations render as markdown in VS Code comment bubbles. Tips:
|
|
|
144
144
|
## How It Works
|
|
145
145
|
|
|
146
146
|
```
|
|
147
|
-
Claude Code → MCP Server (stdio) →
|
|
147
|
+
Claude Code → MCP Server (stdio) → Unix socket → VS Code Extension → Editor API
|
|
148
148
|
```
|
|
149
149
|
|
|
150
150
|
1. Claude calls walkthrough tools via MCP
|
|
151
|
-
2. The MCP server
|
|
152
|
-
3. The
|
|
153
|
-
4.
|
|
151
|
+
2. The MCP server discovers a workspace-specific Unix socket (`/tmp/walkthrough-bridge-<hash>.sock`)
|
|
152
|
+
3. The VS Code extension listens on a socket derived from the workspace folder path
|
|
153
|
+
4. Each VS Code window gets its own socket — multiple windows work independently
|
|
154
|
+
5. Focus stays in your terminal — code appears in the editor beside it
|
|
154
155
|
|
|
155
|
-
The VS Code extension is bundled with the npm package and automatically installed on first
|
|
156
|
+
The VS Code extension is bundled with the npm package and automatically installed on `npm install` and on first server start. The CLI is auto-discovered across VS Code, VS Code Insiders, and Cursor on all platforms.
|
|
156
157
|
|
|
157
158
|
## Development
|
|
158
159
|
|
|
@@ -162,15 +163,22 @@ The VS Code extension is bundled with the npm package and automatically installe
|
|
|
162
163
|
mcp-walkthrough/
|
|
163
164
|
├── src/
|
|
164
165
|
│ ├── index.ts # MCP server entry point, tool registration
|
|
165
|
-
│ ├── bridge.ts #
|
|
166
|
+
│ ├── bridge.ts # Unix socket client to VS Code extension
|
|
167
|
+
│ ├── code-cli.ts # Cross-platform VS Code CLI discovery
|
|
168
|
+
│ ├── socket.ts # Socket path computation and discovery
|
|
166
169
|
│ └── utils/
|
|
167
170
|
│ └── logger.ts # Pino logger (stderr only)
|
|
171
|
+
├── scripts/
|
|
172
|
+
│ └── postinstall.cjs # Auto-installs extension on npm install
|
|
168
173
|
├── vscode-extension/
|
|
169
174
|
│ ├── src/
|
|
170
175
|
│ │ └── extension.ts # VS Code extension (HTTP server, Comments API)
|
|
171
176
|
│ └── package.json
|
|
172
177
|
├── tests/
|
|
173
|
-
│
|
|
178
|
+
│ ├── bridge.test.ts
|
|
179
|
+
│ ├── code-cli.test.ts
|
|
180
|
+
│ ├── postinstall.test.ts
|
|
181
|
+
│ └── socket.test.ts
|
|
174
182
|
└── docs/
|
|
175
183
|
```
|
|
176
184
|
|
|
@@ -194,19 +202,26 @@ The build script syncs the version from root `package.json` into the extension b
|
|
|
194
202
|
|
|
195
203
|
## Troubleshooting
|
|
196
204
|
|
|
197
|
-
### Tools return "
|
|
205
|
+
### Tools return "No walkthrough bridge socket found"
|
|
198
206
|
|
|
199
|
-
The MCP server
|
|
207
|
+
The MCP server discovers the VS Code extension via a Unix socket. If the socket isn't found:
|
|
200
208
|
|
|
201
209
|
1. Make sure you're running Claude Code inside VS Code (not a standalone terminal)
|
|
202
210
|
2. The extension activates on VS Code startup — try reloading the window (`Cmd+Shift+P` → "Reload Window")
|
|
211
|
+
3. The socket is workspace-specific — make sure the VS Code window has a folder open
|
|
203
212
|
|
|
204
213
|
### Extension not installed
|
|
205
214
|
|
|
206
|
-
The MCP server auto-
|
|
215
|
+
The MCP server auto-discovers VS Code, VS Code Insiders, and Cursor CLIs — even when `code` isn't in your PATH. It searches:
|
|
207
216
|
|
|
208
|
-
|
|
209
|
-
|
|
217
|
+
- **macOS**: `/Applications/*.app/Contents/Resources/app/bin/`
|
|
218
|
+
- **Linux**: `/usr/bin/`, `/usr/local/bin/`, `/snap/bin/`, `/opt/*/bin/`
|
|
219
|
+
- **Windows**: `%LOCALAPPDATA%\Programs\*\bin\`
|
|
220
|
+
|
|
221
|
+
The extension is installed into **all** found editors. If auto-install still fails:
|
|
222
|
+
|
|
223
|
+
1. Manually install: `code --install-extension path/to/walkthrough-bridge.vsix`
|
|
224
|
+
2. Or reload the VS Code window after installing the npm package
|
|
210
225
|
|
|
211
226
|
## Contributing
|
|
212
227
|
|
package/dist/bridge.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export declare function ensureExtensionInstalled(): void;
|
|
|
2
2
|
type BridgeResult = Record<string, unknown>;
|
|
3
3
|
export declare let bridgeAvailable: boolean | null;
|
|
4
4
|
export declare function resetBridgeState(): void;
|
|
5
|
+
export declare function _setSocketPath(path: string): void;
|
|
5
6
|
export declare function checkBridge(): Promise<boolean>;
|
|
6
7
|
export declare function isBridgeAvailable(): boolean;
|
|
7
8
|
export declare function openFile(file: string, line: number, endLine?: number, startChar?: number, endChar?: number): Promise<BridgeResult>;
|
package/dist/bridge.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAkBA,wBAAgB,wBAAwB,IAAI,IAAI,CAoC/C;AAED,KAAK,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE5C,eAAO,IAAI,eAAe,EAAE,OAAO,GAAG,IAAW,CAAC;AAGlD,wBAAgB,gBAAgB,IAAI,IAAI,CAGvC;AAGD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEjD;AA+DD,wBAAsB,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,CAKpD;AAED,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C;AAED,wBAAsB,QAAQ,CAC5B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,MAAM,EAChB,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,YAAY,CAAC,CAEvB;AAED,wBAAsB,eAAe,CACnC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,WAAW,EAAE,MAAM,EACnB,KAAK,CAAC,EAAE,MAAM,EACd,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,YAAY,CAAC,CAUvB;AAED,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,YAAY,CAAC,CAE/D;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,eAAe,EAAE,EACxB,QAAQ,CAAC,EAAE,OAAO,EAClB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,YAAY,CAAC,CAEvB;AAED,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,YAAY,CAAC,CAEvB;AAED,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,YAAY,CAAC,CAElE;AAED,wBAAsB,YAAY,IAAI,OAAO,CAAC,YAAY,CAAC,CAE1D"}
|
package/dist/bridge.js
CHANGED
|
@@ -1,81 +1,122 @@
|
|
|
1
1
|
import { execSync } from "node:child_process";
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
|
+
import * as http from "node:http";
|
|
3
4
|
import { dirname, join } from "node:path";
|
|
4
5
|
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { resolveAllCodeClis } from "./code-cli.js";
|
|
7
|
+
import { discoverSocket } from "./socket.js";
|
|
5
8
|
import { logger } from "./utils/logger.js";
|
|
6
9
|
const __filename = fileURLToPath(import.meta.url);
|
|
7
10
|
const __dirname = dirname(__filename);
|
|
8
11
|
const EXTENSION_ID = "undefined_publisher.walkthrough-bridge";
|
|
9
12
|
const VSIX_PATH = join(__dirname, "../vscode-extension/walkthrough-bridge.vsix");
|
|
10
|
-
const BRIDGE_URL = "http://127.0.0.1:7890";
|
|
11
13
|
export function ensureExtensionInstalled() {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
catch {
|
|
20
|
-
logger.warn("Could not check installed extensions");
|
|
14
|
+
const clis = resolveAllCodeClis();
|
|
15
|
+
if (clis.length === 0) {
|
|
16
|
+
logger.warn("Could not find VS Code CLI (code, code-insiders, or cursor). Install one or add it to PATH.");
|
|
17
|
+
return;
|
|
21
18
|
}
|
|
22
19
|
if (!existsSync(VSIX_PATH)) {
|
|
23
20
|
logger.error({ path: VSIX_PATH }, "Extension .vsix not found");
|
|
24
21
|
return;
|
|
25
22
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
23
|
+
for (const cli of clis) {
|
|
24
|
+
try {
|
|
25
|
+
const installed = execSync(`"${cli}" --list-extensions`, {
|
|
26
|
+
encoding: "utf-8",
|
|
27
|
+
});
|
|
28
|
+
if (installed.includes(EXTENSION_ID)) {
|
|
29
|
+
logger.info({ cli }, "Walkthrough bridge extension already installed");
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
logger.warn({ cli }, "Could not check installed extensions");
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
execSync(`"${cli}" --install-extension "${VSIX_PATH}"`, {
|
|
38
|
+
encoding: "utf-8",
|
|
39
|
+
});
|
|
40
|
+
logger.info({ cli }, "Installed walkthrough bridge extension");
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
logger.error({ cli, err: error }, "Failed to install extension");
|
|
44
|
+
}
|
|
32
45
|
}
|
|
33
46
|
}
|
|
34
47
|
export let bridgeAvailable = null;
|
|
48
|
+
let socketPath = null;
|
|
35
49
|
export function resetBridgeState() {
|
|
36
50
|
bridgeAvailable = null;
|
|
51
|
+
socketPath = null;
|
|
37
52
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const data = (await res.json());
|
|
46
|
-
bridgeAvailable = data.ok === true;
|
|
53
|
+
// For testing: override socket path discovery
|
|
54
|
+
export function _setSocketPath(path) {
|
|
55
|
+
socketPath = path;
|
|
56
|
+
}
|
|
57
|
+
function resolveSocketPath() {
|
|
58
|
+
if (!socketPath) {
|
|
59
|
+
socketPath = discoverSocket();
|
|
47
60
|
}
|
|
48
|
-
|
|
49
|
-
|
|
61
|
+
return socketPath;
|
|
62
|
+
}
|
|
63
|
+
function socketRequest(endpoint, data = {}) {
|
|
64
|
+
const resolved = resolveSocketPath();
|
|
65
|
+
if (!resolved) {
|
|
66
|
+
return Promise.resolve({
|
|
67
|
+
ok: false,
|
|
68
|
+
error: "No walkthrough bridge socket found. Make sure VS Code is open with a workspace.",
|
|
69
|
+
});
|
|
50
70
|
}
|
|
71
|
+
return new Promise((resolve) => {
|
|
72
|
+
const body = JSON.stringify(data);
|
|
73
|
+
const req = http.request({
|
|
74
|
+
socketPath: resolved,
|
|
75
|
+
path: endpoint,
|
|
76
|
+
method: "POST",
|
|
77
|
+
headers: {
|
|
78
|
+
"Content-Type": "application/json",
|
|
79
|
+
"Content-Length": Buffer.byteLength(body),
|
|
80
|
+
},
|
|
81
|
+
}, (res) => {
|
|
82
|
+
let responseData = "";
|
|
83
|
+
res.on("data", (chunk) => {
|
|
84
|
+
responseData += chunk.toString();
|
|
85
|
+
});
|
|
86
|
+
res.on("end", () => {
|
|
87
|
+
try {
|
|
88
|
+
bridgeAvailable = true;
|
|
89
|
+
resolve(JSON.parse(responseData));
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
resolve({ ok: false, error: "Invalid response from bridge" });
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
req.on("error", () => {
|
|
97
|
+
resolve({
|
|
98
|
+
ok: false,
|
|
99
|
+
error: "Could not reach VS Code. Make sure VS Code is open and reload the window if you just installed mcp-walkthrough.",
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
req.write(body);
|
|
103
|
+
req.end();
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
export async function checkBridge() {
|
|
107
|
+
const result = await socketRequest("/ping");
|
|
108
|
+
bridgeAvailable = result.ok === true;
|
|
51
109
|
logger.info({ bridgeAvailable }, "Bridge status");
|
|
52
110
|
return bridgeAvailable;
|
|
53
111
|
}
|
|
54
112
|
export function isBridgeAvailable() {
|
|
55
113
|
return bridgeAvailable === true;
|
|
56
114
|
}
|
|
57
|
-
async function bridgeRequest(endpoint, data = {}) {
|
|
58
|
-
try {
|
|
59
|
-
const res = await fetch(`${BRIDGE_URL}${endpoint}`, {
|
|
60
|
-
method: "POST",
|
|
61
|
-
headers: { "Content-Type": "application/json" },
|
|
62
|
-
body: JSON.stringify(data),
|
|
63
|
-
});
|
|
64
|
-
bridgeAvailable = true;
|
|
65
|
-
return (await res.json());
|
|
66
|
-
}
|
|
67
|
-
catch {
|
|
68
|
-
return {
|
|
69
|
-
ok: false,
|
|
70
|
-
error: "Could not reach VS Code. Make sure VS Code is open and reload the window if you just installed mcp-walkthrough.",
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
115
|
export async function openFile(file, line, endLine, startChar, endChar) {
|
|
75
|
-
return
|
|
116
|
+
return socketRequest("/open", { file, line, endLine, startChar, endChar });
|
|
76
117
|
}
|
|
77
118
|
export async function showExplanation(file, line, endLine, explanation, title, startChar, endChar) {
|
|
78
|
-
return
|
|
119
|
+
return socketRequest("/explain", {
|
|
79
120
|
file,
|
|
80
121
|
line,
|
|
81
122
|
endLine,
|
|
@@ -86,18 +127,18 @@ export async function showExplanation(file, line, endLine, explanation, title, s
|
|
|
86
127
|
});
|
|
87
128
|
}
|
|
88
129
|
export async function clearExplanations() {
|
|
89
|
-
return
|
|
130
|
+
return socketRequest("/clear");
|
|
90
131
|
}
|
|
91
132
|
export async function startWalkthrough(steps, autoplay, delayMs) {
|
|
92
|
-
return
|
|
133
|
+
return socketRequest("/walkthrough", { steps, autoplay, delayMs });
|
|
93
134
|
}
|
|
94
135
|
export async function navigateWalkthrough(action, step) {
|
|
95
|
-
return
|
|
136
|
+
return socketRequest("/walkthrough/navigate", { action, step });
|
|
96
137
|
}
|
|
97
138
|
export async function getWalkthroughStatus() {
|
|
98
|
-
return
|
|
139
|
+
return socketRequest("/walkthrough/status");
|
|
99
140
|
}
|
|
100
141
|
export async function getSelection() {
|
|
101
|
-
return
|
|
142
|
+
return socketRequest("/selection");
|
|
102
143
|
}
|
|
103
144
|
//# sourceMappingURL=bridge.js.map
|
package/dist/bridge.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bridge.js","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC,MAAM,YAAY,GAAG,wCAAwC,CAAC;AAC9D,MAAM,SAAS,GAAG,IAAI,CACpB,SAAS,EACT,6CAA6C,CAC9C,CAAC;
|
|
1
|
+
{"version":3,"file":"bridge.js","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare function _findAllCodeClis(platform: NodeJS.Platform, findInPath: (name: string) => string | null, fileExists: (path: string) => boolean, listDir: (path: string) => string[], localAppData?: string): string[];
|
|
2
|
+
export declare function resolveAllCodeClis(): string[];
|
|
3
|
+
export declare function resetCodeCliCache(): void;
|
|
4
|
+
//# sourceMappingURL=code-cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code-cli.d.ts","sourceRoot":"","sources":["../src/code-cli.ts"],"names":[],"mappings":"AAkBA,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,MAAM,CAAC,QAAQ,EACzB,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,EAC3C,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,EACrC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,EAAE,EACnC,YAAY,CAAC,EAAE,MAAM,GACpB,MAAM,EAAE,CAiEV;AAgBD,wBAAgB,kBAAkB,IAAI,MAAM,EAAE,CAS7C;AAED,wBAAgB,iBAAiB,IAAI,IAAI,CAExC"}
|
package/dist/code-cli.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { execSync } from "node:child_process";
|
|
2
|
+
import { existsSync, readdirSync } from "node:fs";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
const CLI_NAMES = ["code", "code-insiders", "cursor"];
|
|
6
|
+
function safeListDir(listDir, path) {
|
|
7
|
+
try {
|
|
8
|
+
return listDir(path);
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return [];
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export function _findAllCodeClis(platform, findInPath, fileExists, listDir, localAppData) {
|
|
15
|
+
const found = [];
|
|
16
|
+
for (const name of CLI_NAMES) {
|
|
17
|
+
const p = findInPath(name);
|
|
18
|
+
if (p)
|
|
19
|
+
found.push(p);
|
|
20
|
+
}
|
|
21
|
+
if (platform === "darwin") {
|
|
22
|
+
for (const entry of safeListDir(listDir, "/Applications")) {
|
|
23
|
+
if (!entry.endsWith(".app"))
|
|
24
|
+
continue;
|
|
25
|
+
for (const name of CLI_NAMES) {
|
|
26
|
+
const bin = join("/Applications", entry, "Contents", "Resources", "app", "bin", name);
|
|
27
|
+
if (fileExists(bin))
|
|
28
|
+
found.push(bin);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (platform === "linux") {
|
|
33
|
+
for (const dir of ["/usr/bin", "/usr/local/bin", "/snap/bin"]) {
|
|
34
|
+
for (const name of CLI_NAMES) {
|
|
35
|
+
const bin = join(dir, name);
|
|
36
|
+
if (fileExists(bin))
|
|
37
|
+
found.push(bin);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
for (const entry of safeListDir(listDir, "/opt")) {
|
|
41
|
+
for (const name of CLI_NAMES) {
|
|
42
|
+
const bin = join("/opt", entry, "bin", name);
|
|
43
|
+
if (fileExists(bin))
|
|
44
|
+
found.push(bin);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (platform === "win32") {
|
|
49
|
+
const appData = localAppData ||
|
|
50
|
+
process.env.LOCALAPPDATA ||
|
|
51
|
+
join(homedir(), "AppData", "Local");
|
|
52
|
+
const programsDir = join(appData, "Programs");
|
|
53
|
+
for (const entry of safeListDir(listDir, programsDir)) {
|
|
54
|
+
for (const name of CLI_NAMES) {
|
|
55
|
+
const std = join(programsDir, entry, "bin", `${name}.cmd`);
|
|
56
|
+
if (fileExists(std))
|
|
57
|
+
found.push(std);
|
|
58
|
+
const electron = join(programsDir, entry, "resources", "app", "bin", `${name}.cmd`);
|
|
59
|
+
if (fileExists(electron))
|
|
60
|
+
found.push(electron);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return [...new Set(found)];
|
|
65
|
+
}
|
|
66
|
+
function defaultFindInPath(name) {
|
|
67
|
+
try {
|
|
68
|
+
const cmd = process.platform === "win32" ? "where" : "which";
|
|
69
|
+
return (execSync(`${cmd} ${name}`, { encoding: "utf-8", stdio: "pipe" }).trim() ||
|
|
70
|
+
null);
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
let cached;
|
|
77
|
+
export function resolveAllCodeClis() {
|
|
78
|
+
if (cached !== undefined)
|
|
79
|
+
return cached;
|
|
80
|
+
cached = _findAllCodeClis(process.platform, defaultFindInPath, existsSync, (p) => readdirSync(p));
|
|
81
|
+
return cached;
|
|
82
|
+
}
|
|
83
|
+
export function resetCodeCliCache() {
|
|
84
|
+
cached = undefined;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=code-cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code-cli.js","sourceRoot":"","sources":["../src/code-cli.ts"],"names":[],"mappings":"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"}
|
package/dist/socket.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"socket.d.ts","sourceRoot":"","sources":["../src/socket.ts"],"names":[],"mappings":"AAOA,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAOpD;AAED,wBAAgB,cAAc,CAAC,GAAG,GAAE,MAAsB,GAAG,MAAM,GAAG,IAAI,CAYzE"}
|
package/dist/socket.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
const SOCKET_DIR = "/tmp";
|
|
5
|
+
const SOCKET_PREFIX = "walkthrough-bridge-";
|
|
6
|
+
export function socketPathForDir(dir) {
|
|
7
|
+
const normalized = dir.replace(/\/+$/, "");
|
|
8
|
+
const hash = createHash("sha256")
|
|
9
|
+
.update(normalized)
|
|
10
|
+
.digest("hex")
|
|
11
|
+
.slice(0, 16);
|
|
12
|
+
return join(SOCKET_DIR, `${SOCKET_PREFIX}${hash}.sock`);
|
|
13
|
+
}
|
|
14
|
+
export function discoverSocket(cwd = process.cwd()) {
|
|
15
|
+
let dir = cwd;
|
|
16
|
+
while (true) {
|
|
17
|
+
const socketPath = socketPathForDir(dir);
|
|
18
|
+
if (existsSync(socketPath)) {
|
|
19
|
+
return socketPath;
|
|
20
|
+
}
|
|
21
|
+
const parent = dirname(dir);
|
|
22
|
+
if (parent === dir)
|
|
23
|
+
break;
|
|
24
|
+
dir = parent;
|
|
25
|
+
}
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=socket.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"socket.js","sourceRoot":"","sources":["../src/socket.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE1C,MAAM,UAAU,GAAG,MAAM,CAAC;AAC1B,MAAM,aAAa,GAAG,qBAAqB,CAAC;AAE5C,MAAM,UAAU,gBAAgB,CAAC,GAAW;IAC1C,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC3C,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC;SAC9B,MAAM,CAAC,UAAU,CAAC;SAClB,MAAM,CAAC,KAAK,CAAC;SACb,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAChB,OAAO,IAAI,CAAC,UAAU,EAAE,GAAG,aAAa,GAAG,IAAI,OAAO,CAAC,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAc,OAAO,CAAC,GAAG,EAAE;IACxD,IAAI,GAAG,GAAG,GAAG,CAAC;IACd,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,UAAU,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;QACzC,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC3B,OAAO,UAAU,CAAC;QACpB,CAAC;QACD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,MAAM,KAAK,GAAG;YAAE,MAAM;QAC1B,GAAG,GAAG,MAAM,CAAC;IACf,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-walkthrough",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "MCP server for interactive code walkthroughs - Claude-driven code tours",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
11
|
"dist",
|
|
12
|
+
"scripts/postinstall.cjs",
|
|
12
13
|
"vscode-extension/walkthrough-bridge.vsix",
|
|
13
14
|
"README.md",
|
|
14
15
|
"LICENSE"
|
|
@@ -29,7 +30,7 @@
|
|
|
29
30
|
"scripts": {
|
|
30
31
|
"build": "npm run build:extension && tsc -p tsconfig.build.json",
|
|
31
32
|
"build:extension": "node -e \"const fs=require('fs');const v=require('./package.json').version;const p=JSON.parse(fs.readFileSync('vscode-extension/package.json','utf-8'));p.version=v;fs.writeFileSync('vscode-extension/package.json',JSON.stringify(p,null,2)+'\\n')\" && cd vscode-extension && npm install && npx tsc -p ./ && npx @vscode/vsce package --allow-missing-repository -o walkthrough-bridge.vsix",
|
|
32
|
-
"postinstall": "node
|
|
33
|
+
"postinstall": "node scripts/postinstall.cjs",
|
|
33
34
|
"dev": "bun --watch src/index.ts",
|
|
34
35
|
"start": "node dist/index.js",
|
|
35
36
|
"test": "bun test",
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
const { execSync } = require("node:child_process");
|
|
2
|
+
const { existsSync, readdirSync } = require("node:fs");
|
|
3
|
+
const { join } = require("node:path");
|
|
4
|
+
|
|
5
|
+
const vsixPath = join(
|
|
6
|
+
__dirname,
|
|
7
|
+
"..",
|
|
8
|
+
"vscode-extension",
|
|
9
|
+
"walkthrough-bridge.vsix",
|
|
10
|
+
);
|
|
11
|
+
if (!existsSync(vsixPath)) process.exit(0);
|
|
12
|
+
|
|
13
|
+
const cliNames = ["code", "code-insiders", "cursor"];
|
|
14
|
+
const whichCmd = process.platform === "win32" ? "where" : "which";
|
|
15
|
+
|
|
16
|
+
function safeReaddir(dir) {
|
|
17
|
+
try {
|
|
18
|
+
return readdirSync(dir);
|
|
19
|
+
} catch {
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const found = [];
|
|
25
|
+
|
|
26
|
+
for (const name of cliNames) {
|
|
27
|
+
try {
|
|
28
|
+
const p = execSync(`${whichCmd} ${name}`, {
|
|
29
|
+
encoding: "utf-8",
|
|
30
|
+
stdio: "pipe",
|
|
31
|
+
}).trim();
|
|
32
|
+
if (p) found.push(p);
|
|
33
|
+
} catch {}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (process.platform === "darwin") {
|
|
37
|
+
for (const entry of safeReaddir("/Applications")) {
|
|
38
|
+
if (!entry.endsWith(".app")) continue;
|
|
39
|
+
for (const name of cliNames) {
|
|
40
|
+
const bin = join(
|
|
41
|
+
"/Applications",
|
|
42
|
+
entry,
|
|
43
|
+
"Contents",
|
|
44
|
+
"Resources",
|
|
45
|
+
"app",
|
|
46
|
+
"bin",
|
|
47
|
+
name,
|
|
48
|
+
);
|
|
49
|
+
if (existsSync(bin)) found.push(bin);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (process.platform === "linux") {
|
|
55
|
+
for (const dir of ["/usr/bin", "/usr/local/bin", "/snap/bin"]) {
|
|
56
|
+
for (const name of cliNames) {
|
|
57
|
+
const bin = join(dir, name);
|
|
58
|
+
if (existsSync(bin)) found.push(bin);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
for (const entry of safeReaddir("/opt")) {
|
|
62
|
+
for (const name of cliNames) {
|
|
63
|
+
const bin = join("/opt", entry, "bin", name);
|
|
64
|
+
if (existsSync(bin)) found.push(bin);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (process.platform === "win32") {
|
|
70
|
+
const appData =
|
|
71
|
+
process.env.LOCALAPPDATA ||
|
|
72
|
+
join(require("node:os").homedir(), "AppData", "Local");
|
|
73
|
+
const programsDir = join(appData, "Programs");
|
|
74
|
+
for (const entry of safeReaddir(programsDir)) {
|
|
75
|
+
for (const name of cliNames) {
|
|
76
|
+
const std = join(programsDir, entry, "bin", `${name}.cmd`);
|
|
77
|
+
if (existsSync(std)) found.push(std);
|
|
78
|
+
const electron = join(
|
|
79
|
+
programsDir,
|
|
80
|
+
entry,
|
|
81
|
+
"resources",
|
|
82
|
+
"app",
|
|
83
|
+
"bin",
|
|
84
|
+
`${name}.cmd`,
|
|
85
|
+
);
|
|
86
|
+
if (existsSync(electron)) found.push(electron);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const unique = [...new Set(found)];
|
|
92
|
+
for (const cli of unique) {
|
|
93
|
+
try {
|
|
94
|
+
execSync(`"${cli}" --install-extension "${vsixPath}" --force`, {
|
|
95
|
+
stdio: "ignore",
|
|
96
|
+
});
|
|
97
|
+
} catch {}
|
|
98
|
+
}
|
|
Binary file
|