@@ -64,6 +64,11 @@ func main() {
6464 os .Exit (1 )
6565 }
6666
67+ if err := generateSkeleton (); err != nil {
68+ fmt .Fprintf (os .Stderr , "Error generating skeleton: %v\n " , err )
69+ os .Exit (1 )
70+ }
71+
6772 // Copy CNAME and static root files to site directory
6873 if cname , err := os .ReadFile ("CNAME" ); err == nil {
6974 os .WriteFile ("site/CNAME" , cname , 0644 )
@@ -86,6 +91,13 @@ func generate404() error {
8691` ), 0644 )
8792}
8893
94+ func generateSkeleton () error {
95+ if err := os .MkdirAll ("site/generating" , 0755 ); err != nil {
96+ return err
97+ }
98+ return os .WriteFile ("site/generating/index.html" , []byte (skeletonTemplate ), 0644 )
99+ }
100+
89101func generateSitemap (cfg Config ) error {
90102 var b strings.Builder
91103 b .WriteString (`<?xml version="1.0" encoding="UTF-8"?>` + "\n " )
@@ -99,6 +111,11 @@ func generateSitemap(cfg Config) error {
99111 return os .WriteFile ("site/sitemap.xml" , []byte (b .String ()), 0644 )
100112}
101113
114+ type PageData struct {
115+ Config
116+ Token string
117+ }
118+
102119func generateIndex (cfg Config ) error {
103120 tmpl , err := template .New ("index" ).Funcs (template.FuncMap {
104121 "escape" : html .EscapeString ,
@@ -133,7 +150,7 @@ func generateIndex(cfg Config) error {
133150 }
134151 defer f .Close ()
135152
136- return tmpl .Execute (f , cfg )
153+ return tmpl .Execute (f , PageData { Config : cfg , Token : os . Getenv ( "ISSUES_TOKEN" )} )
137154}
138155
139156const indexTemplate = `<!DOCTYPE html>
@@ -519,7 +536,8 @@ a:focus-visible { outline: 2px solid var(--accent-light); outline-offset: 2px; b
519536 var feedback = document.getElementById('submit-feedback');
520537 var noResultsRequest = document.getElementById('no-results-request');
521538
522- var API_URL = '/api/request';
539+ var GH_TOKEN = '{{.Token}}';
540+ var GH_REPO = 'supermodeltools/supermodeltools.github.io';
523541
524542 // --- Search ---
525543 searchInput.addEventListener('input', function() {
@@ -573,6 +591,11 @@ a:focus-visible { outline: 2px solid var(--accent-light); outline-offset: 2px; b
573591 var parsed = parseRepo(submitInput.value);
574592 if (!parsed) return;
575593
594+ if (!GH_TOKEN) {
595+ showFeedback('Generate is not configured yet.', 'error');
596+ return;
597+ }
598+
576599 var repoUrl = 'https://github.com/' + parsed;
577600 var name = parsed.split('/')[1];
578601
@@ -582,22 +605,30 @@ a:focus-visible { outline: 2px solid var(--accent-light); outline-offset: 2px; b
582605 showFeedback('Setting up ' + name + '...', 'preview');
583606
584607 try {
585- var resp = await fetch(API_URL , {
608+ var resp = await fetch('https://api.github.com/repos/' + GH_REPO + '/issues' , {
586609 method: 'POST',
587- headers: { 'Content-Type': 'application/json' },
588- body: JSON.stringify({ url: repoUrl }),
610+ headers: {
611+ 'Authorization': 'Bearer ' + GH_TOKEN,
612+ 'Accept': 'application/vnd.github+json',
613+ 'Content-Type': 'application/json',
614+ },
615+ body: JSON.stringify({
616+ title: '[Repo Request] ' + name,
617+ body: '### Repository URL\n\n' + repoUrl,
618+ labels: ['repo-request'],
619+ }),
589620 });
590- var data = await resp.json();
591621
592- if (!resp.ok || !data.success) {
593- showFeedback(data.error || 'Something went wrong. Please try again.', 'error');
622+ if (!resp.ok) {
623+ var err = await resp.json().catch(function() { return {}; });
624+ showFeedback(err.message || 'Something went wrong. Please try again.', 'error');
594625 submitBtn.classList.remove('loading');
595626 submitBtn.textContent = 'Generate';
596627 return;
597628 }
598629
599- // Redirect to the skeleton loading page — served by the worker
600- window.location.href = data.generating_url ;
630+ // Redirect to the skeleton loading page
631+ window.location.href = '/generating/?repo=' + encodeURIComponent(name) ;
601632 } catch (e) {
602633 showFeedback('Network error. Please try again.', 'error');
603634 submitBtn.classList.remove('loading');
@@ -624,3 +655,168 @@ a:focus-visible { outline: 2px solid var(--accent-light); outline-offset: 2px; b
624655</html>
625656`
626657
658+ const skeletonTemplate = `<!DOCTYPE html>
659+ <html lang="en">
660+ <head>
661+ <meta charset="utf-8">
662+ <meta name="viewport" content="width=device-width, initial-scale=1">
663+ <title>Generating — Architecture Documentation</title>
664+ <link rel="preconnect" href="https://fonts.googleapis.com">
665+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
666+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
667+ <style>
668+ :root{--bg:#0f1117;--bg-card:#1a1d27;--bg-hover:#22263a;--border:#2a2e3e;--text:#e4e4e7;--text-muted:#9ca3af;--accent:#6366f1;--accent-light:#818cf8;--font:'Inter',-apple-system,BlinkMacSystemFont,sans-serif;--mono:'JetBrains Mono','Fira Code',monospace;--max-w:1200px;--radius:8px}
669+ *{margin:0;padding:0;box-sizing:border-box}html{overflow-x:hidden}
670+ body{font-family:var(--font);background:var(--bg);color:var(--text);line-height:1.6;-webkit-font-smoothing:antialiased;overflow-x:hidden}
671+ a{color:var(--accent-light);text-decoration:none}a:hover{text-decoration:underline}
672+ .container{max-width:var(--max-w);margin:0 auto;padding:0 24px}
673+ .site-header{border-bottom:1px solid var(--border);padding:16px 0;position:sticky;top:0;background:var(--bg);z-index:100}
674+ .site-header .container{display:flex;align-items:center;justify-content:space-between;gap:16px}
675+ .site-brand{font-size:18px;font-weight:700;color:var(--text);display:flex;align-items:center;gap:8px;white-space:nowrap}
676+ .site-brand:hover{text-decoration:none;color:var(--accent-light)}
677+ .site-brand svg{width:24px;height:24px}
678+ .site-nav{display:flex;gap:16px;align-items:center}
679+ .site-nav a,.site-nav span{color:var(--text-muted);font-size:14px;font-weight:500;white-space:nowrap}
680+ .nav-all-repos{color:var(--accent-light)!important;padding-right:12px;margin-right:4px;border-right:1px solid var(--border)}
681+ .hero{padding:48px 0 40px;text-align:center}
682+ .hero h1{font-size:28px;font-weight:700;margin-bottom:12px}
683+ .hero-sub{color:var(--text-muted);font-size:15px;max-width:560px;margin:0 auto 24px}
684+ .hero-actions{display:flex;gap:8px;justify-content:center;margin-bottom:16px}
685+ .hero-btn{display:inline-flex;align-items:center;gap:6px;padding:7px 14px;font-size:13px;font-weight:500;background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius);color:var(--text-muted)}
686+ .hero-stats{display:flex;justify-content:center;gap:28px;flex-wrap:wrap}
687+ .hero-stat{text-align:center}
688+ .hero-stat .label{font-size:12px;color:var(--text-muted)}
689+ @keyframes shimmer{0%{background-position:-400px 0}100%{background-position:400px 0}}
690+ .shim{background:linear-gradient(90deg,var(--bg-card) 25%,var(--bg-hover) 50%,var(--bg-card) 75%);background-size:800px 100%;animation:shimmer 1.8s ease-in-out infinite;border-radius:4px}
691+ .shim-num{width:48px;height:28px;margin:0 auto 4px;border-radius:4px}
692+ .chart-panel{background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius);padding:24px;margin-bottom:24px}
693+ .chart-panel h3{font-size:16px;font-weight:600;margin-bottom:16px}
694+ .shim-chart{height:280px;border-radius:var(--radius)}
695+ .section{margin-bottom:40px}
696+ .section-title{font-size:20px;font-weight:700;margin-bottom:12px}
697+ .tax-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:8px}
698+ .tax-entry-skel{display:flex;align-items:center;justify-content:space-between;padding:10px 14px;background:var(--bg-card);border:1px solid var(--border);border-radius:6px}
699+ .shim-entry-name{width:60%;height:14px}
700+ .shim-entry-count{width:28px;height:14px}
701+ .gen-status{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);background:var(--bg-card);border:1px solid var(--border);border-radius:12px;padding:14px 24px;display:flex;align-items:center;gap:14px;font-size:14px;color:var(--text);box-shadow:0 8px 32px rgba(0,0,0,0.4);z-index:200;max-width:90vw}
702+ .gen-spinner{width:18px;height:18px;flex-shrink:0;border:2px solid var(--border);border-top-color:var(--accent-light);border-radius:50%;animation:spin .8s linear infinite}
703+ @keyframes spin{to{transform:rotate(360deg)}}
704+ .gen-step{color:var(--text-muted)}.gen-step strong{color:var(--text)}
705+ .site-footer{border-top:1px solid var(--border);padding:32px 0;margin-top:48px;color:var(--text-muted);font-size:13px;text-align:center}
706+ @media(max-width:768px){.container{padding:0 16px}.hero{padding:32px 0 24px}.hero h1{font-size:22px}.hero-stats{gap:16px}.tax-grid{grid-template-columns:1fr}.gen-status{bottom:12px;padding:10px 16px;font-size:13px}}
707+ </style>
708+ </head>
709+ <body>
710+ <header class="site-header">
711+ <div class="container">
712+ <span class="site-brand" id="brand">
713+ <svg viewBox="0 0 90 78" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M90 61.1124C75.9375 73.4694 59.8419 78 44.7554 78C29.669 78 11.8614 72.6122 0 61.1011V16.9458C11.6168 6 29.891 0 44.9887 0C62.77 0 78.8723 6.97959 89.9887 16.9458V61.1124H90ZM88.1881 38.9553C77.7923 22.8824 59.8983 15.7959 44.7554 15.7959C29.6126 15.7959 13.4515 21.9008 1.556 38.9444C12.5382 54.69 26.9 62.5085 44.7554 62.0944C67.6297 61.5639 77.6495 51.9184 88.1881 38.9553ZM44.7554 16.3475C32.4756 16.3475 22.3888 26.6879 22.2554 38.9388C34.3765 38.9162 44.7554 29.1429 44.7554 16.3475C44.7554 29.1429 55.1344 38.9162 67.2554 38.9388C67.1202 26.5216 57.1141 16.3475 44.7554 16.3475ZM44.7554 61.5639C44.7554 48.4898 34.3765 38.9613 22.2554 38.9388C22.3888 51.1897 32.4756 61.5639 44.7554 61.5639C57.0352 61.5639 67.122 51.1897 67.2554 38.9388C55.1344 38.9613 44.7554 48.4898 44.7554 61.5639Z" fill="currentColor"/></svg>
714+ <span id="brand-name"></span>
715+ </span>
716+ <nav class="site-nav">
717+ <a href="https://repos.supermodeltools.com/" class="nav-all-repos">← All Repos</a>
718+ <span>By Type</span><span>Domains</span><span>Languages</span><span>Tags</span>
719+ </nav>
720+ </div>
721+ </header>
722+ <main>
723+ <div class="container">
724+ <div class="hero">
725+ <h1 id="hero-title"></h1>
726+ <div class="hero-actions">
727+ <span class="hero-btn">View on GitHub</span>
728+ <span class="hero-btn">Star</span>
729+ <span class="hero-btn">Fork</span>
730+ </div>
731+ <p class="hero-sub">Architecture documentation generated from code analysis. Explore every file, function, class, and domain.</p>
732+ <div class="hero-stats">
733+ <div class="hero-stat"><div class="shim shim-num"></div><div class="label">Total Entities</div></div>
734+ <div class="hero-stat"><div class="shim shim-num"></div><div class="label">Node Types</div></div>
735+ <div class="hero-stat"><div class="shim shim-num"></div><div class="label">Languages</div></div>
736+ <div class="hero-stat"><div class="shim shim-num"></div><div class="label">Domains</div></div>
737+ <div class="hero-stat"><div class="shim shim-num"></div><div class="label">Subdomains</div></div>
738+ <div class="hero-stat"><div class="shim shim-num"></div><div class="label">Top Directories</div></div>
739+ </div>
740+ </div>
741+ <div class="chart-panel"><h3>Architecture Overview</h3><div class="shim shim-chart"></div></div>
742+ <div class="chart-panel"><h3>Codebase Composition</h3><div class="shim shim-chart" style="height:200px"></div></div>
743+ <div class="section"><h2 class="section-title">Node Types</h2><div class="tax-grid">
744+ <div class="tax-entry-skel"><div class="shim shim-entry-name"></div><div class="shim shim-entry-count"></div></div>
745+ <div class="tax-entry-skel"><div class="shim shim-entry-name"></div><div class="shim shim-entry-count"></div></div>
746+ <div class="tax-entry-skel"><div class="shim shim-entry-name"></div><div class="shim shim-entry-count"></div></div>
747+ <div class="tax-entry-skel"><div class="shim shim-entry-name"></div><div class="shim shim-entry-count"></div></div>
748+ <div class="tax-entry-skel"><div class="shim shim-entry-name"></div><div class="shim shim-entry-count"></div></div>
749+ <div class="tax-entry-skel"><div class="shim shim-entry-name"></div><div class="shim shim-entry-count"></div></div>
750+ </div></div>
751+ <div class="section"><h2 class="section-title">Domains</h2><div class="tax-grid">
752+ <div class="tax-entry-skel"><div class="shim shim-entry-name"></div><div class="shim shim-entry-count"></div></div>
753+ <div class="tax-entry-skel"><div class="shim shim-entry-name"></div><div class="shim shim-entry-count"></div></div>
754+ <div class="tax-entry-skel"><div class="shim shim-entry-name"></div><div class="shim shim-entry-count"></div></div>
755+ <div class="tax-entry-skel"><div class="shim shim-entry-name"></div><div class="shim shim-entry-count"></div></div>
756+ </div></div>
757+ <div class="section"><h2 class="section-title">Languages</h2><div class="tax-grid">
758+ <div class="tax-entry-skel"><div class="shim shim-entry-name"></div><div class="shim shim-entry-count"></div></div>
759+ <div class="tax-entry-skel"><div class="shim shim-entry-name"></div><div class="shim shim-entry-count"></div></div>
760+ <div class="tax-entry-skel"><div class="shim shim-entry-name"></div><div class="shim shim-entry-count"></div></div>
761+ </div></div>
762+ </div>
763+ </main>
764+ <footer class="site-footer"><div class="container"><p>Generated with <a href="https://github.com/supermodeltools/arch-docs">arch-docs</a> by <a href="https://supermodeltools.com">supermodeltools</a></p></div></footer>
765+ <div class="gen-status" id="gen-status">
766+ <div class="gen-spinner"></div>
767+ <div class="gen-step" id="gen-step"><strong>Generating docs</strong> — forking repository…</div>
768+ </div>
769+ <script>
770+ (function() {
771+ var params = new URLSearchParams(window.location.search);
772+ var name = params.get('repo') || 'repository';
773+ var docsUrl = 'https://repos.supermodeltools.com/' + encodeURIComponent(name) + '/';
774+
775+ document.getElementById('brand-name').textContent = name;
776+ document.getElementById('hero-title').textContent = name;
777+ document.title = 'Generating ' + name + ' \u2014 Architecture Documentation';
778+
779+ var statusEl = document.getElementById('gen-step');
780+ var messages = [
781+ { text: '<strong>Generating docs</strong> \u2014 forking repository\u2026', at: 0 },
782+ { text: '<strong>Generating docs</strong> \u2014 analyzing codebase\u2026', at: 8000 },
783+ { text: '<strong>Generating docs</strong> \u2014 building code graphs\u2026', at: 35000 },
784+ { text: '<strong>Generating docs</strong> \u2014 mapping architecture\u2026', at: 60000 },
785+ { text: '<strong>Generating docs</strong> \u2014 deploying site\u2026', at: 90000 },
786+ { text: '<strong>Almost there</strong> \u2014 finalizing\u2026', at: 120000 },
787+ ];
788+ messages.forEach(function(m) {
789+ setTimeout(function() { statusEl.innerHTML = m.text; }, m.at);
790+ });
791+
792+ var pollCount = 0;
793+ var maxPolls = 120;
794+ function poll() {
795+ pollCount++;
796+ if (pollCount > maxPolls) {
797+ statusEl.innerHTML = '<strong>Still working</strong> \u2014 this repo may be large. <a href="' + docsUrl + '">Check manually \u2192</a>';
798+ return;
799+ }
800+ fetch(docsUrl, { cache: 'no-store', redirect: 'follow' })
801+ .then(function(resp) {
802+ if (resp.ok) {
803+ return resp.text().then(function(html) {
804+ if (html.indexOf('arch-docs') !== -1 && html.indexOf('gen-status') === -1) {
805+ statusEl.innerHTML = '<strong>Ready!</strong> Loading docs\u2026';
806+ setTimeout(function() { window.location.href = docsUrl; }, 600);
807+ return;
808+ }
809+ setTimeout(poll, 5000);
810+ });
811+ }
812+ setTimeout(poll, 5000);
813+ })
814+ .catch(function() { setTimeout(poll, 5000); });
815+ }
816+ setTimeout(poll, 5000);
817+ })();
818+ </script>
819+ </body>
820+ </html>
821+ `
822+
0 commit comments