| 1 | <div class="home"> |
| 2 | <div class="home-logo"> |
| 3 | <svg class="home-shuriken-svg" viewBox="0 0 100 100" aria-hidden="true"> |
| 4 | <polygon points="50,5 55,40 95,50 60,55 50,95 45,60 5,50 40,45" fill="var(--text-muted)"/> |
| 5 | <circle cx="50" cy="50" r="4" fill="var(--bg)"/> |
| 6 | </svg> |
| 7 | <pre class="home-title"> |
| 8 | _ _ _ _ |
| 9 | _ _ ___ __| |__ __| |_ __ _ _ _ _ _ (_)_ _ (_)__ _ |
| 10 | | '_/ _ \/ _| / /(_-< _/ _` | '_|| ' \| | ' \ | / _` | |
| 11 | |_| \___/\__|_\_\/__/\__\__,_|_|(_)_||_|_|_||_|/ \__,_| |
| 12 | |__/ |
| 13 | </pre> |
| 14 | </div> |
| 15 | |
| 16 | <p class="home-tagline">share your <a href="https://claude.ai/code">Claude Code</a> sessions and plans.</p> |
| 17 | |
| 18 | <div class="home-install"> |
| 19 | <div class="home-install-label">$ install</div> |
| 20 | <div class="home-install-row"> |
| 21 | <code class="home-install-cmd">curl -fsSL https://rockstar.ninja/install.sh | sh</code> |
| 22 | <button class="home-copy-btn" id="copy-install" aria-label="Copy to clipboard"> |
| 23 | <span id="copy-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg></span> |
| 24 | </button> |
| 25 | </div> |
| 26 | </div> |
| 27 | |
| 28 | <div class="home-features"> |
| 29 | <div class="home-feature"><span class="home-bullet">></span> push sessions and plans from the CLI</div> |
| 30 | <div class="home-feature"><span class="home-bullet">></span> rendered with syntax highlighting and tool call diffs</div> |
| 31 | <div class="home-feature"><span class="home-bullet">></span> live emoji reactions via WebSocket</div> |
| 32 | <div class="home-feature"><span class="home-bullet">></span> auto-expiring links, secret redaction</div> |
| 33 | <div class="home-feature"><span class="home-bullet">></span> no tracking, no cookies, no third parties</div> |
| 34 | </div> |
| 35 | |
| 36 | <div class="home-demo"> |
| 37 | <div class="home-demo-label">$ demo</div> |
| 38 | <div class="term" id="term"> |
| 39 | <div class="term-chrome"> |
| 40 | <span class="term-dot term-dot-red"></span> |
| 41 | <span class="term-dot term-dot-yellow"></span> |
| 42 | <span class="term-dot term-dot-green"></span> |
| 43 | <span class="term-title">rn</span> |
| 44 | </div> |
| 45 | <div class="term-body" id="term-body"> |
| 46 | <div id="term-output"></div> |
| 47 | <div class="term-input-line"> |
| 48 | <span class="term-prompt">$ </span> |
| 49 | <span class="term-input" id="term-input"></span> |
| 50 | <span class="term-cursor" id="term-cursor"></span> |
| 51 | </div> |
| 52 | </div> |
| 53 | </div> |
| 54 | <div class="term-hint" id="term-hint"></div> |
| 55 | </div> |
| 56 | </div> |
| 57 | <script> |
| 58 | document.getElementById('copy-install').addEventListener('click',function(){ |
| 59 | var t='curl -fsSL https://rockstar.ninja/install.sh | sh'; |
| 60 | navigator.clipboard.writeText(t).then(function(){ |
| 61 | var i=document.getElementById('copy-icon'); |
| 62 | i.innerHTML='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>'; |
| 63 | setTimeout(function(){i.innerHTML='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>'},1500) |
| 64 | }) |
| 65 | }); |
| 66 | </script> |
| 67 | <script> |
| 68 | (function(){ |
| 69 | var output=document.getElementById('term-output'); |
| 70 | var input=document.getElementById('term-input'); |
| 71 | var body=document.getElementById('term-body'); |
| 72 | var hint=document.getElementById('term-hint'); |
| 73 | var buf=''; |
| 74 | var locked=true; |
| 75 | var hist=[]; |
| 76 | var hIdx=-1; |
| 77 | var mobile=window.innerWidth<768; |
| 78 | // Braille spinner frames (charmbracelet/bubbles spinner.Dot) |
| 79 | var spin='\u28fe\u28fd\u28fb\u28bf\u287f\u289f\u28af\u28f7'; |
| 80 | |
| 81 | function esc(s){return s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>')} |
| 82 | function S(cls,t){return'<span class="term-s-'+cls+'">'+esc(t)+'</span>'} |
| 83 | |
| 84 | function addLine(cls,text){ |
| 85 | var d=document.createElement('div'); |
| 86 | d.className='term-line term-line-'+cls; |
| 87 | d.textContent=text; |
| 88 | output.appendChild(d); |
| 89 | body.scrollTop=body.scrollHeight; |
| 90 | } |
| 91 | |
| 92 | function addHtml(cls,html){ |
| 93 | var d=document.createElement('div'); |
| 94 | d.className='term-line'+(cls?' term-line-'+cls:''); |
| 95 | d.innerHTML=html; |
| 96 | output.appendChild(d); |
| 97 | body.scrollTop=body.scrollHeight; |
| 98 | } |
| 99 | |
| 100 | function addPrompt(cmd){ |
| 101 | addHtml('','<span class="term-line-prompt">$ </span><span class="term-line-cmd">'+esc(cmd)+'</span>'); |
| 102 | } |
| 103 | |
| 104 | // Mock data — structured for sort/filter/reverse |
| 105 | var remote={'calm-silver-mountain':{v:1,p:'public',u:'rockstar.ninja/p/mT7nX3qR'}}; |
| 106 | var sessions=[ |
| 107 | {n:'add-mock-terminal',id:'a1b2c3d4-e5f6-7890-abcd-ef1234567890',d:'2024-02-24',ds:'Feb 24',sz:145408,ss:'142 KB',t:47,ts:' 47t',b:'main',pj:'rockstar.ninja'}, |
| 108 | {n:'fix-websocket-reconnect',id:'b2c3d4e5-f6a7-8901-bcde-f12345678901',d:'2024-02-22',ds:'Feb 22',sz:91136,ss:' 89 KB',t:23,ts:' 23t',b:'main',pj:'rockstar.ninja'}, |
| 109 | {n:'implement-og-images',id:'c3d4e5f6-a7b8-9012-cdef-123456789012',d:'2024-02-20',ds:'Feb 20',sz:208896,ss:'204 KB',t:61,ts:' 61t',b:'feat/og',pj:'rockstar.ninja'}, |
| 110 | {n:'add-rate-limiting',id:'d4e5f6a7-b8c9-0123-defa-234567890123',d:'2024-02-18',ds:'Feb 18',sz:68608,ss:' 67 KB',t:19,ts:' 19t',b:'main',pj:'bewitch'}, |
| 111 | {n:'refactor-auth-flow',id:'e5f6a7b8-c9d0-1234-efab-345678901234',d:'2024-02-15',ds:'Feb 15',sz:319488,ss:'312 KB',t:84,ts:' 84t',b:'feat/auth',pj:'bewitch'}, |
| 112 | {n:'setup-ci-pipeline',id:'f6a7b8c9-d0e1-2345-fabc-456789012345',d:'2024-02-12',ds:'Feb 12',sz:46080,ss:' 45 KB',t:12,ts:' 12t',b:'main',pj:'bewitch'} |
| 113 | ]; |
| 114 | var plans=[ |
| 115 | {n:'fancy-dazzling-pumpkin',d:'2024-02-24',ds:'Feb 24',sz:4300,ss:'4.2 KB'}, |
| 116 | {n:'calm-silver-mountain',d:'2024-02-21',ds:'Feb 21',sz:2867,ss:'2.8 KB'}, |
| 117 | {n:'bold-crimson-falcon',d:'2024-02-17',ds:'Feb 17',sz:6246,ss:'6.1 KB'}, |
| 118 | {n:'swift-azure-thunder',d:'2024-02-10',ds:'Feb 10',sz:1536,ss:'1.5 KB'} |
| 119 | ]; |
| 120 | |
| 121 | function parseFlags(parts,path){ |
| 122 | var defs=flagDefs[path]||{}; |
| 123 | var shorts={};for(var k in defs)if(defs[k].s)shorts[defs[k].s]=k; |
| 124 | var f={};for(var k in defs){ |
| 125 | if(defs[k].t==='b')f[k]=false; |
| 126 | else if(defs[k].t==='i')f[k]=defs[k].d?parseInt(defs[k].d):0; |
| 127 | else if(defs[k].t==='a')f[k]=[]; |
| 128 | else f[k]=defs[k].d||'';} |
| 129 | var args=[]; |
| 130 | for(var i=0;i<parts.length;i++){ |
| 131 | var p=parts[i]; |
| 132 | if(p==='--help'||p==='-h'){f._help=true;continue} |
| 133 | if(p.charAt(0)==='-'&&p.length>1&&p.charAt(1)==='-'){ |
| 134 | var eq=p.indexOf('=');var nm=eq>=0?p.substring(2,eq):p.substring(2); |
| 135 | var def=defs[nm];if(!def)continue; |
| 136 | if(def.t==='b')f[nm]=true; |
| 137 | else if(def.t==='a'){f[nm].push(eq>=0?p.substring(eq+1):(parts[++i]||''))} |
| 138 | else{f[nm]=eq>=0?p.substring(eq+1):(parts[++i]||'');if(def.t==='i')f[nm]=parseInt(f[nm])||0} |
| 139 | }else if(p.charAt(0)==='-'&&p.length===2){ |
| 140 | var ln=shorts[p.charAt(1)];if(!ln)continue;var def=defs[ln]; |
| 141 | if(def.t==='b')f[ln]=true; |
| 142 | else if(def.t==='a'){f[ln].push(parts[++i]||'')} |
| 143 | else{f[ln]=parts[++i]||'';if(def.t==='i')f[ln]=parseInt(f[ln])||0} |
| 144 | }else args.push(p)} |
| 145 | f._args=args;return f} |
| 146 | |
| 147 | function pad(s,n){while(s.length<n)s+=' ';return s} |
| 148 | |
| 149 | function sRow(s){ |
| 150 | var h=' '+S('blue',pad(s.n,28))+' '+S('dim',s.id)+' '+S('dim',s.ds)+' '+S('dim',s.ss)+' '+S('dim',s.ts)+' '+S('dim',s.b); |
| 151 | var r=remote[s.n]; |
| 152 | if(r){h+=' '+S(r.p==='public'?'green':'yellow','v'+r.v+' '+r.p)+' '+S('dim',r.u)} |
| 153 | return['html','',h]} |
| 154 | |
| 155 | function pRow(p){ |
| 156 | var h=' '+S('blue',pad(p.n,32))+' '+S('dim',p.ds)+' '+S('dim',p.ss); |
| 157 | var r=remote[p.n]; |
| 158 | if(r){h+=' '+S(r.p==='public'?'green':'yellow','v'+r.v+' '+r.p)+' '+S('dim',r.u)} |
| 159 | return['html','',h]} |
| 160 | |
| 161 | function sessionList(f){ |
| 162 | var items=sessions.slice(); |
| 163 | if(!f.all)items=items.filter(function(s){return s.pj==='rockstar.ninja'}); |
| 164 | if(f.branch)items=items.filter(function(s){return s.b===f.branch}); |
| 165 | if(f.search){var q=f.search.toLowerCase();items=items.filter(function(s){ |
| 166 | return s.n.toLowerCase().indexOf(q)>=0||s.id.indexOf(q)>=0})} |
| 167 | if(f.pushed)items=items.filter(function(s){return!!remote[s.n]}); |
| 168 | else if(f.local)items=items.filter(function(s){return!remote[s.n]}); |
| 169 | var field=f.sort||'date'; |
| 170 | items.sort(function(a,b){var c=0; |
| 171 | if(field==='date')c=a.d<b.d?-1:a.d>b.d?1:0; |
| 172 | else if(field==='size')c=a.sz-b.sz; |
| 173 | else if(field==='turns')c=a.t-b.t; |
| 174 | else if(field==='name')c=a.n<b.n?-1:a.n>b.n?1:0; |
| 175 | if(field==='date')c=-c;if(f.reverse)c=-c;return c}); |
| 176 | if(f.limit>0)items=items.slice(0,f.limit); |
| 177 | if(!items.length)return[['output','No sessions match the given filters']]; |
| 178 | var groups={},order=[]; |
| 179 | for(var i=0;i<items.length;i++){var pj=items[i].pj; |
| 180 | if(!groups[pj]){groups[pj]=[];order.push(pj)}groups[pj].push(items[i])} |
| 181 | var rows=[]; |
| 182 | for(var g=0;g<order.length;g++){ |
| 183 | if(g>0)rows.push(['output','']);var grp=groups[order[g]]; |
| 184 | var cl=grp.length===1?'1 session':grp.length+' sessions'; |
| 185 | rows.push(['html','bold','<span class="term-line-bold">'+esc(order[g])+'</span> '+S('dim',cl)]); |
| 186 | for(var i=0;i<grp.length;i++)rows.push(sRow(grp[i]))} |
| 187 | return rows} |
| 188 | |
| 189 | function planList(f){ |
| 190 | var items=plans.slice(); |
| 191 | if(f.search){var q=f.search.toLowerCase();items=items.filter(function(p){ |
| 192 | return p.n.toLowerCase().indexOf(q)>=0})} |
| 193 | if(f.pushed)items=items.filter(function(p){return!!remote[p.n]}); |
| 194 | else if(f.local)items=items.filter(function(p){return!remote[p.n]}); |
| 195 | var field=f.sort||'date'; |
| 196 | items.sort(function(a,b){var c=0; |
| 197 | if(field==='date')c=a.d<b.d?-1:a.d>b.d?1:0; |
| 198 | else if(field==='size')c=a.sz-b.sz; |
| 199 | else if(field==='name')c=a.n<b.n?-1:a.n>b.n?1:0; |
| 200 | if(field==='date')c=-c;if(f.reverse)c=-c;return c}); |
| 201 | if(f.limit>0)items=items.slice(0,f.limit); |
| 202 | if(!items.length)return[['output','No plans match the given filters']]; |
| 203 | var rows=[]; |
| 204 | for(var i=0;i<items.length;i++)rows.push(pRow(items[i])); |
| 205 | return rows} |
| 206 | |
| 207 | function sessionPush(f){ |
| 208 | var r=remote['add-mock-terminal'];var v=r?r.v+1:1; |
| 209 | var p=f.public?'public':f.secret?'secret':'secret'; |
| 210 | remote['add-mock-terminal']={v:v,p:p,u:'rockstar.ninja/s/xK9mQ2pL'}; |
| 211 | var adhoc=f.redact?f.redact.length:0; |
| 212 | var secrets=3+adhoc*2; |
| 213 | var rules=5+adhoc; |
| 214 | var rows=[ |
| 215 | ['output','Found 3 sessions. Using most recent: add-mock-terminal'], |
| 216 | ['blue',spin[0]+' Scanning session records...'], |
| 217 | ['blue',spin[2]+' Compressing 142 KB...'], |
| 218 | ['blue',spin[4]+' Generating preview image...'], |
| 219 | ['blue',spin[6]+' Saving session...'], |
| 220 | ['output','Pushed session (v'+v+')'], |
| 221 | ['output','URL: https://rockstar.ninja/s/xK9mQ2pL'], |
| 222 | ['dim',' 843 records scanned, '+secrets+' secrets redacted ('+rules+' rules)']]; |
| 223 | if(f.verbose){ |
| 224 | rows.push(['dim',' Rules matched:'],['dim',' 2\u00d7 env-vars'],['dim',' 1\u00d7 api-keys']); |
| 225 | for(var i=0;i<adhoc;i++){var nm=f.redact[i];if(nm.length>20)nm=nm.substring(0,17)+'...';rows.push(['dim',' 2\u00d7 ad-hoc: '+nm])} |
| 226 | rows.push(['dim',' Timing:']); |
| 227 | rows.push(['dim',' config 4ms']); |
| 228 | rows.push(['dim',' find 12ms (project: 3 sessions)']); |
| 229 | rows.push(['dim',' read 8ms (142 KB)']); |
| 230 | rows.push(['dim',' compile 1ms ('+rules+' patterns)']); |
| 231 | rows.push(['dim',' redact 23ms (843 records, 312 with messages)']); |
| 232 | rows.push(['dim',' marshal 3ms (request: 138 KB)']); |
| 233 | rows.push(['dim',' upload 847ms']); |
| 234 | rows.push(['dim',' server 234ms']); |
| 235 | rows.push(['dim',' total 1132ms'])} |
| 236 | return rows} |
| 237 | |
| 238 | function planPush(f,name){ |
| 239 | var match=null; |
| 240 | for(var i=0;i<plans.length;i++){if(plans[i].n===name||plans[i].n.indexOf(name)>=0){match=plans[i];break}} |
| 241 | if(!match)return[['error','Error: no plan matching "'+name+'"']]; |
| 242 | var r=remote[match.n];var v=r?r.v+1:1; |
| 243 | var p=f.public?'public':f.secret?'secret':'secret'; |
| 244 | remote[match.n]={v:v,p:p,u:'rockstar.ninja/p/nR4kW8vJ'}; |
| 245 | var adhoc=f.redact?f.redact.length:0; |
| 246 | var rows=[ |
| 247 | ['blue',spin[0]+' Checking for changes...'], |
| 248 | ['blue',spin[2]+' Generating preview image...'], |
| 249 | ['blue',spin[4]+' Saving v'+v+'...'], |
| 250 | ['blue',spin[6]+' Committing v'+v+'...'], |
| 251 | ['output','Pushed plan (v'+v+')'], |
| 252 | ['output','URL: https://rockstar.ninja/p/nR4kW8vJ']]; |
| 253 | if(adhoc>0)rows.push(['dim',' '+adhoc*3+' ad-hoc redactions applied']); |
| 254 | return rows} |
| 255 | |
| 256 | function helpCmd(){return[ |
| 257 | ['output','Available commands:'],['output',''], |
| 258 | ['cyan',' rn session push Push most recent session'], |
| 259 | ['cyan',' rn session list List local sessions'], |
| 260 | ['cyan',' rn plan push <name> Push a plan'], |
| 261 | ['cyan',' rn plan list List local plans'], |
| 262 | ['cyan',' rn version Print version'], |
| 263 | ['output',''], |
| 264 | ['dim',' clear Clear terminal'], |
| 265 | ['dim',' help Show this message']]} |
| 266 | |
| 267 | function H(desc,usage,subs,flags,foot){ |
| 268 | var r=[['output',desc],['output',''],['output','Usage:'],['output',' '+usage]]; |
| 269 | if(subs){r.push(['output',''],['output','Available Commands:']);for(var i=0;i<subs.length;i++)r.push(['output',' '+subs[i]])} |
| 270 | if(flags){r.push(['output',''],['output','Flags:']);for(var i=0;i<flags.length;i++)r.push(['output',' '+flags[i]])} |
| 271 | if(foot)r.push(['output',''],['dim',foot]); |
| 272 | return r; |
| 273 | } |
| 274 | /*HELP_TEXTS*/var helpTexts={}; |
| 275 | /*FLAG_DEFS*/var flagDefs={}; |
| 276 | /*CMD_ALIASES*/var cmdAliases={}; |
| 277 | |
| 278 | function render(rows){ |
| 279 | for(var i=0;i<rows.length;i++){ |
| 280 | var r=rows[i]; |
| 281 | if(r[0]==='html')addHtml(r[1],r[2]); |
| 282 | else addLine(r[0],r[1]); |
| 283 | } |
| 284 | } |
| 285 | |
| 286 | function exec(cmd){ |
| 287 | cmd=cmd.trim(); |
| 288 | if(!cmd)return; |
| 289 | addPrompt(cmd); |
| 290 | hist.push(cmd); |
| 291 | hIdx=hist.length; |
| 292 | var parts=cmd.split(/\s+/); |
| 293 | if(parts.length>1&&parts[0]==='rn'&&cmdAliases[parts[1]])parts[1]=cmdAliases[parts[1]]; |
| 294 | var hasHelp=false; |
| 295 | for(var i=0;i<parts.length;i++){ |
| 296 | if(parts[i]==='--help'||parts[i]==='-h')hasHelp=true; |
| 297 | } |
| 298 | var words=[]; |
| 299 | for(var i=0;i<parts.length;i++){ |
| 300 | if(parts[i].charAt(0)==='-')break; |
| 301 | words.push(parts[i]); |
| 302 | } |
| 303 | var base=words.join(' '); |
| 304 | if(!hasHelp&&(base==='rn'||base==='rn session'||base==='rn plan'||base==='rn account'))hasHelp=true; |
| 305 | if(hasHelp){ |
| 306 | var h=helpTexts[base]; |
| 307 | var w=words.slice(); |
| 308 | while(!h&&w.length>1){w.pop();h=helpTexts[w.join(' ')]} |
| 309 | if(h){render(h);body.scrollTop=body.scrollHeight;return} |
| 310 | } |
| 311 | if(base==='rn session push'||base.lastIndexOf('rn session push ',0)===0){ |
| 312 | render(sessionPush(parseFlags(parts.slice(3),'rn session push'))); |
| 313 | }else if(base==='rn session list'||base==='rn list'){ |
| 314 | var skip=base==='rn list'?2:3; |
| 315 | render(sessionList(parseFlags(parts.slice(skip),'rn session list'))); |
| 316 | }else if(base==='rn plan list'||base==='rn plans'){ |
| 317 | var skip=base==='rn plans'?2:3; |
| 318 | render(planList(parseFlags(parts.slice(skip),'rn plan list'))); |
| 319 | }else if(base==='rn plan push'||base.lastIndexOf('rn plan push ',0)===0){ |
| 320 | var f=parseFlags(parts.slice(3),'rn plan push'); |
| 321 | if(!f._args.length){addLine('error','Error: accepts 1 arg(s), received 0');addLine('dim','Usage: rn plan push [name|path]')} |
| 322 | else render(planPush(f,f._args[0])); |
| 323 | }else if(base==='help'){ |
| 324 | render(helpCmd()); |
| 325 | }else if(base==='clear'){ |
| 326 | output.innerHTML=''; |
| 327 | }else if(base==='rn version'){ |
| 328 | addLine('output','rn v0.9.2'); |
| 329 | }else{ |
| 330 | addLine('error','command not found: '+cmd); |
| 331 | addLine('dim',"type 'help' for available commands"); |
| 332 | } |
| 333 | body.scrollTop=body.scrollHeight; |
| 334 | } |
| 335 | |
| 336 | function unlock(){ |
| 337 | locked=false; |
| 338 | if(mobile){ |
| 339 | hint.textContent='works best on desktop'; |
| 340 | }else{ |
| 341 | hint.textContent='try: rn session list --all --sort turns'; |
| 342 | } |
| 343 | hint.classList.add('term-hint-visible'); |
| 344 | } |
| 345 | |
| 346 | document.addEventListener('keydown',function(e){ |
| 347 | if(locked)return; |
| 348 | var tag=document.activeElement&&document.activeElement.tagName; |
| 349 | if(tag==='INPUT'||tag==='TEXTAREA'||tag==='SELECT')return; |
| 350 | if(e.ctrlKey||e.metaKey||e.altKey)return; |
| 351 | if(e.key==='Enter'){ |
| 352 | e.preventDefault();exec(buf);buf='';input.textContent=''; |
| 353 | }else if(e.key==='Backspace'){ |
| 354 | e.preventDefault();buf=buf.slice(0,-1);input.textContent=buf; |
| 355 | }else if(e.key==='ArrowUp'){ |
| 356 | e.preventDefault(); |
| 357 | if(hIdx>0){hIdx--;buf=hist[hIdx];input.textContent=buf;} |
| 358 | }else if(e.key==='ArrowDown'){ |
| 359 | e.preventDefault(); |
| 360 | if(hIdx<hist.length-1){hIdx++;buf=hist[hIdx];input.textContent=buf;} |
| 361 | else{hIdx=hist.length;buf='';input.textContent='';} |
| 362 | }else if(e.key.length===1){ |
| 363 | e.preventDefault();buf+=e.key;input.textContent=buf; |
| 364 | body.scrollTop=body.scrollHeight; |
| 365 | } |
| 366 | }); |
| 367 | |
| 368 | var demo=[ |
| 369 | {cmd:'rn session push',pause:1200}, |
| 370 | {cmd:'rn session list',pause:1500}, |
| 371 | {cmd:'rn session list --all --sort name',pause:0} |
| 372 | ]; |
| 373 | |
| 374 | function typeCmd(text,cb){ |
| 375 | var i=0; |
| 376 | function tick(){ |
| 377 | if(i<text.length){ |
| 378 | buf+=text[i];input.textContent=buf;i++; |
| 379 | setTimeout(tick,40+Math.random()*35); |
| 380 | }else{setTimeout(cb,250);} |
| 381 | } |
| 382 | tick(); |
| 383 | } |
| 384 | |
| 385 | function run(idx){ |
| 386 | if(idx>=demo.length){unlock();return;} |
| 387 | var step=demo[idx]; |
| 388 | typeCmd(step.cmd,function(){ |
| 389 | exec(buf);buf='';input.textContent=''; |
| 390 | setTimeout(function(){run(idx+1)},step.pause||400); |
| 391 | }); |
| 392 | } |
| 393 | |
| 394 | setTimeout(function(){run(0)},800); |
| 395 | |
| 396 | var shuriken=document.querySelector('.home-shuriken-svg'); |
| 397 | function spinShuriken(){ |
| 398 | shuriken.getAnimations().forEach(function(a){a.cancel()}); |
| 399 | shuriken.animate( |
| 400 | [{transform:'rotate(0deg)'},{transform:'rotate(1080deg)'}], |
| 401 | {duration:2000,easing:'cubic-bezier(0,0.4,0.2,1)',fill:'forwards'} |
| 402 | ); |
| 403 | } |
| 404 | spinShuriken(); |
| 405 | shuriken.addEventListener('click',spinShuriken); |
| 406 | })(); |
| 407 | </script> |
| 408 | |
| 1 | <div class="home"> |
| 2 | <div class="home-logo"> |
| 3 | <svg class="home-shuriken-svg" viewBox="0 0 100 100" aria-hidden="true"> |
| 4 | <polygon points="50,5 55,40 95,50 60,55 50,95 45,60 5,50 40,45" fill="var(--text-muted)"/> |
| 5 | <circle cx="50" cy="50" r="4" fill="var(--bg)"/> |
| 6 | </svg> |
| 7 | <pre class="home-title"> |
| 8 | _ _ _ _ |
| 9 | _ _ ___ __| |__ __| |_ __ _ _ _ _ _ (_)_ _ (_)__ _ |
| 10 | | '_/ _ \/ _| / /(_-< _/ _` | '_|| ' \| | ' \ | / _` | |
| 11 | |_| \___/\__|_\_\/__/\__\__,_|_|(_)_||_|_|_||_|/ \__,_| |
| 12 | |__/ |
| 13 | </pre> |
| 14 | </div> |
| 15 | |
| 16 | <p class="home-tagline">share your <a href="https://claude.ai/code">Claude Code</a> sessions and plans.</p> |
| 17 | |
| 18 | <div class="home-install"> |
| 19 | <div class="home-install-label">$ install</div> |
| 20 | <div class="home-install-row"> |
| 21 | <code class="home-install-cmd">curl -fsSL https://rockstar.ninja/install.sh | sh</code> |
| 22 | <button class="home-copy-btn" id="copy-install" aria-label="Copy to clipboard"> |
| 23 | <span id="copy-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg></span> |
| 24 | </button> |
| 25 | </div> |
| 26 | </div> |
| 27 | |
| 28 | <div class="home-features"> |
| 29 | <div class="home-feature"><span class="home-bullet">></span> push sessions and plans from the CLI</div> |
| 30 | <div class="home-feature"><span class="home-bullet">></span> rendered with syntax highlighting and tool call diffs</div> |
| 31 | <div class="home-feature"><span class="home-bullet">></span> live emoji reactions via WebSocket</div> |
| 32 | <div class="home-feature"><span class="home-bullet">></span> auto-expiring links, secret redaction</div> |
| 33 | <div class="home-feature"><span class="home-bullet">></span> no tracking, no cookies, no third parties</div> |
| 34 | </div> |
| 35 | |
| 36 | <div class="home-demo"> |
| 37 | <div class="home-demo-label">$ demo</div> |
| 38 | <div class="term" id="term"> |
| 39 | <div class="term-chrome"> |
| 40 | <span class="term-dot term-dot-red"></span> |
| 41 | <span class="term-dot term-dot-yellow"></span> |
| 42 | <span class="term-dot term-dot-green"></span> |
| 43 | <span class="term-title">rn</span> |
| 44 | </div> |
| 45 | <div class="term-body" id="term-body"> |
| 46 | <div id="term-output"></div> |
| 47 | <div class="term-input-line"> |
| 48 | <span class="term-prompt">$ </span> |
| 49 | <span class="term-input" id="term-input"></span> |
| 50 | <span class="term-cursor" id="term-cursor"></span> |
| 51 | </div> |
| 52 | </div> |
| 53 | </div> |
| 54 | <div class="term-hint" id="term-hint"></div> |
| 55 | </div> |
| 56 | </div> |
| 57 | <script> |
| 58 | document.getElementById('copy-install').addEventListener('click',function(){ |
| 59 | var t='curl -fsSL https://rockstar.ninja/install.sh | sh'; |
| 60 | navigator.clipboard.writeText(t).then(function(){ |
| 61 | var i=document.getElementById('copy-icon'); |
| 62 | i.innerHTML='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>'; |
| 63 | setTimeout(function(){i.innerHTML='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>'},1500) |
| 64 | }) |
| 65 | }); |
| 66 | </script> |
| 67 | <script> |
| 68 | (function(){ |
| 69 | var output=document.getElementById('term-output'); |
| 70 | var input=document.getElementById('term-input'); |
| 71 | var body=document.getElementById('term-body'); |
| 72 | var hint=document.getElementById('term-hint'); |
| 73 | var buf=''; |
| 74 | var locked=true; |
| 75 | var hist=[]; |
| 76 | var hIdx=-1; |
| 77 | var mobile=window.innerWidth<768; |
| 78 | // Braille spinner frames (charmbracelet/bubbles spinner.Dot) |
| 79 | var spin='\u28fe\u28fd\u28fb\u28bf\u287f\u289f\u28af\u28f7'; |
| 80 | |
| 81 | function esc(s){return s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>')} |
| 82 | function S(cls,t){return'<span class="term-s-'+cls+'">'+esc(t)+'</span>'} |
| 83 | |
| 84 | function addLine(cls,text){ |
| 85 | var d=document.createElement('div'); |
| 86 | d.className='term-line term-line-'+cls; |
| 87 | d.textContent=text; |
| 88 | output.appendChild(d); |
| 89 | body.scrollTop=body.scrollHeight; |
| 90 | } |
| 91 | |
| 92 | function addHtml(cls,html){ |
| 93 | var d=document.createElement('div'); |
| 94 | d.className='term-line'+(cls?' term-line-'+cls:''); |
| 95 | d.innerHTML=html; |
| 96 | output.appendChild(d); |
| 97 | body.scrollTop=body.scrollHeight; |
| 98 | } |
| 99 | |
| 100 | function addPrompt(cmd){ |
| 101 | addHtml('','<span class="term-line-prompt">$ </span><span class="term-line-cmd">'+esc(cmd)+'</span>'); |
| 102 | } |
| 103 | |
| 104 | // Mock data — structured for sort/filter/reverse |
| 105 | var remote={'calm-silver-mountain':{v:1,p:'public',u:'rockstar.ninja/p/mT7nX3qR'}}; |
| 106 | var sessions=[ |
| 107 | {n:'add-mock-terminal',id:'a1b2c3d4-e5f6-7890-abcd-ef1234567890',d:'2024-02-24',ds:'Feb 24',sz:145408,ss:'142 KB',t:47,ts:' 47t',b:'main',pj:'rockstar.ninja'}, |
| 108 | {n:'fix-websocket-reconnect',id:'b2c3d4e5-f6a7-8901-bcde-f12345678901',d:'2024-02-22',ds:'Feb 22',sz:91136,ss:' 89 KB',t:23,ts:' 23t',b:'main',pj:'rockstar.ninja'}, |
| 109 | {n:'implement-og-images',id:'c3d4e5f6-a7b8-9012-cdef-123456789012',d:'2024-02-20',ds:'Feb 20',sz:208896,ss:'204 KB',t:61,ts:' 61t',b:'feat/og',pj:'rockstar.ninja'}, |
| 110 | {n:'add-rate-limiting',id:'d4e5f6a7-b8c9-0123-defa-234567890123',d:'2024-02-18',ds:'Feb 18',sz:68608,ss:' 67 KB',t:19,ts:' 19t',b:'main',pj:'bewitch'}, |
| 111 | {n:'refactor-auth-flow',id:'e5f6a7b8-c9d0-1234-efab-345678901234',d:'2024-02-15',ds:'Feb 15',sz:319488,ss:'312 KB',t:84,ts:' 84t',b:'feat/auth',pj:'bewitch'}, |
| 112 | {n:'setup-ci-pipeline',id:'f6a7b8c9-d0e1-2345-fabc-456789012345',d:'2024-02-12',ds:'Feb 12',sz:46080,ss:' 45 KB',t:12,ts:' 12t',b:'main',pj:'bewitch'} |
| 113 | ]; |
| 114 | var plans=[ |
| 115 | {n:'fancy-dazzling-pumpkin',d:'2024-02-24',ds:'Feb 24',sz:4300,ss:'4.2 KB'}, |
| 116 | {n:'calm-silver-mountain',d:'2024-02-21',ds:'Feb 21',sz:2867,ss:'2.8 KB'}, |
| 117 | {n:'bold-crimson-falcon',d:'2024-02-17',ds:'Feb 17',sz:6246,ss:'6.1 KB'}, |
| 118 | {n:'swift-azure-thunder',d:'2024-02-10',ds:'Feb 10',sz:1536,ss:'1.5 KB'} |
| 119 | ]; |
| 120 | |
| 121 | function parseFlags(parts,path){ |
| 122 | var defs=flagDefs[path]||{}; |
| 123 | var shorts={};for(var k in defs)if(defs[k].s)shorts[defs[k].s]=k; |
| 124 | var f={};for(var k in defs){ |
| 125 | if(defs[k].t==='b')f[k]=false; |
| 126 | else if(defs[k].t==='i')f[k]=defs[k].d?parseInt(defs[k].d):0; |
| 127 | else if(defs[k].t==='a')f[k]=[]; |
| 128 | else f[k]=defs[k].d||'';} |
| 129 | var args=[]; |
| 130 | for(var i=0;i<parts.length;i++){ |
| 131 | var p=parts[i]; |
| 132 | if(p==='--help'||p==='-h'){f._help=true;continue} |
| 133 | if(p.charAt(0)==='-'&&p.length>1&&p.charAt(1)==='-'){ |
| 134 | var eq=p.indexOf('=');var nm=eq>=0?p.substring(2,eq):p.substring(2); |
| 135 | var def=defs[nm];if(!def)continue; |
| 136 | if(def.t==='b')f[nm]=true; |
| 137 | else if(def.t==='a'){f[nm].push(eq>=0?p.substring(eq+1):(parts[++i]||''))} |
| 138 | else{f[nm]=eq>=0?p.substring(eq+1):(parts[++i]||'');if(def.t==='i')f[nm]=parseInt(f[nm])||0} |
| 139 | }else if(p.charAt(0)==='-'&&p.length===2){ |
| 140 | var ln=shorts[p.charAt(1)];if(!ln)continue;var def=defs[ln]; |
| 141 | if(def.t==='b')f[ln]=true; |
| 142 | else if(def.t==='a'){f[ln].push(parts[++i]||'')} |
| 143 | else{f[ln]=parts[++i]||'';if(def.t==='i')f[ln]=parseInt(f[ln])||0} |
| 144 | }else args.push(p)} |
| 145 | f._args=args;return f} |
| 146 | |
| 147 | function pad(s,n){while(s.length<n)s+=' ';return s} |
| 148 | |
| 149 | function sRow(s){ |
| 150 | var h=' '+S('blue',pad(s.n,28))+' '+S('dim',s.id)+' '+S('dim',s.ds)+' '+S('dim',s.ss)+' '+S('dim',s.ts)+' '+S('dim',s.b); |
| 151 | var r=remote[s.n]; |
| 152 | if(r){h+=' '+S(r.p==='public'?'green':'yellow','v'+r.v+' '+r.p)+' '+S('dim',r.u)} |
| 153 | return['html','',h]} |
| 154 | |
| 155 | function pRow(p){ |
| 156 | var h=' '+S('blue',pad(p.n,32))+' '+S('dim',p.ds)+' '+S('dim',p.ss); |
| 157 | var r=remote[p.n]; |
| 158 | if(r){h+=' '+S(r.p==='public'?'green':'yellow','v'+r.v+' '+r.p)+' '+S('dim',r.u)} |
| 159 | return['html','',h]} |
| 160 | |
| 161 | function sessionList(f){ |
| 162 | var items=sessions.slice(); |
| 163 | if(!f.all)items=items.filter(function(s){return s.pj==='rockstar.ninja'}); |
| 164 | if(f.branch)items=items.filter(function(s){return s.b===f.branch}); |
| 165 | if(f.search){var q=f.search.toLowerCase();items=items.filter(function(s){ |
| 166 | return s.n.toLowerCase().indexOf(q)>=0||s.id.indexOf(q)>=0})} |
| 167 | if(f.pushed)items=items.filter(function(s){return!!remote[s.n]}); |
| 168 | else if(f.local)items=items.filter(function(s){return!remote[s.n]}); |
| 169 | var field=f.sort||'date'; |
| 170 | items.sort(function(a,b){var c=0; |
| 171 | if(field==='date')c=a.d<b.d?-1:a.d>b.d?1:0; |
| 172 | else if(field==='size')c=a.sz-b.sz; |
| 173 | else if(field==='turns')c=a.t-b.t; |
| 174 | else if(field==='name')c=a.n<b.n?-1:a.n>b.n?1:0; |
| 175 | if(field==='date')c=-c;if(f.reverse)c=-c;return c}); |
| 176 | if(f.limit>0)items=items.slice(0,f.limit); |
| 177 | if(!items.length)return[['output','No sessions match the given filters']]; |
| 178 | var groups={},order=[]; |
| 179 | for(var i=0;i<items.length;i++){var pj=items[i].pj; |
| 180 | if(!groups[pj]){groups[pj]=[];order.push(pj)}groups[pj].push(items[i])} |
| 181 | var rows=[]; |
| 182 | for(var g=0;g<order.length;g++){ |
| 183 | if(g>0)rows.push(['output','']);var grp=groups[order[g]]; |
| 184 | var cl=grp.length===1?'1 session':grp.length+' sessions'; |
| 185 | rows.push(['html','bold','<span class="term-line-bold">'+esc(order[g])+'</span> '+S('dim',cl)]); |
| 186 | for(var i=0;i<grp.length;i++)rows.push(sRow(grp[i]))} |
| 187 | return rows} |
| 188 | |
| 189 | function planList(f){ |
| 190 | var items=plans.slice(); |
| 191 | if(f.search){var q=f.search.toLowerCase();items=items.filter(function(p){ |
| 192 | return p.n.toLowerCase().indexOf(q)>=0})} |
| 193 | if(f.pushed)items=items.filter(function(p){return!!remote[p.n]}); |
| 194 | else if(f.local)items=items.filter(function(p){return!remote[p.n]}); |
| 195 | var field=f.sort||'date'; |
| 196 | items.sort(function(a,b){var c=0; |
| 197 | if(field==='date')c=a.d<b.d?-1:a.d>b.d?1:0; |
| 198 | else if(field==='size')c=a.sz-b.sz; |
| 199 | else if(field==='name')c=a.n<b.n?-1:a.n>b.n?1:0; |
| 200 | if(field==='date')c=-c;if(f.reverse)c=-c;return c}); |
| 201 | if(f.limit>0)items=items.slice(0,f.limit); |
| 202 | if(!items.length)return[['output','No plans match the given filters']]; |
| 203 | var rows=[]; |
| 204 | for(var i=0;i<items.length;i++)rows.push(pRow(items[i])); |
| 205 | return rows} |
| 206 | |
| 207 | function sessionPush(f){ |
| 208 | var r=remote['add-mock-terminal'];var v=r?r.v+1:1; |
| 209 | var p=f.public?'public':f.secret?'secret':'secret'; |
| 210 | remote['add-mock-terminal']={v:v,p:p,u:'rockstar.ninja/s/xK9mQ2pL'}; |
| 211 | var adhoc=f.redact?f.redact.length:0; |
| 212 | var secrets=3+adhoc*2; |
| 213 | var rules=5+adhoc; |
| 214 | var rows=[ |
| 215 | ['output','Found 3 sessions. Using most recent: add-mock-terminal'], |
| 216 | ['blue',spin[0]+' Scanning session records...'], |
| 217 | ['blue',spin[2]+' Compressing 142 KB...'], |
| 218 | ['blue',spin[4]+' Generating preview image...'], |
| 219 | ['blue',spin[6]+' Saving session...'], |
| 220 | ['output','Pushed session (v'+v+')'], |
| 221 | ['output','URL: https://rockstar.ninja/s/xK9mQ2pL'], |
| 222 | ['dim',' 843 records scanned, '+secrets+' secrets redacted ('+rules+' rules)']]; |
| 223 | if(f.verbose){ |
| 224 | rows.push(['dim',' Rules matched:'],['dim',' 2\u00d7 env-vars'],['dim',' 1\u00d7 api-keys']); |
| 225 | for(var i=0;i<adhoc;i++){var nm=f.redact[i];if(nm.length>20)nm=nm.substring(0,17)+'...';rows.push(['dim',' 2\u00d7 ad-hoc: '+nm])} |
| 226 | rows.push(['dim',' Timing:']); |
| 227 | rows.push(['dim',' config 4ms']); |
| 228 | rows.push(['dim',' find 12ms (project: 3 sessions)']); |
| 229 | rows.push(['dim',' read 8ms (142 KB)']); |
| 230 | rows.push(['dim',' compile 1ms ('+rules+' patterns)']); |
| 231 | rows.push(['dim',' redact 23ms (843 records, 312 with messages)']); |
| 232 | rows.push(['dim',' marshal 3ms (request: 138 KB)']); |
| 233 | rows.push(['dim',' upload 847ms']); |
| 234 | rows.push(['dim',' server 234ms']); |
| 235 | rows.push(['dim',' total 1132ms'])} |
| 236 | return rows} |
| 237 | |
| 238 | function planPush(f,name){ |
| 239 | var match=null; |
| 240 | for(var i=0;i<plans.length;i++){if(plans[i].n===name||plans[i].n.indexOf(name)>=0){match=plans[i];break}} |
| 241 | if(!match)return[['error','Error: no plan matching "'+name+'"']]; |
| 242 | var r=remote[match.n];var v=r?r.v+1:1; |
| 243 | var p=f.public?'public':f.secret?'secret':'secret'; |
| 244 | remote[match.n]={v:v,p:p,u:'rockstar.ninja/p/nR4kW8vJ'}; |
| 245 | var adhoc=f.redact?f.redact.length:0; |
| 246 | var rows=[ |
| 247 | ['blue',spin[0]+' Checking for changes...'], |
| 248 | ['blue',spin[2]+' Generating preview image...'], |
| 249 | ['blue',spin[4]+' Saving v'+v+'...'], |
| 250 | ['blue',spin[6]+' Committing v'+v+'...'], |
| 251 | ['output','Pushed plan (v'+v+')'], |
| 252 | ['output','URL: https://rockstar.ninja/p/nR4kW8vJ']]; |
| 253 | if(adhoc>0)rows.push(['dim',' '+adhoc*3+' ad-hoc redactions applied']); |
| 254 | return rows} |
| 255 | |
| 256 | function helpCmd(){return[ |
| 257 | ['output','Available commands:'],['output',''], |
| 258 | ['cyan',' rn session push Push most recent session'], |
| 259 | ['cyan',' rn session list List local sessions'], |
| 260 | ['cyan',' rn plan push <name> Push a plan'], |
| 261 | ['cyan',' rn plan list List local plans'], |
| 262 | ['cyan',' rn version Print version'], |
| 263 | ['output',''], |
| 264 | ['dim',' clear Clear terminal'], |
| 265 | ['dim',' help Show this message']]} |
| 266 | |
| 267 | function H(desc,usage,subs,flags,foot){ |
| 268 | var r=[['output',desc],['output',''],['output','Usage:'],['output',' '+usage]]; |
| 269 | if(subs){r.push(['output',''],['output','Available Commands:']);for(var i=0;i<subs.length;i++)r.push(['output',' '+subs[i]])} |
| 270 | if(flags){r.push(['output',''],['output','Flags:']);for(var i=0;i<flags.length;i++)r.push(['output',' '+flags[i]])} |
| 271 | if(foot)r.push(['output',''],['dim',foot]); |
| 272 | return r; |
| 273 | } |
| 274 | /*HELP_TEXTS*/var helpTexts={}; |
| 275 | /*FLAG_DEFS*/var flagDefs={}; |
| 276 | /*CMD_ALIASES*/var cmdAliases={}; |
| 277 | |
| 278 | function render(rows){ |
| 279 | for(var i=0;i<rows.length;i++){ |
| 280 | var r=rows[i]; |
| 281 | if(r[0]==='html')addHtml(r[1],r[2]); |
| 282 | else addLine(r[0],r[1]); |
| 283 | } |
| 284 | } |
| 285 | |
| 286 | function exec(cmd){ |
| 287 | cmd=cmd.trim(); |
| 288 | if(!cmd)return; |
| 289 | addPrompt(cmd); |
| 290 | hist.push(cmd); |
| 291 | hIdx=hist.length; |
| 292 | var parts=cmd.split(/\s+/); |
| 293 | if(parts.length>1&&parts[0]==='rn'&&cmdAliases[parts[1]])parts[1]=cmdAliases[parts[1]]; |
| 294 | var hasHelp=false; |
| 295 | for(var i=0;i<parts.length;i++){ |
| 296 | if(parts[i]==='--help'||parts[i]==='-h')hasHelp=true; |
| 297 | } |
| 298 | var words=[]; |
| 299 | for(var i=0;i<parts.length;i++){ |
| 300 | if(parts[i].charAt(0)==='-')break; |
| 301 | words.push(parts[i]); |
| 302 | } |
| 303 | var base=words.join(' '); |
| 304 | if(!hasHelp&&(base==='rn'||base==='rn session'||base==='rn plan'||base==='rn account'))hasHelp=true; |
| 305 | if(hasHelp){ |
| 306 | var h=helpTexts[base]; |
| 307 | var w=words.slice(); |
| 308 | while(!h&&w.length>1){w.pop();h=helpTexts[w.join(' ')]} |
| 309 | if(h){render(h);body.scrollTop=body.scrollHeight;return} |
| 310 | } |
| 311 | if(base==='rn session push'||base.lastIndexOf('rn session push ',0)===0){ |
| 312 | render(sessionPush(parseFlags(parts.slice(3),'rn session push'))); |
| 313 | }else if(base==='rn session list'||base==='rn list'){ |
| 314 | var skip=base==='rn list'?2:3; |
| 315 | render(sessionList(parseFlags(parts.slice(skip),'rn session list'))); |
| 316 | }else if(base==='rn plan list'||base==='rn plans'){ |
| 317 | var skip=base==='rn plans'?2:3; |
| 318 | render(planList(parseFlags(parts.slice(skip),'rn plan list'))); |
| 319 | }else if(base==='rn plan push'||base.lastIndexOf('rn plan push ',0)===0){ |
| 320 | var f=parseFlags(parts.slice(3),'rn plan push'); |
| 321 | if(!f._args.length){addLine('error','Error: accepts 1 arg(s), received 0');addLine('dim','Usage: rn plan push [name|path]')} |
| 322 | else render(planPush(f,f._args[0])); |
| 323 | }else if(base==='help'){ |
| 324 | render(helpCmd()); |
| 325 | }else if(base==='clear'){ |
| 326 | output.innerHTML=''; |
| 327 | }else if(base==='rn version'){ |
| 328 | addLine('output','rn v0.9.2'); |
| 329 | }else{ |
| 330 | addLine('error','command not found: '+cmd); |
| 331 | addLine('dim',"type 'help' for available commands"); |
| 332 | } |
| 333 | body.scrollTop=body.scrollHeight; |
| 334 | } |
| 335 | |
| 336 | function unlock(){ |
| 337 | locked=false; |
| 338 | if(mobile){ |
| 339 | hint.textContent='works best on desktop'; |
| 340 | }else{ |
| 341 | hint.textContent='try: rn session list --all --sort turns'; |
| 342 | } |
| 343 | hint.classList.add('term-hint-visible'); |
| 344 | } |
| 345 | |
| 346 | document.addEventListener('keydown',function(e){ |
| 347 | if(locked)return; |
| 348 | var tag=document.activeElement&&document.activeElement.tagName; |
| 349 | if(tag==='INPUT'||tag==='TEXTAREA'||tag==='SELECT')return; |
| 350 | if(e.ctrlKey||e.metaKey||e.altKey)return; |
| 351 | if(e.key==='Enter'){ |
| 352 | e.preventDefault();exec(buf);buf='';input.textContent=''; |
| 353 | }else if(e.key==='Backspace'){ |
| 354 | e.preventDefault();buf=buf.slice(0,-1);input.textContent=buf; |
| 355 | }else if(e.key==='ArrowUp'){ |
| 356 | e.preventDefault(); |
| 357 | if(hIdx>0){hIdx--;buf=hist[hIdx];input.textContent=buf;} |
| 358 | }else if(e.key==='ArrowDown'){ |
| 359 | e.preventDefault(); |
| 360 | if(hIdx<hist.length-1){hIdx++;buf=hist[hIdx];input.textContent=buf;} |
| 361 | else{hIdx=hist.length;buf='';input.textContent='';} |
| 362 | }else if(e.key.length===1){ |
| 363 | e.preventDefault();buf+=e.key;input.textContent=buf; |
| 364 | body.scrollTop=body.scrollHeight; |
| 365 | } |
| 366 | }); |
| 367 | |
| 368 | var demo=[ |
| 369 | {cmd:'rn session push',pause:1200}, |
| 370 | {cmd:'rn session list',pause:1500}, |
| 371 | {cmd:'rn session list --all --sort name',pause:0} |
| 372 | ]; |
| 373 | |
| 374 | function typeCmd(text,cb){ |
| 375 | var i=0; |
| 376 | function tick(){ |
| 377 | if(i<text.length){ |
| 378 | buf+=text[i];input.textContent=buf;i++; |
| 379 | setTimeout(tick,40+Math.random()*35); |
| 380 | }else{setTimeout(cb,250);} |
| 381 | } |
| 382 | tick(); |
| 383 | } |
| 384 | |
| 385 | function run(idx){ |
| 386 | if(idx>=demo.length){unlock();return;} |
| 387 | var step=demo[idx]; |
| 388 | typeCmd(step.cmd,function(){ |
| 389 | exec(buf);buf='';input.textContent=''; |
| 390 | setTimeout(function(){run(idx+1)},step.pause||400); |
| 391 | }); |
| 392 | } |
| 393 | |
| 394 | setTimeout(function(){run(0)},800); |
| 395 | |
| 396 | var shuriken=document.querySelector('.home-shuriken-svg'); |
| 397 | function spinShuriken(){ |
| 398 | shuriken.getAnimations().forEach(function(a){a.cancel()}); |
| 399 | shuriken.animate( |
| 400 | [{transform:'rotate(0deg)'},{transform:'rotate(1080deg)'}], |
| 401 | {duration:2000,easing:'cubic-bezier(0,0.4,0.2,1)',fill:'forwards'} |
| 402 | ); |
| 403 | } |
| 404 | spinShuriken(); |
| 405 | shuriken.addEventListener('click',spinShuriken); |
| 406 | })(); |
| 407 | </script> |
| 408 | |