From f023d8c4d40a35a7627adc5bac71d57c580d9002 Mon Sep 17 00:00:00 2001 From: SpiralGang Date: Sun, 14 Sep 2025 14:35:19 -0600 Subject: [PATCH] Add files via upload --- AndroidManifest.xml | 13 ++ QuantumAIIDEWebViewActivity.kt | 21 ++ QuantumAIIDE_Monolith.html | 352 ++++++++++++++++++++++++++++++++ QuantumWebIDE.html | 358 +++++++++++++++++++++++++++++++++ agent.py | 50 +++++ ai-chat.js | 27 +++ ai.js | 51 +++++ ai.py | 13 ++ audit.py | 5 + build.gradle | 22 ++ build_apk.sh | 2 +- editor.js | 18 ++ files.js | 18 ++ index.html | 22 ++ main.js | 22 ++ proxy.js | 26 +++ settings.js | 19 ++ shell.py | 7 + terminal.js | 34 ++++ theme.css | 6 + utils.js | 4 + 21 files changed, 1089 insertions(+), 1 deletion(-) create mode 100644 AndroidManifest.xml create mode 100644 QuantumAIIDEWebViewActivity.kt create mode 100644 QuantumAIIDE_Monolith.html create mode 100644 QuantumWebIDE.html create mode 100644 agent.py create mode 100644 ai-chat.js create mode 100644 ai.js create mode 100644 ai.py create mode 100644 audit.py create mode 100644 build.gradle create mode 100644 editor.js create mode 100644 files.js create mode 100644 index.html create mode 100644 main.js create mode 100644 proxy.js create mode 100644 settings.js create mode 100644 shell.py create mode 100644 terminal.js create mode 100644 theme.css create mode 100644 utils.js diff --git a/AndroidManifest.xml b/AndroidManifest.xml new file mode 100644 index 0000000..afec66f --- /dev/null +++ b/AndroidManifest.xml @@ -0,0 +1,13 @@ + + + + + + + + + + \ No newline at end of file diff --git a/QuantumAIIDEWebViewActivity.kt b/QuantumAIIDEWebViewActivity.kt new file mode 100644 index 0000000..c37457d --- /dev/null +++ b/QuantumAIIDEWebViewActivity.kt @@ -0,0 +1,21 @@ +package com.quantumaiide.agent + +import android.annotation.SuppressLint +import android.os.Bundle +import android.webkit.WebView +import android.webkit.WebViewClient +import androidx.appcompat.app.AppCompatActivity + +class QuantumAIIDEWebViewActivity : AppCompatActivity() { + @SuppressLint("SetJavaScriptEnabled") + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + val webView = WebView(this) + setContentView(webView) + webView.settings.javaScriptEnabled = true + webView.settings.domStorageEnabled = true + webView.settings.allowFileAccess = true + webView.webViewClient = WebViewClient() + webView.loadUrl("file:///android_asset/QuantumAIIDE_Monolith.html") + } +} \ No newline at end of file diff --git a/QuantumAIIDE_Monolith.html b/QuantumAIIDE_Monolith.html new file mode 100644 index 0000000..424af2c --- /dev/null +++ b/QuantumAIIDE_Monolith.html @@ -0,0 +1,352 @@ + + + + + QuantumAIIDE — Self-Compiling APK Agentic IDE + + + + + + + + + + + +
+
+ QuantumAIIDE — Self-Compiling APK Agent + +
+
+ +
+
+
+
+ + + + +
+
+
+ + + + \ No newline at end of file diff --git a/QuantumWebIDE.html b/QuantumWebIDE.html new file mode 100644 index 0000000..b8e086b --- /dev/null +++ b/QuantumWebIDE.html @@ -0,0 +1,358 @@ + + + + + Quantum WebIDE — Mobile-First, Privileged Proxy Shell + + + + + + + + + +
+
+ Quantum WebIDE — Mobile-First Privileged Proxy Shell +
+
+ + + +
+ +
+
+
+ + + + + + + + +
+
+
+ + + + \ No newline at end of file diff --git a/agent.py b/agent.py new file mode 100644 index 0000000..bfd4ec1 --- /dev/null +++ b/agent.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 +""" +QuantumAIIDE Agent: Mobile-First, Privileged AI System Builder +Industry standards, agentic orchestration, Android/Aarch64 ready. +References: /reference vault, ai_dev_system.py, OWASP, GitHub API docs, DeepSeek, HuggingFace +""" +import asyncio, json, os, aiohttp, logging +from github import Github +from shell import run_shell_command +from ai import query_ai +from audit import log_action + +# Configure logging +logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s %(message)s') +logger = logging.getLogger("QuantumAIIDE-Agent") + +class QuantumAgent: + def __init__(self, github_token, ai_token): + self.github = Github(github_token) + self.ai_token = ai_token + + async def handle_request(self, req): + """Dispatch agentic requests: build, refactor, run, push, etc.""" + action = req.get("action") + params = req.get("params", {}) + log_action(action, params) + if action == "refactor_file": + repo = self.github.get_repo(params["repo"]) + file = repo.get_contents(params["path"]) + code = file.decoded_content.decode() + instructions = params["instructions"] + prompt = f"Refactor this code for {params['path']}:\n{code}\nInstructions: {instructions}\nOutput only final code." + new_code = await query_ai(prompt, self.ai_token) + repo.update_file(params["path"], "Agentic AI refactor", new_code, file.sha) + return {"status": "ok", "msg": "File refactored"} + elif action == "generate_file": + repo = self.github.get_repo(params["repo"]) + prompt = f"Generate code for {params['path']}:\n{params['description']}\nOutput only final code." + code = await query_ai(prompt, self.ai_token) + repo.create_file(params["path"], "Agentic AI generate", code) + return {"status": "ok", "msg": "File generated"} + elif action == "run_shell": + result = run_shell_command(params["command"]) + return {"status": "ok", "output": result} + # Extend for more agentic ops: build, deploy, proxy, etc. + else: + return {"status": "error", "msg": "Unknown action"} + +# FastAPI or Flask app to expose agent endpoints (omitted for brevity) +# See /reference vault, ai_dev_system.py for full server reference \ No newline at end of file diff --git a/ai-chat.js b/ai-chat.js new file mode 100644 index 0000000..f9129d6 --- /dev/null +++ b/ai-chat.js @@ -0,0 +1,27 @@ +import { githubWrite, shellRun, auditLog } from './integrations.js'; + +export function initAIChat(container) { + container.innerHTML = ` +
+ + + `; + document.getElementById('chat-send-btn').onclick = async () => { + let val = document.getElementById('chat-input').value.trim(); + if (!val) return; + addChatMsg('You', val); + // Call DeepSeek/HF API + let result = await aiExecute(val); + addChatMsg('AI', result.message); + // If result includes action (code, command), execute directly + if (result.action === 'write_file') { + await githubWrite(result.file, result.content); + auditLog('write_file', result.file); + } + if (result.action === 'run_shell') { + let shellResult = await shellRun(result.command); + auditLog('run_shell', result.command, shellResult); + addChatMsg('Shell', shellResult.output); + } + }; +} \ No newline at end of file diff --git a/ai.js b/ai.js new file mode 100644 index 0000000..9c6905a --- /dev/null +++ b/ai.js @@ -0,0 +1,51 @@ +import { files } from './files.js'; + +let aiKey = ""; + +export function initAIChat(container) { + container.innerHTML = ` +
+
+ + +
+ `; + document.getElementById('chat-send-btn').onclick = () => { + let val = document.getElementById('chat-input').value.trim(); + if (!val) return; + runAIChat(val); + document.getElementById('chat-input').value = ''; + }; +} + +export async function runAIChat(prompt, source="chat", cb) { + addChatMsg(source==="cli"?"CLI":"You",prompt); + let repoContext = Object.keys(files).map(f=>`${f}:\n${files[f].slice(0,300)}`).join('\n\n'); + let userMsg = `QuantumWebIDE, Mobile-First, Android 10+/Aarch64. Files:\n${repoContext}\n\n${prompt}`; + let answer = await queryAI([{role:"user",content:userMsg}]); + addChatMsg("AI",answer); + if(cb) cb(answer); +} + +function addChatMsg(user, text) { + let chatbox = document.getElementById('chatbox'); + let div = document.createElement('div'); + div.className = 'chat-msg'; + div.innerHTML = `${user}: ${text}`; + chatbox.appendChild(div); + chatbox.scrollTop = chatbox.scrollHeight; +} + +async function queryAI(messages, model="deepseek-ai/DeepSeek-R1:fireworks-ai") { + if(!aiKey) return "AI key not set. Paste in settings."; + try { + const response = await fetch("https://router.huggingface.co/v1/chat/completions",{ + headers: { Authorization: "Bearer "+aiKey, "Content-Type":"application/json"}, + method: "POST", + body: JSON.stringify({messages,top_p:1,model}), + }); + const result = await response.json(); + if(result.choices && result.choices.length>0) return result.choices[0].message.content; + return result.error||"AI error: Unexpected response"; + } catch(e){ return "AI error: "+e.message;} +} \ No newline at end of file diff --git a/ai.py b/ai.py new file mode 100644 index 0000000..8b3240d --- /dev/null +++ b/ai.py @@ -0,0 +1,13 @@ +import aiohttp, os +async def query_ai(prompt, ai_token, model="deepseek-ai/DeepSeek-R1:fireworks-ai"): + url = "https://router.huggingface.co/v1/chat/completions" + payload = { + "messages": [{"role": "user", "content": prompt}], + "top_p": 1, + "model": model + } + headers = {"Authorization": f"Bearer {ai_token}", "Content-Type": "application/json"} + async with aiohttp.ClientSession() as session: + async with session.post(url, json=payload, headers=headers) as resp: + res = await resp.json() + return res["choices"][0]["message"]["content"] if "choices" in res else res.get("error", "") \ No newline at end of file diff --git a/audit.py b/audit.py new file mode 100644 index 0000000..3e944a1 --- /dev/null +++ b/audit.py @@ -0,0 +1,5 @@ +import time, json +def log_action(action, params): + entry = {"ts": time.time(), "action": action, "params": params} + with open("agent_audit.log", "a") as f: + f.write(json.dumps(entry) + "\n") \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..ffa4b8c --- /dev/null +++ b/build.gradle @@ -0,0 +1,22 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 33 + defaultConfig { + applicationId "com.quantumaiide.agent" + minSdkVersion 29 + targetSdkVersion 33 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + implementation 'androidx.appcompat:appcompat:1.6.1' +} \ No newline at end of file diff --git a/build_apk.sh b/build_apk.sh index bfe360f..6a1475f 100644 --- a/build_apk.sh +++ b/build_apk.sh @@ -20,4 +20,4 @@ cd QuantumAIIDE echo "==> APK BUILD COMPLETE" ls -l app/build/outputs/apk/release/ -# Optionally upload artifact (if running on a CI runner with artifact upload support) +# Optionally upload artifact (if running on a CI runner with artifact upload support) \ No newline at end of file diff --git a/editor.js b/editor.js new file mode 100644 index 0000000..97df327 --- /dev/null +++ b/editor.js @@ -0,0 +1,18 @@ +import { files, openFile, saveFile, deleteFile, downloadFile } from './files.js'; + +export function initEditor(container) { + container.innerHTML = ` + +
+ + + + +
+ `; + document.getElementById('editor').value = files[openFile()] || ''; + document.getElementById('save-file-btn').onclick = () => saveFile(document.getElementById('editor').value); + document.getElementById('new-file-btn').onclick = () => openFile(prompt("New file name:")); + document.getElementById('delete-file-btn').onclick = () => deleteFile(); + document.getElementById('download-file-btn').onclick = () => downloadFile(); +} \ No newline at end of file diff --git a/files.js b/files.js new file mode 100644 index 0000000..90e2549 --- /dev/null +++ b/files.js @@ -0,0 +1,18 @@ +export let files = { + "README.md": "# QuantumWebIDE\nMobile-first, privileged shell.", + "main.sh": "#!/bin/bash\necho 'Ready.'" +}; +let activeFile = "README.md"; + +export function openFile(fname) { + if (fname && files[fname]) activeFile = fname; + return activeFile; +} +export function saveFile(content) { files[activeFile] = content; } +export function deleteFile() { delete files[activeFile]; activeFile = Object.keys(files)[0];} +export function downloadFile() { + const a = document.createElement('a'); + a.href = URL.createObjectURL(new Blob([files[activeFile]], {type: "text/plain"})); + a.download = activeFile; + a.click(); +} \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..b34b3ab --- /dev/null +++ b/index.html @@ -0,0 +1,22 @@ + + + + + QuantumAIIDE Mobile Agentic IDE + + + + + +

QuantumAIIDE

+ +
+ + + \ No newline at end of file diff --git a/main.js b/main.js new file mode 100644 index 0000000..2acee0d --- /dev/null +++ b/main.js @@ -0,0 +1,22 @@ +import { initTerminal } from './terminal.js' +import { initEditor } from './editor.js' +import { initAIChat } from './ai-chat.js' +import { initProxy } from './proxy.js' +import { initSettings } from './settings.js' + +const panels = { + terminal: initTerminal, + editor: initEditor, + ai: initAIChat, + proxy: initProxy, + settings: initSettings +} +function showPanel(panel) { + const main = document.getElementById('main-panel') + main.innerHTML = '' + panels[panel](main) +} +['terminal','editor','ai','proxy','settings'].forEach(p=>{ + document.getElementById('nav-'+p).onclick=()=>showPanel(p) +}) +showPanel('terminal') \ No newline at end of file diff --git a/proxy.js b/proxy.js new file mode 100644 index 0000000..d881c84 --- /dev/null +++ b/proxy.js @@ -0,0 +1,26 @@ +export function initProxy(container) { + container.innerHTML = ` +
Proxy system ready.
+ + + + + + `; + document.getElementById('proxy-send-btn').onclick = async () => { + const url = document.getElementById('proxy-url').value.trim(); + const method = document.getElementById('proxy-method').value.trim(); + let headers = {}; + try { headers = JSON.parse(document.getElementById('proxy-headers').value || "{}"); } catch(e){} + let body = document.getElementById('proxy-body').value.trim(); + let options = { method, headers }; + if (body) options.body = body; + try { + let res = await fetch(url, options); + let text = await res.text(); + document.getElementById('proxy-output').textContent = text.slice(0,2000); + } catch(e) { + document.getElementById('proxy-output').textContent = "Proxy error: "+e.message; + } + }; +} \ No newline at end of file diff --git a/settings.js b/settings.js new file mode 100644 index 0000000..0d1fca2 --- /dev/null +++ b/settings.js @@ -0,0 +1,19 @@ +import { aiKey } from './ai.js'; + +export function loadSettings(container) { + container.innerHTML = ` +

