@taciturnaxolotl/traverse 0.1.6 → 0.1.8

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/package.json CHANGED
@@ -1,31 +1,32 @@
1
1
  {
2
- "name": "@taciturnaxolotl/traverse",
3
- "version": "0.1.6",
4
- "description": "Interactive code walkthrough diagrams via MCP",
5
- "module": "src/index.ts",
6
- "type": "module",
7
- "bin": {
8
- "traverse": "./bin/traverse.cjs"
9
- },
10
- "files": [
11
- "src",
12
- "bin",
13
- "fonts",
14
- "icon.svg"
15
- ],
16
- "scripts": {
17
- "start": "bun run src/index.ts",
18
- "dev": "bun --hot run src/index.ts"
19
- },
20
- "devDependencies": {
21
- "@types/bun": "latest"
22
- },
23
- "peerDependencies": {
24
- "typescript": "^5"
25
- },
26
- "dependencies": {
27
- "@modelcontextprotocol/sdk": "^1.26.0",
28
- "@resvg/resvg-wasm": "^2.6.2",
29
- "satori": "^0.19.1"
30
- }
2
+ "name": "@taciturnaxolotl/traverse",
3
+ "version": "0.1.8",
4
+ "description": "Interactive code walkthrough diagrams via MCP",
5
+ "module": "src/index.ts",
6
+ "type": "module",
7
+ "bin": {
8
+ "traverse": "bin/traverse.cjs"
9
+ },
10
+ "files": [
11
+ "src",
12
+ "bin",
13
+ "fonts",
14
+ "vendor",
15
+ "icon.svg"
16
+ ],
17
+ "scripts": {
18
+ "start": "bun run src/index.ts",
19
+ "dev": "bun --hot run src/index.ts"
20
+ },
21
+ "devDependencies": {
22
+ "@types/bun": "latest"
23
+ },
24
+ "peerDependencies": {
25
+ "typescript": "^5"
26
+ },
27
+ "dependencies": {
28
+ "@modelcontextprotocol/sdk": "^1.26.0",
29
+ "@resvg/resvg-wasm": "^2.6.2",
30
+ "satori": "^0.19.1"
31
+ }
31
32
  }
package/src/index.ts CHANGED
@@ -14,6 +14,16 @@ const VERSION = await Bun.$`git rev-parse --short HEAD`.text().then(s => s.trim(
14
14
  const pkg = await Bun.file(import.meta.dir + "/../package.json").json();
15
15
  return `v${pkg.version}`;
16
16
  });
17
+ const GITHUB_REPO = await Bun.$`git remote get-url origin`.text().then(url => {
18
+ url = url.trim();
19
+ // Convert SSH URLs: git@github.com:user/repo.git -> https://github.com/user/repo
20
+ const sshMatch = url.match(/^git@github\.com:(.+?)(?:\.git)?$/);
21
+ if (sshMatch) return `https://github.com/${sshMatch[1]}`;
22
+ // Convert HTTPS URLs: https://github.com/user/repo.git -> https://github.com/user/repo
23
+ const httpsMatch = url.match(/^https:\/\/github\.com\/(.+?)(?:\.git)?$/);
24
+ if (httpsMatch) return `https://github.com/${httpsMatch[1]}`;
25
+ return "";
26
+ }).catch(() => "");
17
27
  initDb();
18
28
 
19
29
  // Load persisted diagrams
@@ -119,6 +129,7 @@ try {
119
129
  code: body.code,
120
130
  summary: body.summary,
121
131
  nodes: body.nodes,
132
+ githubRepo: body.githubRepo || undefined,
122
133
  createdAt: new Date().toISOString(),
123
134
  };
124
135
  diagrams.set(id, diagram);
@@ -230,7 +241,7 @@ Then build the diagram:
230
241
  const res = await fetch(`http://localhost:${PORT}/api/diagrams`, {
231
242
  method: "POST",
232
243
  headers: { "Content-Type": "application/json" },
233
- body: JSON.stringify({ code, summary, nodes }),
244
+ body: JSON.stringify({ code, summary, nodes, githubRepo: GITHUB_REPO || undefined }),
234
245
  });
