self modifying website

feat: remove some copy and add runtime and memeory

dunkirk.sh 71e5906f ffacc84f

verified
+199 -113
+199 -113
index.html
··· 188 188 </div> 189 189 190 190 <div class="content"> 191 - <p class="prompt">C:\PLASTIC> DIR</p> 192 - 193 - <div class="file-listing"> 194 - <div class="file-line"> 195 - Volume in drive C is PLASTIC-SYS 196 - </div> 197 - <div class="file-line">Directory of C:\PLASTIC</div> 198 - <div class="file-line"></div> 199 - <div class="file-line"> 200 - <span class="dir">SYSTEM &lt;DIR&gt;</span> 12-15-95 201 - 3:42p 202 - </div> 203 - <div class="file-line"> 204 - <span class="exe">PLASTIC EXE</span> 24,576 12-15-95 205 - 3:42p 206 - </div> 207 - <div class="file-line"> 208 - <span class="txt">README TXT</span> 1,024 12-15-95 3:42p 209 - </div> 210 - <div class="file-line"> 211 - <span class="txt">CONFIG SYS</span> 512 12-15-95 3:42p 212 - </div> 213 - <div class="file-line">4 File(s) 26,112 bytes</div> 214 - <div class="file-line">524,288 bytes free</div> 215 - </div> 216 - 217 191 <p class="prompt">C:\PLASTIC> PLASTIC.EXE</p> 218 192 219 193 <pre class="ascii-art"> ··· 272 246 <li>Supports EGA/VGA graphics modes</li> 273 247 </ul> 274 248 275 - <h2>System Commands:</h2> 276 - <p> 277 - <span class="command">HELP</span> 278 - <span class="command">DIR</span> 279 - <span class="command">EDIT</span> 280 - <span class="command">RUN</span> 281 - <span class="command">EXIT</span> 282 - </p> 283 - 284 249 <div class="separator"> 285 250 ════════════════════════════════════════════════════════════ 286 251 </div> 287 252 288 - <p>Runtime: 00:13:37 | Memory: 589K free | CPU: 80486DX-33</p> 289 - <p class="error"> 290 - WARNING: Unauthorized modification may corrupt system files 253 + <p> 254 + Runtime: <span id="runtime">00:13:37</span> | Memory: 255 + <span id="memory">589K free</span> | CPU: 80486DX-33 291 256 </p> 292 - 293 - <p class="prompt">C:\PLASTIC> <span class="cursor">_</span></p> 294 257 </div> 295 258 296 259 <div class="status-bar"> 297 260 <span>F1=Help F2=Save F3=Load F10=Menu</span> 298 - <span>12:34 PM</span> 261 + <span>12:00</span> 299 262 </div> 300 263 </div> 301 264 302 265 <script> 303 266 // Tool call system for AI to interact with the page 304 267 window.toolCallbacks = { 305 - replaceElement: function(selector, newHTML) { 268 + replaceElement: function (selector, newHTML) { 306 269 const element = document.querySelector(selector); 307 270 if (element) { 308 271 element.outerHTML = newHTML; 309 - return { success: true, message: `Replaced element: ${selector}` }; 272 + return { 273 + success: true, 274 + message: `Replaced element: ${selector}`, 275 + }; 310 276 } 311 - return { success: false, message: `Element not found: ${selector}` }; 277 + return { 278 + success: false, 279 + message: `Element not found: ${selector}`, 280 + }; 312 281 }, 313 - 314 - updateElement: function(selector, newContent) { 282 + 283 + updateElement: function (selector, newContent) { 315 284 const element = document.querySelector(selector); 316 285 if (element) { 317 286 element.innerHTML = newContent; 318 - return { success: true, message: `Updated element: ${selector}` }; 287 + return { 288 + success: true, 289 + message: `Updated element: ${selector}`, 290 + }; 319 291 } 320 - return { success: false, message: `Element not found: ${selector}` }; 292 + return { 293 + success: false, 294 + message: `Element not found: ${selector}`, 295 + }; 321 296 }, 322 - 323 - addElement: function(parentSelector, newHTML, position = 'beforeend') { 297 + 298 + addElement: function ( 299 + parentSelector, 300 + newHTML, 301 + position = "beforeend", 302 + ) { 324 303 const parent = document.querySelector(parentSelector); 325 304 if (parent) { 326 305 parent.insertAdjacentHTML(position, newHTML); 327 - return { success: true, message: `Added element to: ${parentSelector}` }; 306 + return { 307 + success: true, 308 + message: `Added element to: ${parentSelector}`, 309 + }; 328 310 } 329 - return { success: false, message: `Parent not found: ${parentSelector}` }; 311 + return { 312 + success: false, 313 + message: `Parent not found: ${parentSelector}`, 314 + }; 330 315 }, 331 - 332 - removeElement: function(selector) { 316 + 317 + removeElement: function (selector) { 333 318 const element = document.querySelector(selector); 334 319 if (element) { 335 320 element.remove(); 336 - return { success: true, message: `Removed element: ${selector}` }; 321 + return { 322 + success: true, 323 + message: `Removed element: ${selector}`, 324 + }; 337 325 } 338 - return { success: false, message: `Element not found: ${selector}` }; 326 + return { 327 + success: false, 328 + message: `Element not found: ${selector}`, 329 + }; 339 330 }, 340 - 341 - updateStyle: function(selector, styleObj) { 331 + 332 + updateStyle: function (selector, styleObj) { 342 333 const element = document.querySelector(selector); 343 334 if (element) { 344 335 Object.assign(element.style, styleObj); 345 - return { success: true, message: `Updated styles for: ${selector}` }; 336 + return { 337 + success: true, 338 + message: `Updated styles for: ${selector}`, 339 + }; 346 340 } 347 - return { success: false, message: `Element not found: ${selector}` }; 341 + return { 342 + success: false, 343 + message: `Element not found: ${selector}`, 344 + }; 348 345 }, 349 - 350 - executeJS: function(code) { 346 + 347 + executeJS: function (code) { 351 348 try { 352 349 const result = eval(code); 353 - return { success: true, message: 'JavaScript executed', result: result }; 350 + return { 351 + success: true, 352 + message: "JavaScript executed", 353 + result: result, 354 + }; 354 355 } catch (error) { 355 - return { success: false, message: `JS Error: ${error.message}` }; 356 + return { 357 + success: false, 358 + message: `JS Error: ${error.message}`, 359 + }; 356 360 } 357 - } 361 + }, 358 362 }; 359 363 360 364 function executeToolCall(toolCall) { 361 365 const { function: func, arguments: args } = toolCall; 362 - console.log('Executing tool call:', func, args); 363 - 366 + console.log("Executing tool call:", func, args); 367 + 364 368 if (window.toolCallbacks[func]) { 365 369 try { 366 370 // Handle different function signatures 367 - if (func === 'removeElement') { 371 + if (func === "removeElement") { 368 372 // removeElement expects just a selector 369 - const selector = args.selector || Object.keys(args)[0] || Object.values(args)[0]; 373 + const selector = 374 + args.selector || 375 + Object.keys(args)[0] || 376 + Object.values(args)[0]; 370 377 return window.toolCallbacks[func](selector); 371 - } else if (func === 'updateStyle' && args.styleObj) { 372 - return window.toolCallbacks[func](args.selector, args.styleObj); 373 - } else if (func === 'executeJS') { 378 + } else if (func === "updateStyle" && args.styleObj) { 379 + return window.toolCallbacks[func]( 380 + args.selector, 381 + args.styleObj, 382 + ); 383 + } else if (func === "executeJS") { 374 384 return window.toolCallbacks[func](args.code); 375 - } else if (func === 'updateElement') { 376 - return window.toolCallbacks[func](args.selector, args.newContent); 377 - } else if (func === 'replaceElement') { 378 - return window.toolCallbacks[func](args.selector, args.newHTML); 379 - } else if (func === 'addElement') { 380 - return window.toolCallbacks[func](args.parentSelector, args.newHTML, args.position); 385 + } else if (func === "updateElement") { 386 + return window.toolCallbacks[func]( 387 + args.selector, 388 + args.newContent, 389 + ); 390 + } else if (func === "replaceElement") { 391 + return window.toolCallbacks[func]( 392 + args.selector, 393 + args.newHTML, 394 + ); 395 + } else if (func === "addElement") { 396 + return window.toolCallbacks[func]( 397 + args.parentSelector, 398 + args.newHTML, 399 + args.position, 400 + ); 381 401 } else { 382 402 // Fallback: use all argument values in order 383 - return window.toolCallbacks[func](...Object.values(args)); 403 + return window.toolCallbacks[func]( 404 + ...Object.values(args), 405 + ); 384 406 } 385 407 } catch (error) { 386 - return { success: false, message: `Error executing ${func}: ${error.message}` }; 408 + return { 409 + success: false, 410 + message: `Error executing ${func}: ${error.message}`, 411 + }; 387 412 } 388 413 } 389 414 return { success: false, message: `Unknown tool: ${func}` }; ··· 453 478 454 479 // Clean up response and extract JSON if present 455 480 let cleanResponse = generatedContent.trim(); 456 - 481 + 457 482 // Remove markdown formatting 458 483 cleanResponse = cleanResponse 459 484 .replace(/```json\n?/g, "") 460 485 .replace(/```\n?/g, ""); 461 486 462 487 // Try to extract JSON from mixed content 463 - const jsonMatch = cleanResponse.match(/\{[\s\S]*"tool_calls"[\s\S]*\}/); 488 + const jsonMatch = cleanResponse.match( 489 + /\{[\s\S]*"tool_calls"[\s\S]*\}/, 490 + ); 464 491 if (jsonMatch) { 465 492 cleanResponse = jsonMatch[0]; 466 493 } 467 494 468 - console.log('Cleaned response:', cleanResponse); 495 + console.log("Cleaned response:", cleanResponse); 469 496 470 497 // Check if response contains tool calls 471 498 try { 472 499 const toolResponse = JSON.parse(cleanResponse); 473 - if (toolResponse.tool_calls && Array.isArray(toolResponse.tool_calls)) { 500 + if ( 501 + toolResponse.tool_calls && 502 + Array.isArray(toolResponse.tool_calls) 503 + ) { 474 504 // Execute tool calls 475 505 const results = []; 476 506 for (const toolCall of toolResponse.tool_calls) { 477 507 const result = executeToolCall(toolCall); 478 508 results.push(result); 479 - console.log('Tool call result:', result); 509 + console.log("Tool call result:", result); 480 510 } 481 511 statusDiv.textContent = `EXECUTED ${results.length} COMMANDS`; 482 - 512 + 483 513 // Send feedback to AI about tool results 484 - setTimeout(() => sendToolFeedback(userPrompt, results), 100); 514 + setTimeout( 515 + () => sendToolFeedback(userPrompt, results), 516 + 100, 517 + ); 485 518 } else { 486 519 throw new Error("Invalid tool call format"); 487 520 } 488 521 } catch (jsonError) { 489 - console.log('JSON parse error:', jsonError); 490 - console.log('Raw response:', generatedContent); 491 - console.log('Attempting to parse as HTML...'); 492 - 522 + console.log("JSON parse error:", jsonError); 523 + console.log("Raw response:", generatedContent); 524 + console.log("Attempting to parse as HTML..."); 525 + 493 526 // Not JSON, treat as HTML code 494 527 let cleanCode = generatedContent 495 528 .replace(/```html\n?/g, "") 496 529 .replace(/```\n?/g, ""); 497 530 498 531 statusDiv.textContent = "INJECTING CODE..."; 499 - document.querySelector(".content").innerHTML += cleanCode; 532 + document.querySelector(".content").innerHTML += 533 + cleanCode; 500 534 statusDiv.textContent = "CODE EXECUTION SUCCESSFUL"; 501 535 } 502 536 ··· 519 553 520 554 async function sendToolFeedback(originalPrompt, toolResults) { 521 555 const statusDiv = document.getElementById("statusDisplay"); 522 - 556 + 523 557 try { 524 558 statusDiv.textContent = "SENDING FEEDBACK TO AI..."; 525 - 559 + 526 560 const currentPageHTML = document.documentElement.outerHTML; 527 - const resultsText = toolResults.map(r => 528 - `${r.success ? '✓' : '✗'} ${r.message}${r.result ? ` (result: ${r.result})` : ''}` 529 - ).join('\n'); 561 + const resultsText = toolResults 562 + .map( 563 + (r) => 564 + `${r.success ? "✓" : "✗"} ${r.message}${r.result ? ` (result: ${r.result})` : ""}`, 565 + ) 566 + .join("\n"); 530 567 531 568 const response = await fetch( 532 569 "https://ai.hackclub.com/chat/completions", ··· 547 584 ); 548 585 549 586 if (!response.ok) { 550 - throw new Error(`HTTP ${response.status}: ${response.statusText}`); 587 + throw new Error( 588 + `HTTP ${response.status}: ${response.statusText}`, 589 + ); 551 590 } 552 591 553 592 const data = await response.json(); 554 593 let followUpContent; 555 - 556 - if (data.choices && data.choices[0] && data.choices[0].message) { 594 + 595 + if ( 596 + data.choices && 597 + data.choices[0] && 598 + data.choices[0].message 599 + ) { 557 600 followUpContent = data.choices[0].message.content; 558 601 } else if (data.content) { 559 602 followUpContent = data.content; ··· 564 607 } 565 608 566 609 followUpContent = followUpContent.trim(); 567 - console.log('Follow-up response:', followUpContent); 610 + console.log("Follow-up response:", followUpContent); 568 611 569 612 if (followUpContent === "COMPLETE") { 570 613 statusDiv.textContent = "AI SATISFIED - TASK COMPLETE"; 571 - setTimeout(() => statusDiv.textContent = "", 3000); 614 + setTimeout(() => (statusDiv.textContent = ""), 3000); 572 615 return; 573 616 } 574 617 575 618 // Process follow-up commands 576 619 statusDiv.textContent = "AI MAKING ADJUSTMENTS..."; 577 - 620 + 578 621 // Try to parse as tool calls 579 622 try { 580 - const jsonMatch = followUpContent.match(/\{[\s\S]*"tool_calls"[\s\S]*\}/); 623 + const jsonMatch = followUpContent.match( 624 + /\{[\s\S]*"tool_calls"[\s\S]*\}/, 625 + ); 581 626 if (jsonMatch) { 582 627 const toolResponse = JSON.parse(jsonMatch[0]); 583 - if (toolResponse.tool_calls && Array.isArray(toolResponse.tool_calls)) { 628 + if ( 629 + toolResponse.tool_calls && 630 + Array.isArray(toolResponse.tool_calls) 631 + ) { 584 632 const followUpResults = []; 585 633 for (const toolCall of toolResponse.tool_calls) { 586 634 const result = executeToolCall(toolCall); 587 635 followUpResults.push(result); 588 - console.log('Follow-up tool result:', result); 636 + console.log( 637 + "Follow-up tool result:", 638 + result, 639 + ); 589 640 } 590 641 statusDiv.textContent = `AI EXECUTED ${followUpResults.length} ADJUSTMENTS`; 591 642 } ··· 594 645 let cleanCode = followUpContent 595 646 .replace(/```html\n?/g, "") 596 647 .replace(/```\n?/g, ""); 597 - document.querySelector(".content").innerHTML += cleanCode; 598 - statusDiv.textContent = "AI ADDED FOLLOW-UP CONTENT"; 648 + document.querySelector(".content").innerHTML += 649 + cleanCode; 650 + statusDiv.textContent = 651 + "AI ADDED FOLLOW-UP CONTENT"; 599 652 } 600 653 } catch (error) { 601 - console.log('Follow-up parsing error:', error); 654 + console.log("Follow-up parsing error:", error); 602 655 statusDiv.textContent = "AI FEEDBACK ERROR"; 603 656 } 604 657 605 - setTimeout(() => statusDiv.textContent = "", 4000); 606 - 658 + setTimeout(() => (statusDiv.textContent = ""), 4000); 607 659 } catch (error) { 608 660 statusDiv.textContent = `FEEDBACK ERROR: ${error.message}`; 609 - console.error('Feedback error:', error); 610 - setTimeout(() => statusDiv.textContent = "", 3000); 661 + console.error("Feedback error:", error); 662 + setTimeout(() => (statusDiv.textContent = ""), 3000); 611 663 } 612 664 } 613 665 ··· 629 681 const timeStr = now.toLocaleTimeString([], { 630 682 hour: "2-digit", 631 683 minute: "2-digit", 684 + hour12: false, 632 685 }); 633 686 const statusBarTime = document.querySelector( 634 687 ".status-bar span:last-child", 635 688 ); 636 689 if (statusBarTime) { 637 690 statusBarTime.textContent = timeStr; 691 + } 692 + 693 + // Update memory in status bar based on actual tab memory usage 694 + const memoryUsage = Math.round( 695 + performance.memory 696 + ? performance.memory.usedJSHeapSize / 1024 697 + : 0, 698 + ); 699 + 700 + const memoryStr = `${589 - Math.min(Math.round(memoryUsage / 1024), 500)}K free`; 701 + const memory = document.getElementById("memory"); 702 + if (memory) { 703 + memory.textContent = memoryStr; 704 + } 705 + 706 + // Update runtime in status bar - based on how long the page has been open 707 + const pageOpenTime = performance.timing 708 + ? performance.timing.navigationStart || Date.now() 709 + : Date.now(); 710 + const timeOpen = Math.floor((Date.now() - pageOpenTime) / 1000); 711 + const hours = Math.floor(timeOpen / 3600) 712 + .toString() 713 + .padStart(2, "0"); 714 + const minutes = Math.floor((timeOpen % 3600) / 60) 715 + .toString() 716 + .padStart(2, "0"); 717 + const seconds = Math.floor(timeOpen % 60) 718 + .toString() 719 + .padStart(2, "0"); 720 + const runtimeStr = `${hours}:${minutes}:${seconds}`; 721 + const runtime = document.getElementById("runtime"); 722 + if (runtime) { 723 + runtime.textContent = runtimeStr; 638 724 } 639 725 }, 1000); 640 726 </script>