System Settings

+ + + `; + document.getElementById('settings-ai-key').onchange = e => { + aiKey = e.target.value.trim(); + }; + document.getElementById('settings-theme').onchange = e => { + document.body.style.background = e.target.value === "light" ? "#f9fafb" : "#111827"; + document.body.style.color = e.target.value === "light" ? "#181f2a" : "#e5e7eb"; + }; +} \ No newline at end of file diff --git a/shell.py b/shell.py new file mode 100644 index 0000000..dbd104e --- /dev/null +++ b/shell.py @@ -0,0 +1,7 @@ +import subprocess +def run_shell_command(cmd): + try: + result = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=120) + return result.stdout if result.returncode == 0 else result.stderr + except Exception as e: + return f"Shell error: {e}" \ No newline at end of file diff --git a/terminal.js b/terminal.js new file mode 100644 index 0000000..f069378 --- /dev/null +++ b/terminal.js @@ -0,0 +1,34 @@ +import { files, openFile } from './files.js'; +import { runAIChat } from './ai.js'; + +export function initTerminal(container) { + container.innerHTML = `
`; + const term = new Terminal({ theme: { background: '#181f2a', foreground: '#5eead4' }, fontFamily: 'Fira Code, monospace', fontSize: 15 }); + term.open(document.getElementById('terminal')); + term.write('QuantumWebIDE Terminal Ready!\r\n> '); + let cmd = ''; + term.onData(data => { + if (data === '\r') { + term.write('\r\n'); + handleCmd(cmd.trim(), term); + cmd = ''; + term.write('> '); + } else if (data === '\u007F') { + if (cmd.length > 0) { + term.write('\b \b'); cmd = cmd.slice(0, -1); + } + } else { term.write(data); cmd += data;} + }); +} + +function handleCmd(cmd, term) { + if (!cmd) return; + if (cmd === 'help') { + term.write('Commands: help, ls, cat , edit , proxy , ai \r\n'); return; + } + if (cmd === 'ls') { term.write(Object.keys(files).join(' ') + '\r\n'); return; } + if (cmd.startsWith('cat ')) { term.write((files[cmd.slice(4).trim()] || 'File not found.') + '\r\n'); return; } + if (cmd.startsWith('edit ')) { openFile(cmd.slice(5).trim()); term.write('Editing ' + cmd.slice(5).trim() + '\r\n'); return; } + if (cmd.startsWith('ai ')) { runAIChat(cmd.slice(3).trim(),"cli",out=>term.write(out+'\r\n')); return; } + term.write('Unknown command. Type help.\r\n'); +} \ No newline at end of file diff --git a/theme.css b/theme.css new file mode 100644 index 0000000..03d6ef3 --- /dev/null +++ b/theme.css @@ -0,0 +1,6 @@ +html, body { background: #111827; color: #e5e7eb; font-family: 'Inter', sans-serif; } +a { color: #5eead4; } +::-webkit-scrollbar { width: 8px; } +::-webkit-scrollbar-thumb { background: #6366f1; border-radius: 4px; } +.btn { background: #6366f1; color: #fff; border-radius: 0.5em; padding: 0.6em 1.3em; font-weight: 500; } +.btn:hover { background: #7c3aed; } \ No newline at end of file diff --git a/utils.js b/utils.js new file mode 100644 index 0000000..84b2926 --- /dev/null +++ b/utils.js @@ -0,0 +1,4 @@ +export function androidCompatCheck() { + let ua = navigator.userAgent; + return /Android 10|aarch64|arm64|Linux/.test(ua); +} \ No newline at end of file