snatching amp's walkthrough for my own purposes mwhahaha traverse.dunkirk.sh/diagram/6121f05c-a5ef-4ecf-8ffc-02534c5e767c
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: add github links

+33 -6
+1 -1
package.json
··· 1 1 { 2 2 "name": "@taciturnaxolotl/traverse", 3 - "version": "0.1.7", 3 + "version": "0.1.11", 4 4 "description": "Interactive code walkthrough diagrams via MCP", 5 5 "module": "src/index.ts", 6 6 "type": "module",
+15 -1
src/index.ts
··· 14 14 const pkg = await Bun.file(import.meta.dir + "/../package.json").json(); 15 15 return `v${pkg.version}`; 16 16 }); 17 + const GIT_HASH = await Bun.$`git rev-parse HEAD`.text().then(s => s.trim()).catch(() => ""); 18 + const GITHUB_REPO = await Bun.$`git remote get-url origin`.text().then(url => { 19 + url = url.trim(); 20 + // Convert SSH URLs: git@github.com:user/repo.git -> https://github.com/user/repo 21 + const sshMatch = url.match(/^git@github\.com:(.+?)(?:\.git)?$/); 22 + if (sshMatch) return `https://github.com/${sshMatch[1]}`; 23 + // Convert HTTPS URLs: https://github.com/user/repo.git -> https://github.com/user/repo 24 + const httpsMatch = url.match(/^https:\/\/github\.com\/(.+?)(?:\.git)?$/); 25 + if (httpsMatch) return `https://github.com/${httpsMatch[1]}`; 26 + return ""; 27 + }).catch(() => ""); 17 28 initDb(); 18 29 19 30 // Load persisted diagrams ··· 119 130 code: body.code, 120 131 summary: body.summary, 121 132 nodes: body.nodes, 133 + githubRepo: body.githubRepo || undefined, 134 + githubRef: body.githubRef || undefined, 122 135 createdAt: new Date().toISOString(), 123 136 }; 124 137 diagrams.set(id, diagram); ··· 230 243 const res = await fetch(`http://localhost:${PORT}/api/diagrams`, { 231 244 method: "POST", 232 245 headers: { "Content-Type": "application/json" }, 233 - body: JSON.stringify({ code, summary, nodes }), 246 + body: JSON.stringify({ code, summary, nodes, githubRepo: GITHUB_REPO || undefined, githubRef: GIT_HASH || undefined }), 234 247 }); 235 248 if (!res.ok) { 236 249 return { ··· 245 258 code, 246 259 summary, 247 260 nodes, 261 + githubRepo: GITHUB_REPO || undefined, githubRef: GIT_HASH || undefined, 248 262 createdAt: new Date().toISOString(), 249 263 }; 250 264 diagrams.set(id, diagram);
+15 -4
src/template.ts
··· 654 654 655 655 const DIAGRAM_DATA = ${diagramJSON}; 656 656 const PROJECT_ROOT = ${JSON.stringify(projectRoot)}; 657 + const GITHUB_REPO = ${JSON.stringify(diagram.githubRepo || "")}; 658 + const GITHUB_REF = ${JSON.stringify(diagram.githubRef || "main")}; 657 659 const SHARE_SERVER_URL = ${JSON.stringify(shareServerUrl)}; 658 660 const DIAGRAM_ID = ${JSON.stringify(diagramId)}; 659 661 const VIEWER_MODE = ${JSON.stringify(mode)}; ··· 814 816 html += '<ul class="links-list">'; 815 817 meta.links.forEach(link => { 816 818 const href = buildFileUrl(link.label, link.url); 817 - html += '<li><a href="' + escapeAttr(href) + '">' + escapeText(link.label) + "</a></li>"; 819 + const target = GITHUB_REPO ? ' target="_blank" rel="noopener"' : ''; 820 + html += '<li><a href="' + escapeAttr(href) + '"' + target + '>' + escapeText(link.label) + "</a></li>"; 818 821 }); 819 822 html += "</ul>"; 820 823 } ··· 920 923 } 921 924 922 925 function buildFileUrl(label, url) { 923 - // Parse line number from label like "src/index.ts:56-59" or "src/index.ts:56" 924 - const lineMatch = label.match(/:(\d+)/); 926 + // Parse line number from label or url like "src/index.ts:56-59" or "src/index.ts:56" 927 + const lineMatch = label.match(/:(\\d+)(?:-(\\d+))?/) || url.match(/:(\\d+)(?:-(\\d+))?/); 925 928 const line = lineMatch ? lineMatch[1] : "1"; 926 - const filePath = PROJECT_ROOT + "/" + url; 929 + // Strip any :line suffix from url path 930 + const cleanUrl = url.replace(/:[\\d-]+$/, ""); 931 + if (GITHUB_REPO) { 932 + const lineAnchor = lineMatch && lineMatch[2] 933 + ? "?plain=1#L" + lineMatch[1] + "-L" + lineMatch[2] 934 + : "?plain=1#L" + line; 935 + return GITHUB_REPO + "/blob/" + GITHUB_REF + "/" + cleanUrl + lineAnchor; 936 + } 937 + const filePath = PROJECT_ROOT + "/" + cleanUrl; 927 938 return "vscode://file/" + filePath + ":" + line; 928 939 } 929 940
+2
src/types.ts
··· 14 14 code: string; 15 15 summary: string; 16 16 nodes: Record<string, NodeMetadata>; 17 + githubRepo?: string; 18 + githubRef?: string; 17 19 createdAt?: string; 18 20 } 19 21