235
246
  if (!res.ok) {
236
247
  return {
@@ -245,6 +256,7 @@ Then build the diagram:
245
256
  code,
246
257
  summary,
247
258
  nodes,
259
+ githubRepo: GITHUB_REPO || undefined,
248
260
  createdAt: new Date().toISOString(),
249
261
  };
250
262
  diagrams.set(id, diagram);
package/src/og.ts CHANGED
@@ -10,38 +10,32 @@ const [interRegular, interBold] = await Promise.all([
10
10
  ]);
11
11
 
12
12
  // Initialize resvg-wasm
13
- // Use import.meta.resolve to find the package, then locate the WASM file
14
- let wasmPath: string;
15
- try {
16
- // Try to resolve the @resvg/resvg-wasm package
17
- const resvgPath = import.meta.resolve("@resvg/resvg-wasm");
18
- // The resolved path will be something like file:///path/to/node_modules/@resvg/resvg-wasm/index.js
19
- // Extract the directory and append the WASM file
20
- const resvgDir = new URL(".", resvgPath).pathname;
21
- wasmPath = join(resvgDir, "index_bg.wasm");
22
- } catch {
23
- // Fallback to manual path resolution if import.meta.resolve fails
24
- const possiblePaths = [
25
- join(import.meta.dir, "../node_modules/@resvg/resvg-wasm/index_bg.wasm"),
26
- join(import.meta.dir, "../../@resvg/resvg-wasm/index_bg.wasm"),
27
- join(import.meta.dir, "../../../@resvg/resvg-wasm/index_bg.wasm"),
28
- ];
13
+ // Try bundled WASM first, then fall back to node_modules
14
+ const possiblePaths = [
15
+ // Bundled WASM file (most reliable)
16
+ join(import.meta.dir, "../vendor/index_bg.wasm"),
17
+ // Development: node_modules is a sibling of src
18
+ join(import.meta.dir, "../node_modules/@resvg/resvg-wasm/index_bg.wasm"),
19
+ // Installed: in parent node_modules
20
+ join(import.meta.dir, "../../@resvg/resvg-wasm/index_bg.wasm"),
21
+ join(import.meta.dir, "../../../@resvg/resvg-wasm/index_bg.wasm"),
22
+ ];
29
23
 
30
- for (const path of possiblePaths) {
31
- if (await Bun.file(path).exists()) {
32
- wasmPath = path;
33
- break;
34
- }
24
+ let wasmPath: string | undefined;
25
+ for (const path of possiblePaths) {
26
+ if (await Bun.file(path).exists()) {
27
+ wasmPath = path;
28
+ break;
35
29
  }
30
+ }
36
31
 
37
- if (!wasmPath!) {
38
- console.error("Failed to find @resvg/resvg-wasm WASM file. Tried:");
39
- for (const path of possiblePaths) {
40
- console.error(` - ${path}`);
41
- }
42
- console.error(`\nCurrent directory: ${import.meta.dir}`);
43
- throw new Error("Could not find @resvg/resvg-wasm WASM file");
32
+ if (!wasmPath) {
33
+ console.error("Failed to find @resvg/resvg-wasm WASM file. Tried:");
34
+ for (const path of possiblePaths) {
35
+ console.error(` - ${path}`);
44
36
  }
37
+ console.error(`\nCurrent directory: ${import.meta.dir}`);
38
+ throw new Error("Could not find @resvg/resvg-wasm WASM file");
45
39
  }
46
40
 
47
41
  await initWasm(Bun.file(wasmPath).arrayBuffer());
package/src/template.ts CHANGED
@@ -654,6 +654,7 @@ export function generateViewerHTML(diagram: WalkthroughDiagram, gitHash: string
654
654
 
655
655
  const DIAGRAM_DATA = ${diagramJSON};
656
656
  const PROJECT_ROOT = ${JSON.stringify(projectRoot)};
657
+ const GITHUB_REPO = ${JSON.stringify(diagram.githubRepo || "")};
657
658
  const SHARE_SERVER_URL = ${JSON.stringify(shareServerUrl)};
658
659
  const DIAGRAM_ID = ${JSON.stringify(diagramId)};
659
660
  const VIEWER_MODE = ${JSON.stringify(mode)};
@@ -814,7 +815,8 @@ export function generateViewerHTML(diagram: WalkthroughDiagram, gitHash: string
814
815
  html += '<ul class="links-list">';
815
816
  meta.links.forEach(link => {
816
817
  const href = buildFileUrl(link.label, link.url);
817
- html += '<li><a href="' + escapeAttr(href) + '">' + escapeText(link.label) + "</a></li>";
818
+ const target = GITHUB_REPO ? ' target="_blank" rel="noopener"' : '';
819
+ html += '<li><a href="' + escapeAttr(href) + '"' + target + '>' + escapeText(link.label) + "</a></li>";
818
820
  });
819
821
  html += "</ul>";
820
822
  }
@@ -921,8 +923,15 @@ export function generateViewerHTML(diagram: WalkthroughDiagram, gitHash: string
921
923
 
922
924
  function buildFileUrl(label, url) {
923
925
  // Parse line number from label like "src/index.ts:56-59" or "src/index.ts:56"
924
- const lineMatch = label.match(/:(\d+)/);
926
+ const lineMatch = label.match(/:(\d+)(?:-(\d+))?/);
925
927
  const line = lineMatch ? lineMatch[1] : "1";
928
+ if (GITHUB_REPO) {
929
+ // Build GitHub link: https://github.com/user/repo/blob/HEAD/path#L1-L5
930
+ const lineAnchor = lineMatch && lineMatch[2]
931
+ ? "#L" + lineMatch[1] + "-L" + lineMatch[2]
932
+ : "#L" + line;
933
+ return GITHUB_REPO + "/blob/HEAD/" + url + lineAnchor;
934
+ }
926
935
  const filePath = PROJECT_ROOT + "/" + url;
927
936
  return "vscode://file/" + filePath + ":" + line;
928
937
  }
package/src/types.ts CHANGED
@@ -14,6 +14,7 @@ export interface WalkthroughDiagram {
14
14
  code: string;
15
15
  summary: string;
16
16
  nodes: Record<string, NodeMetadata>;
17
+ githubRepo?: string;
17
18
  createdAt?: string;
18
19
  }
19
20
 
Binary file