From 3306a33e53738b4c160df8eff3470c03c4421e3f Mon Sep 17 00:00:00 2001 From: Commander Date: Tue, 28 Apr 2026 12:05:45 -0400 Subject: [PATCH] Restore alfred-commander 5.0.0 from alfredlinux.com backup tarball --- README.md | 68 + extension.js | 4302 ++++++++++++++++++++++++++++++ extensions.json | 10 + media/alfred-icon.svg | 6 + media/walkthrough/meet-alfred.md | 17 + media/walkthrough/models.md | 18 + media/walkthrough/shortcuts.md | 24 + media/walkthrough/sovereign.md | 27 + media/walkthrough/stats.md | 16 + media/walkthrough/voice.md | 18 + package.json | 168 ++ package.json.bak.vault | 187 ++ 12 files changed, 4861 insertions(+) create mode 100644 README.md create mode 100644 extension.js create mode 100644 extensions.json create mode 100644 media/alfred-icon.svg create mode 100644 media/walkthrough/meet-alfred.md create mode 100644 media/walkthrough/models.md create mode 100644 media/walkthrough/shortcuts.md create mode 100644 media/walkthrough/sovereign.md create mode 100644 media/walkthrough/stats.md create mode 100644 media/walkthrough/voice.md create mode 100644 package.json create mode 100644 package.json.bak.vault diff --git a/README.md b/README.md new file mode 100644 index 0000000..d3f1cd3 --- /dev/null +++ b/README.md @@ -0,0 +1,68 @@ +# Alfred Commander + +**3,551-line VS Code extension — AI chat, voice, stats, walkthrough — the brain of Alfred IDE.** + +Alfred Commander is a single-file VS Code/code-server extension that provides multi-provider AI chat, speech-to-text/text-to-speech, workspace intelligence, and an interactive walkthrough. It is the primary user interface for Alfred IDE. + +## Architecture + +One extension, one `extension.js` — 3,551 lines of production code. No framework, no bundler, no node_modules. Pure VS Code API. + +### What It Does + +| Feature | How it works | +|---------|-------------| +| **AI Chat** | Multi-provider (Anthropic Claude, OpenAI GPT, Groq, local Ollama) via streaming API | +| **Voice** | Browser SpeechRecognition for STT, Kokoro TTS engine for speech output | +| **Attachments** | Drag-and-drop files/images into chat, base64 encoding for vision models | +| **Model Picker** | Runtime model switching across all providers | +| **Stats Panel** | Account usage, token counts, billing period, plan badge | +| **Walkthrough** | 6-page interactive onboarding (sovereignty, models, voice, shortcuts, stats) | +| **Sidebar** | Custom webview with full HTML/CSS/JS UI rendered in VS Code panel | +| **MCP Tools** | 500+ tools via gocodeme-mcp service integration | + +### Commands + +| Command | Action | +|---------|--------| +| `alfred-commander.open` | Open the Alfred chat panel | +| `alfred-commander.toggle` | Toggle panel visibility | +| `alfred-commander.showStats` | Account & usage statistics | +| `alfred-commander.welcome` | Open walkthrough | +| `alfred-commander.workspaceStatus` | Workspace health check | + +## File Structure + +``` +alfred-commander/ +├── extension.js # 3,551 lines — entire extension +├── package.json # Extension manifest, commands, keybindings +├── extensions.json # Extension dependency declarations +├── media/ +│ ├── alfred-icon.svg # Panel icon +│ └── walkthrough/ +│ ├── meet-alfred.md # Introduction walkthrough +│ ├── sovereign.md # Sovereignty & privacy walkthrough +│ ├── models.md # AI model configuration +│ ├── voice.md # Voice assistant setup +│ ├── shortcuts.md # Keyboard shortcuts reference +│ └── stats.md # Usage statistics guide +``` + +## Key Design Decisions + +- **Single file**: No build step, no transpilation, no bundler. `extension.js` is the extension. +- **Webview UI**: Full HTML/CSS/JS UI rendered inside VS Code's webview API — not a tree view or quick pick. +- **Multi-provider**: Provider abstraction supports Anthropic, OpenAI, Groq, and Ollama with a single chat interface. +- **Offline voice**: TTS via local Kokoro engine (no cloud API calls for speech). +- **Zero telemetry**: No analytics, no tracking, no phone-home. Conversations stay on the server. + +## Runs On + +- **Alfred IDE** (cloud): code-server 4.x on Linux — primary target +- **Alfred IDE** (desktop): Windows portable build +- **VS Code**: Compatible with stock VS Code (some features require Alfred infrastructure) + +## License + +AGPL-3.0 \ No newline at end of file diff --git a/extension.js b/extension.js new file mode 100644 index 0000000..417ac17 --- /dev/null +++ b/extension.js @@ -0,0 +1,4302 @@ +const vscode = require('vscode'); +const https = require('https'); +const http = require('http'); +const os = require('os'); +const fs = require('fs'); +const path = require('path'); +const crypto = require('crypto'); +const { execSync } = require('child_process'); + +let currentAgent = 'alfred'; +let convId = null; +let csrfToken = null; +let sessionCookie = null; +let userProfile = null; +let hmacSecretCache = null; +let statsPanel = null; +let voicePanel = null; +let memoryPanel = null; +let costPanel = null; +let vaultPanel = null; +let sessionHistory = []; // v5: session persistence +let sessionStartTime = Date.now(); + +// ═══════════════════════════════════════════════════════════════════════════ +// WORKSPACE INTELLIGENCE ENGINE — Deep awareness of project, files, git +// ═══════════════════════════════════════════════════════════════════════════ + +function getWorkspaceRoot() { + const folders = vscode.workspace.workspaceFolders; + return folders && folders.length > 0 ? folders[0].uri.fsPath : os.homedir(); +} + +function safeExec(cmd, cwd, timeout) { + try { + return execSync(cmd, { cwd: cwd || getWorkspaceRoot(), encoding: 'utf8', timeout: timeout || 5000, stdio: ['pipe', 'pipe', 'pipe'] }).trim(); + } catch (_) { return ''; } +} + +function getProjectStructure() { + const root = getWorkspaceRoot(); + try { + const tree = safeExec('find . -maxdepth 3 -not -path "./.git/*" -not -path "./node_modules/*" -not -path "./.venv/*" -not -path "./__pycache__/*" -not -path "./vendor/*" -not -path "./dist/*" -not -path "./build/*" | sort | head -200', root); + return tree || ''; + } catch (_) { return ''; } +} + +function detectProjectType() { + const root = getWorkspaceRoot(); + const indicators = []; + const checks = [ + ['package.json', 'Node.js / JavaScript'], + ['tsconfig.json', 'TypeScript'], + ['composer.json', 'PHP / Composer'], + ['requirements.txt', 'Python'], + ['pyproject.toml', 'Python (modern)'], + ['Cargo.toml', 'Rust'], + ['go.mod', 'Go'], + ['pom.xml', 'Java / Maven'], + ['build.gradle', 'Java / Gradle'], + ['Gemfile', 'Ruby'], + ['.htaccess', 'Apache Web Server'], + ['Dockerfile', 'Docker'], + ['docker-compose.yml', 'Docker Compose'], + ['Makefile', 'Make-based build'], + ['CMakeLists.txt', 'C/C++ CMake'], + ['.env', 'Environment config'], + ['webpack.config.js', 'Webpack'], + ['vite.config.ts', 'Vite'], + ['next.config.js', 'Next.js'], + ['nuxt.config.ts', 'Nuxt'], + ['tailwind.config.js', 'Tailwind CSS'], + ]; + for (const [file, label] of checks) { + try { + if (fs.existsSync(path.join(root, file))) indicators.push(label); + } catch (_) {} + } + return indicators; +} + +function getGitInfo() { + const root = getWorkspaceRoot(); + const branch = safeExec('git rev-parse --abbrev-ref HEAD', root); + if (!branch) return null; + const status = safeExec('git status --porcelain | head -30', root); + const lastCommit = safeExec('git log -1 --format="%h %s (%cr)"', root); + const remoteUrl = safeExec('git remote get-url origin', root); + const dirty = safeExec('git diff --stat | tail -1', root); + const ahead = safeExec('git rev-list --count @{u}..HEAD 2>/dev/null || echo 0', root); + const behind = safeExec('git rev-list --count HEAD..@{u} 2>/dev/null || echo 0', root); + return { branch, status, lastCommit, remoteUrl, dirty, ahead, behind }; +} + +function getOpenEditors() { + const editors = []; + for (const group of vscode.window.tabGroups.all) { + for (const tab of group.tabs) { + if (tab.input && tab.input.uri) { + const rel = vscode.workspace.asRelativePath(tab.input.uri, false); + editors.push(rel); + } + } + } + return editors; +} + +function getDiagnosticsSummary() { + const diags = vscode.languages.getDiagnostics(); + let errors = 0, warnings = 0; + const errorFiles = []; + for (const [uri, items] of diags) { + for (const d of items) { + if (d.severity === vscode.DiagnosticSeverity.Error) { + errors++; + const rel = vscode.workspace.asRelativePath(uri, false); + if (!errorFiles.includes(rel)) errorFiles.push(rel); + } else if (d.severity === vscode.DiagnosticSeverity.Warning) { + warnings++; + } + } + } + return { errors, warnings, errorFiles: errorFiles.slice(0, 10) }; +} + +function getTerminalNames() { + return vscode.window.terminals.map(t => t.name); +} + +function getActiveFileDetails() { + const editor = vscode.window.activeTextEditor; + if (!editor) return null; + const doc = editor.document; + const sel = editor.selection; + const result = { + file: vscode.workspace.asRelativePath(doc.uri, false), + fullPath: doc.fileName, + language: doc.languageId, + lineCount: doc.lineCount, + isDirty: doc.isDirty, + cursorLine: sel.active.line + 1, + cursorCol: sel.active.character + 1, + }; + if (!sel.isEmpty) { + result.selectedText = doc.getText(sel).substring(0, 3000); + result.selectionRange = `L${sel.start.line + 1}-L${sel.end.line + 1}`; + } else { + // Include surrounding context (20 lines around cursor) + const startLine = Math.max(0, sel.active.line - 10); + const endLine = Math.min(doc.lineCount - 1, sel.active.line + 10); + const range = new vscode.Range(startLine, 0, endLine, doc.lineAt(endLine).text.length); + result.surroundingCode = doc.getText(range).substring(0, 2000); + result.contextRange = `L${startLine + 1}-L${endLine + 1}`; + } + return result; +} + +function readFileContent(filePath, maxChars) { + try { + const root = getWorkspaceRoot(); + const fullPath = path.isAbsolute(filePath) ? filePath : path.join(root, filePath); + // Security: don't read outside workspace + if (!fullPath.startsWith(root) && !fullPath.startsWith(os.homedir())) return null; + const stat = fs.statSync(fullPath); + if (stat.size > 500000) return `[File too large: ${(stat.size / 1024).toFixed(0)} KB]`; + return fs.readFileSync(fullPath, 'utf8').substring(0, maxChars || 50000); + } catch (e) { return null; } +} + +function searchFilesInWorkspace(pattern) { + const root = getWorkspaceRoot(); + const results = safeExec(`find . -maxdepth 6 -type f -not -path "./.git/*" -not -path "./node_modules/*" -not -path "./.venv/*" -iname "*${pattern.replace(/[^a-zA-Z0-9._-]/g, '')}*" | head -30`, root); + return results ? results.split('\n').filter(Boolean) : []; +} + +function grepInWorkspace(text, filePattern) { + const root = getWorkspaceRoot(); + const safeText = text.replace(/['"\\$`]/g, ''); + const fileArg = filePattern ? ` --include="${filePattern.replace(/[^a-zA-Z0-9.*_-]/g, '')}"` : ''; + const results = safeExec(`grep -rn --color=never${fileArg} -m 50 "${safeText}" . --exclude-dir=.git --exclude-dir=node_modules --exclude-dir=.venv | head -50`, root, 8000); + return results || ''; +} + +// ═══════════════════════════════════════════════════════════════════════════ +// GIT OPERATIONS TOOLKIT — Full git power from chat +// ═══════════════════════════════════════════════════════════════════════════ + +function gitCommit(message) { + const root = getWorkspaceRoot(); + const safeMsg = message.replace(/"/g, '\\"').replace(/\$/g, '\\$').substring(0, 500); + const addResult = safeExec('git add -A', root); + const commitResult = safeExec(`git commit -m "${safeMsg}" 2>&1`, root, 15000); + return commitResult || 'Nothing to commit'; +} + +function gitDiff(filePath, staged) { + const root = getWorkspaceRoot(); + const stageFlag = staged ? '--staged ' : ''; + const fileArg = filePath ? ` -- "${filePath.replace(/"/g, '')}"` : ''; + return safeExec(`git diff ${stageFlag}--stat${fileArg}`, root, 10000) + '\n' + + safeExec(`git diff ${stageFlag}${fileArg}`, root, 10000).substring(0, 30000); +} + +function gitLog(count, filePath) { + const root = getWorkspaceRoot(); + const n = Math.min(Math.max(parseInt(count) || 10, 1), 100); + const fileArg = filePath ? ` -- "${filePath.replace(/"/g, '')}"` : ''; + return safeExec(`git log --oneline --decorate -n ${n}${fileArg}`, root, 10000); +} + +function gitBlame(filePath, startLine, endLine) { + const root = getWorkspaceRoot(); + const safePath = filePath.replace(/"/g, ''); + const lineRange = (startLine && endLine) ? `-L ${parseInt(startLine)},${parseInt(endLine)} ` : ''; + return safeExec(`git blame ${lineRange}"${safePath}" 2>&1`, root, 10000).substring(0, 20000); +} + +function gitStash(action, message) { + const root = getWorkspaceRoot(); + if (action === 'list') return safeExec('git stash list', root); + if (action === 'pop') return safeExec('git stash pop 2>&1', root, 10000); + if (action === 'drop') return safeExec('git stash drop 2>&1', root); + const safeMsg = message ? ` -m "${message.replace(/"/g, '\\"').substring(0, 200)}"` : ''; + return safeExec(`git stash push${safeMsg} 2>&1`, root, 10000); +} + +function gitBranch(action, branchName) { + const root = getWorkspaceRoot(); + const safeName = (branchName || '').replace(/[^a-zA-Z0-9/_.\-]/g, '').substring(0, 100); + if (action === 'list') return safeExec('git branch -a', root); + if (action === 'create' && safeName) return safeExec(`git checkout -b "${safeName}" 2>&1`, root); + if (action === 'switch' && safeName) return safeExec(`git checkout "${safeName}" 2>&1`, root); + if (action === 'delete' && safeName) return safeExec(`git branch -d "${safeName}" 2>&1`, root); + return 'Invalid branch operation'; +} + +// ═══════════════════════════════════════════════════════════════════════════ +// SYSTEM & PROCESS TOOLS — Server awareness, ports, processes, env +// ═══════════════════════════════════════════════════════════════════════════ + +function getSystemInfo() { + return { + hostname: os.hostname(), + platform: os.platform(), + arch: os.arch(), + cpus: os.cpus().length, + totalMem: (os.totalmem() / 1073741824).toFixed(1) + ' GB', + freeMem: (os.freemem() / 1073741824).toFixed(1) + ' GB', + uptime: (os.uptime() / 3600).toFixed(1) + ' hours', + nodeVersion: process.version, + user: os.userInfo().username, + homeDir: os.homedir(), + loadAvg: os.loadavg().map(l => l.toFixed(2)).join(', '), + }; +} + +function getRunningPorts() { + return safeExec("ss -tlnp 2>/dev/null | grep LISTEN | awk '{print $4, $6}' | head -40", os.homedir(), 8000); +} + +function getPm2Services() { + return safeExec('pm2 jlist 2>/dev/null', os.homedir(), 10000); +} + +function getDiskUsage() { + return safeExec("df -h / /home 2>/dev/null | tail -n +2", os.homedir()); +} + +function getEnvironmentVars(filter) { + const safeFilter = (filter || '').replace(/[^a-zA-Z0-9_*]/g, ''); + if (safeFilter) { + return safeExec(`env | grep -i "${safeFilter}" | sort | head -50`, os.homedir()); + } + return safeExec('env | grep -v "^LS_COLORS\\|^SSH_\\|^LESSOPEN\\|^XDG_" | sort | head -80', os.homedir()); +} + +// ═══════════════════════════════════════════════════════════════════════════ +// DATA FORMAT UTILITIES — JSON, base64, hashing, encoding +// ═══════════════════════════════════════════════════════════════════════════ + +function formatJson(text) { + try { return JSON.stringify(JSON.parse(text), null, 2); } + catch (e) { return 'Invalid JSON: ' + e.message; } +} + +function computeHash(text, algorithm) { + const algo = ['sha256', 'sha512', 'md5', 'sha1'].includes(algorithm) ? algorithm : 'sha256'; + return crypto.createHash(algo).update(text).digest('hex'); +} + +function base64Encode(text) { return Buffer.from(text).toString('base64'); } +function base64Decode(text) { + try { return Buffer.from(text, 'base64').toString('utf8'); } + catch (e) { return 'Invalid base64: ' + e.message; } +} + +function urlEncode(text) { return encodeURIComponent(text); } +function urlDecode(text) { + try { return decodeURIComponent(text); } + catch (e) { return 'Invalid URL encoding: ' + e.message; } +} + +function generateUuid() { return crypto.randomUUID(); } + +function countLines(filePath) { + try { + const root = getWorkspaceRoot(); + const fullPath = path.isAbsolute(filePath) ? filePath : path.join(root, filePath); + const content = fs.readFileSync(fullPath, 'utf8'); + const lines = content.split('\n').length; + const chars = content.length; + const words = content.split(/\s+/).filter(Boolean).length; + const blanks = content.split('\n').filter(l => !l.trim()).length; + return { lines, chars, words, blanks, codeLines: lines - blanks }; + } catch (e) { return { error: e.message }; } +} + +// ═══════════════════════════════════════════════════════════════════════════ +// ADVANCED FILE OPERATIONS — Diff, multi-edit, bulk search-replace +// ═══════════════════════════════════════════════════════════════════════════ + +function diffFiles(fileA, fileB) { + const root = getWorkspaceRoot(); + const pathA = path.isAbsolute(fileA) ? fileA : path.join(root, fileA); + const pathB = path.isAbsolute(fileB) ? fileB : path.join(root, fileB); + return safeExec(`diff -u "${pathA}" "${pathB}" 2>&1`, root, 10000).substring(0, 30000); +} + +function findReplace(filePath, search, replace, isRegex) { + try { + const root = getWorkspaceRoot(); + const fullPath = path.isAbsolute(filePath) ? filePath : path.join(root, filePath); + let content = fs.readFileSync(fullPath, 'utf8'); + let count = 0; + if (isRegex) { + const re = new RegExp(search, 'g'); + content = content.replace(re, (...args) => { count++; return replace; }); + } else { + while (content.includes(search)) { + content = content.replace(search, replace); + count++; + if (count > 10000) break; + } + } + if (count > 0) fs.writeFileSync(fullPath, content, 'utf8'); + return { count, filePath }; + } catch (e) { return { error: e.message }; } +} + +function getRecentFiles(count) { + const root = getWorkspaceRoot(); + const n = Math.min(parseInt(count) || 20, 50); + return safeExec(`find . -maxdepth 4 -type f -not -path "./.git/*" -not -path "./node_modules/*" -printf "%T@ %p\\n" 2>/dev/null | sort -rn | head -${n} | awk '{print $2}'`, root, 8000); +} + +function getFileSizes(pattern) { + const root = getWorkspaceRoot(); + const safePattern = (pattern || '*').replace(/[^a-zA-Z0-9.*_\-/]/g, ''); + return safeExec(`find . -maxdepth 4 -type f -name "${safePattern}" -not -path "./.git/*" -not -path "./node_modules/*" -exec ls -lhS {} + 2>/dev/null | head -30`, root, 8000); +} + +// ═══════════════════════════════════════════════════════════════════════════ +// TEST RUNNER — Detect and run project tests +// ═══════════════════════════════════════════════════════════════════════════ + +function detectTestFramework() { + const root = getWorkspaceRoot(); + const frameworks = []; + try { + const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8')); + const deps = { ...(pkg.devDependencies || {}), ...(pkg.dependencies || {}) }; + if (deps.jest || deps['@jest/core']) frameworks.push({ name: 'jest', cmd: 'npx jest --verbose' }); + if (deps.mocha) frameworks.push({ name: 'mocha', cmd: 'npx mocha' }); + if (deps.vitest) frameworks.push({ name: 'vitest', cmd: 'npx vitest run' }); + if (deps.ava) frameworks.push({ name: 'ava', cmd: 'npx ava' }); + if (pkg.scripts && pkg.scripts.test && pkg.scripts.test !== 'echo "Error: no test specified" && exit 1') { + frameworks.push({ name: 'npm-test', cmd: 'npm test' }); + } + } catch (_) {} + if (fs.existsSync(path.join(root, 'pytest.ini')) || fs.existsSync(path.join(root, 'pyproject.toml'))) { + frameworks.push({ name: 'pytest', cmd: 'python -m pytest -v' }); + } + if (fs.existsSync(path.join(root, 'phpunit.xml')) || fs.existsSync(path.join(root, 'phpunit.xml.dist'))) { + frameworks.push({ name: 'phpunit', cmd: 'vendor/bin/phpunit' }); + } + if (fs.existsSync(path.join(root, 'Cargo.toml'))) { + frameworks.push({ name: 'cargo-test', cmd: 'cargo test' }); + } + if (fs.existsSync(path.join(root, 'go.mod'))) { + frameworks.push({ name: 'go-test', cmd: 'go test ./...' }); + } + return frameworks; +} + +function runTests(framework, testFile) { + const root = getWorkspaceRoot(); + const fw = detectTestFramework().find(f => !framework || f.name === framework) || detectTestFramework()[0]; + if (!fw) return 'No test framework detected'; + const fileArg = testFile ? ` "${testFile.replace(/"/g, '')}"` : ''; + return safeExec(`${fw.cmd}${fileArg} 2>&1`, root, 60000).substring(0, 30000); +} + +// ═══════════════════════════════════════════════════════════════════════════ +// ENHANCED CONTEXT ENGINE — Import graph, complexity, dependency audit +// ═══════════════════════════════════════════════════════════════════════════ + +function getImportGraph(filePath) { + try { + const root = getWorkspaceRoot(); + const fullPath = path.isAbsolute(filePath) ? filePath : path.join(root, filePath); + const content = fs.readFileSync(fullPath, 'utf8'); + const imports = []; + // JS/TS imports + const jsImports = content.matchAll(/(?:import\s+.*?from\s+['"](.+?)['"]|require\s*\(\s*['"](.+?)['"]\s*\))/g); + for (const m of jsImports) imports.push(m[1] || m[2]); + // Python imports + const pyImports = content.matchAll(/(?:from\s+(\S+)\s+import|import\s+(\S+))/g); + for (const m of pyImports) imports.push(m[1] || m[2]); + // PHP includes + const phpIncludes = content.matchAll(/(?:require|include)(?:_once)?\s*[\(]?\s*['"](.+?)['"]/g); + for (const m of phpIncludes) imports.push(m[1]); + // Go imports + const goImports = content.matchAll(/import\s+(?:\(\s*([\s\S]*?)\)|"(.+?)")/g); + for (const m of goImports) { + if (m[1]) { + for (const line of m[1].split('\n')) { + const gm = line.match(/["'](.+?)["']/); + if (gm) imports.push(gm[1]); + } + } else if (m[2]) imports.push(m[2]); + } + // Rust use + const rustUse = content.matchAll(/use\s+(\S+)/g); + for (const m of rustUse) imports.push(m[1].replace(/;$/, '')); + return { file: filePath, imports: [...new Set(imports)] }; + } catch (e) { return { file: filePath, imports: [], error: e.message }; } +} + +function analyzeComplexity(filePath) { + try { + const root = getWorkspaceRoot(); + const fullPath = path.isAbsolute(filePath) ? filePath : path.join(root, filePath); + const content = fs.readFileSync(fullPath, 'utf8'); + const lines = content.split('\n'); + const totalLines = lines.length; + const blankLines = lines.filter(l => !l.trim()).length; + const commentLines = lines.filter(l => { + const t = l.trim(); + return t.startsWith('//') || t.startsWith('#') || t.startsWith('*') || t.startsWith('/*') || t.startsWith(' +
+
+ + + + +
+
+
+

🎙️ Voice Configuration

+
+
1.0x
+
+
+
+ + +
+
+
+

📊 Voice Usage

+
+
TTS Requests
+
STT Requests
+
Characters
+
Cost ($)
+
+
+
+ + + +
+
+
+

🧠 Memory Engine

+

View and search facts from Alfred's decay memory system.

+
+ +
+
+
+

💰 Cost Tracker

+

Real-time token usage and cost tracking across all providers.

+
+
0
Session Tokens
+
$0.00
Session Cost
+
0
Messages
+
0m
Duration
+
+
+ +
+
+
+

🔄 Session Persistence

+

Save and resume conversations across IDE restarts.

+
+ + + +
+
+
+
+

🏗️ Model Router

+

Current model routing is handled by the Agent/Model dropdowns in the Chat tab. Use Auto mode for smart routing across providers.

+

Configured providers: Anthropic, OpenAI, Google, Groq, OpenRouter, Ollama (local)

+
+
+ + + +`; +} + +function deactivate() {} + +function getWorkspaceStatusHTML(token) { + return ` + + + + +

🖥 Workspace Status

+
+

Loading workspace data...

+ +`; +} + +// ===== V5: Voice AI Full Panel ===== +function getVoiceAIPanelHTML(token) { + return ` + +

🎙️ Voice AI — Full Dashboard

+

Voice Configuration

+

Voice: + Speed: 1.0x

+ +
+

Voice Agents

Loading...

+

Usage Statistics

+
TTS Requests
+
STT Requests
+
Characters
+
Cost
+
+`; +} + +// ===== V5: Memory Engine Panel ===== +function getMemoryPanelHTML(token) { + return ` + +

🧠 Memory Engine — Decay Memory System

+

Search Memories

+ + +
+

Memory Stats

+
+
Total Facts
+
Active
+
Decayed
+
Permanent
+
+
+

Recent Memories

Loading...

+`; +} + +// ===== V5: Cost & Usage Tracker Panel ===== +function getCostPanelHTML(token) { + return ` + +

💰 Cost & Usage Tracker

+

Session Summary

+
+
Total Tokens
+
Total Cost
+
Messages
+
Avg Tokens/Msg
+
+
+

By Provider

ProviderRequestsTokensCost
Loading...
+

By Model

ModelRequestsIn TokensOut TokensCost
Loading...
+

Balance

+
+ Remaining: + +
+
+
+`; +} + + +function getVaultPanelHTML(token) { + const baseUrl = 'https://gositeme.com/kingdom-vault/?embed'; + return ` + + +
+ Kingdom Vault + + +
+ + +`; +} + +module.exports = { activate, deactivate }; diff --git a/extensions.json b/extensions.json new file mode 100644 index 0000000..d18ff45 --- /dev/null +++ b/extensions.json @@ -0,0 +1,10 @@ +{ + "recommendations": [ + "gositeme.alfred-commander" + ], + "unwantedRecommendations": [ + "ms-vscode-remote.remote-ssh", + "ms-vscode.remote-server", + "ms-vscode.remote-explorer" + ] +} diff --git a/media/alfred-icon.svg b/media/alfred-icon.svg new file mode 100644 index 0000000..62c2921 --- /dev/null +++ b/media/alfred-icon.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/media/walkthrough/meet-alfred.md b/media/walkthrough/meet-alfred.md new file mode 100644 index 0000000..804ad39 --- /dev/null +++ b/media/walkthrough/meet-alfred.md @@ -0,0 +1,17 @@ +# Meet Alfred + +Alfred is your AI coding companion, built into the sidebar. + +## What Alfred Can Do +- **Answer questions** about your code, frameworks, and tools +- **Generate code** from natural language descriptions +- **Debug issues** by analyzing errors and suggesting fixes +- **Explain code** — select any block and ask "what does this do?" +- **Run tools** — file search, terminal commands, web lookups + +## How to Start +1. Click the **Alfred icon** (🅰️) in the activity bar (left side) +2. Type your question or request in the chat input +3. Press Enter — Alfred responds in real time + +Alfred remembers your conversation context, so you can have natural multi-turn discussions about your code. diff --git a/media/walkthrough/models.md b/media/walkthrough/models.md new file mode 100644 index 0000000..054ff49 --- /dev/null +++ b/media/walkthrough/models.md @@ -0,0 +1,18 @@ +# AI Models + +Alfred IDE supports multiple AI providers and models. + +## Available Tiers + +| Tier | Best For | Examples | +|------|----------|---------| +| **Leaf** | Simple tasks, quick answers | GPT-4o-mini, local Ollama | +| **Mid** | Code generation, analysis | Claude 3.5 Sonnet, GPT-4o | +| **Frontier** | Complex reasoning, architecture | Claude Opus, GPT-4 | +| **Max** | Research, multi-step planning | Claude Opus (extended) | + +## How to Switch +Use the **model dropdown** at the top of the Alfred panel to select your preferred model. + +## Local Models +If Ollama is running, local models appear automatically — your code never leaves your machine. diff --git a/media/walkthrough/shortcuts.md b/media/walkthrough/shortcuts.md new file mode 100644 index 0000000..b7cca88 --- /dev/null +++ b/media/walkthrough/shortcuts.md @@ -0,0 +1,24 @@ +# Keyboard Shortcuts + +Master these to work at full speed. + +## Alfred Commands +| Shortcut | Action | +|----------|--------| +| `Ctrl+Shift+Alt+O` | Open Alfred Panel | +| `Ctrl+Shift+Alt+A` | Toggle Voice Mode | + +## Essential IDE Shortcuts +| Shortcut | Action | +|----------|--------| +| `Ctrl+P` | Quick File Open | +| `Ctrl+Shift+P` | Command Palette | +| `Ctrl+`` ` | Toggle Terminal | +| `Ctrl+B` | Toggle Sidebar | +| `Ctrl+Shift+E` | File Explorer | +| `Ctrl+Shift+F` | Search Across Files | +| `Ctrl+Shift+G` | Source Control | +| `F5` | Start Debugging | +| `Ctrl+/` | Toggle Line Comment | +| `Alt+↑/↓` | Move Line Up/Down | +| `Ctrl+D` | Select Next Occurrence | diff --git a/media/walkthrough/sovereign.md b/media/walkthrough/sovereign.md new file mode 100644 index 0000000..65e7edb --- /dev/null +++ b/media/walkthrough/sovereign.md @@ -0,0 +1,27 @@ +# Sovereign Development + +Alfred IDE is built on one principle: **your code is yours**. + +## What We Don't Do +- ❌ No telemetry or usage tracking +- ❌ No analytics or behavior profiling +- ❌ No data sold to third parties +- ❌ No phone-home to Microsoft, Google, or anyone +- ❌ No extension marketplace surveillance + +## What We Do +- ✅ All AI calls go through your GoSiteMe account +- ✅ Conversations are stored in YOUR database +- ✅ Local Ollama models keep everything on-device +- ✅ Secret redaction engine scrubs credentials from all output +- ✅ Post-quantum encryption available via Veil Protocol + +## The GoSiteMe Ecosystem +Alfred IDE is one pillar of the sovereign computing stack: +- **Alfred Linux** — AI-native operating system +- **Alfred Browser** — zero-tracking web browser +- **Alfred Mobile** — sovereign smartphone OS +- **Veil** — post-quantum encrypted messaging +- **MetaDome** — VR worlds with 51M+ AI agents + +Welcome to the kingdom. 🏰 diff --git a/media/walkthrough/stats.md b/media/walkthrough/stats.md new file mode 100644 index 0000000..b35bc60 --- /dev/null +++ b/media/walkthrough/stats.md @@ -0,0 +1,16 @@ +# Account & Usage + +Monitor your plan, usage, and billing from inside the IDE. + +## How to Access +Click your **username** in the bottom status bar, or run: +- Command Palette → "Alfred: Account & Usage Stats" + +## What You'll See +- **Plan**: Your current subscription tier +- **Token Usage**: How many AI tokens you've consumed +- **Credit Balance**: Remaining credits for the billing period +- **Active Services**: Which ecosystem services are linked + +## Commander Access +If you're the Commander (client_id 33), you have unlimited access — no token limits, no restrictions. diff --git a/media/walkthrough/voice.md b/media/walkthrough/voice.md new file mode 100644 index 0000000..c2ca72b --- /dev/null +++ b/media/walkthrough/voice.md @@ -0,0 +1,18 @@ +# Voice Commands + +Talk to your IDE — Alfred listens, transcribes, and responds. + +## How It Works +1. Click the **🎤 microphone** button in the Alfred panel +2. Speak naturally — your voice is transcribed in real time +3. Alfred processes your request and responds + +## Voice Architecture +- **STT (Speech-to-Text)**: Whisper-based transcription +- **LLM**: Your selected AI model processes the request +- **TTS (Text-to-Speech)**: Kokoro voices read the response back + +## Tips +- Speak clearly and at a normal pace +- You can say "stop" or click the mic again to end recording +- Voice works best with short, focused requests diff --git a/package.json b/package.json new file mode 100644 index 0000000..76c665c --- /dev/null +++ b/package.json @@ -0,0 +1,168 @@ +{ + "name": "alfred-commander", + "displayName": "Alfred IDE Assistant \u2014 Full IDE Chat & Voice", + "description": "Alfred Commander v5 Kingdom Edition \u2014 AI chat, voice AI, model routing, memory engine, cost tracking, session persistence, fleet commander. The sovereign IDE brain.", + "version": "5.0.0", + "publisher": "gositeme", + "repository": { + "type": "git", + "url": "https://alfredlinux.com/forge/commander/alfred-ide.git" + }, + "homepage": "https://alfredlinux.com/forge/commander/alfred-ide", + "engines": { + "vscode": "^1.70.0" + }, + "categories": [ + "Other" + ], + "activationEvents": [ + "onStartupFinished" + ], + "main": "./extension.js", + "contributes": { + "configurationDefaults": { + "window.menuBarVisibility": "visible", + "chat.disableAIFeatures": false + }, + "commands": [ + { + "command": "alfred-commander.open", + "title": "Alfred: Open Panel" + }, + { + "command": "alfred-commander.toggle", + "title": "Alfred: Toggle Mic" + }, + { + "command": "alfred-commander.showStats", + "title": "Alfred: Account & Usage Stats" + }, + { + "command": "alfred-commander.welcome", + "title": "Alfred: Getting Started" + }, + { + "command": "alfred-commander.workspaceStatus", + "title": "Alfred: Workspace Status" + }, + { + "command": "alfred-commander.voicePanel", + "title": "Alfred: Voice AI Panel" + }, + { + "command": "alfred-commander.memoryPanel", + "title": "Alfred: Memory Engine" + }, + { + "command": "alfred-commander.costPanel", + "title": "Alfred: Cost & Usage Tracker" + }, + { + "command": "alfred-commander.vaultPanel", + "title": "Alfred: Kingdom Vault" + }, + { + "command": "alfred-commander.vaultPanel", + "title": "Alfred: Kingdom Vault" + } + ], + "keybindings": [ + { + "command": "alfred-commander.open", + "key": "ctrl+shift+alt+o", + "mac": "cmd+shift+alt+o" + }, + { + "command": "alfred-commander.toggle", + "key": "ctrl+shift+alt+a", + "mac": "cmd+shift+alt+a" + }, + { + "command": "alfred-commander.voicePanel", + "key": "ctrl+shift+alt+v", + "mac": "cmd+shift+alt+v" + } + ], + "viewsContainers": { + "activitybar": [ + { + "id": "alfred-commander-container", + "title": "Alfred", + "icon": "media/alfred-icon.svg" + } + ] + }, + "views": { + "alfred-commander-container": [ + { + "type": "webview", + "id": "alfred-commander.panel", + "name": "Alfred", + "visibility": "visible" + } + ] + }, + "walkthroughs": [ + { + "id": "alfred-ide-getting-started", + "title": "Getting Started with Alfred IDE", + "description": "Your sovereign development environment \u2014 AI-powered, zero-tracking, fully yours.", + "steps": [ + { + "id": "meet-alfred", + "title": "Meet Alfred \u2014 Your AI Companion", + "description": "Alfred lives in the sidebar. Click the Alfred icon in the activity bar to open the chat panel. Ask anything \u2014 code questions, file operations, debugging help.\n\n[Open Alfred Panel](command:alfred-commander.open)", + "media": { + "markdown": "media/walkthrough/meet-alfred.md" + } + }, + { + "id": "voice-commands", + "title": "Talk to Your IDE", + "description": "Alfred supports voice input. Click the microphone button or press ``Ctrl+Shift+Alt+A`` to toggle voice mode. Speak naturally \u2014 Alfred transcribes and responds.\n\n[Toggle Voice](command:alfred-commander.toggle)", + "media": { + "markdown": "media/walkthrough/voice.md" + } + }, + { + "id": "choose-model", + "title": "Choose Your AI Model", + "description": "Switch between AI providers and models using the dropdown at the top of the Alfred panel. Available models include Claude, GPT, local Ollama models, and more.", + "media": { + "markdown": "media/walkthrough/models.md" + } + }, + { + "id": "account-stats", + "title": "Check Your Usage & Plan", + "description": "Click your username in the status bar (bottom-left) to see your account details, token usage, plan info, and billing.\n\n[View Account Stats](command:alfred-commander.showStats)", + "media": { + "markdown": "media/walkthrough/stats.md" + } + }, + { + "id": "keyboard-shortcuts", + "title": "Essential Shortcuts", + "description": "Master these shortcuts to work faster:\n- ``Ctrl+Shift+Alt+O`` \u2014 Open Alfred Panel\n- ``Ctrl+Shift+Alt+A`` \u2014 Toggle Voice\n- ``Ctrl+``` `` \u2014 Open Terminal\n- ``Ctrl+P`` \u2014 Quick File Open\n- ``Ctrl+Shift+P`` \u2014 Command Palette", + "media": { + "markdown": "media/walkthrough/shortcuts.md" + } + }, + { + "id": "sovereign-ide", + "title": "Your Sovereign IDE", + "description": "Alfred IDE tracks nothing. No telemetry, no usage analytics, no data collection. Your code stays on your machine. Your conversations stay private. Welcome to sovereign development.", + "media": { + "markdown": "media/walkthrough/sovereign.md" + } + } + ] + } + ] + }, + "__metadata": { + "installedTimestamp": 1774281381634, + "targetPlatform": "undefined", + "size": 75665 + } +} \ No newline at end of file diff --git a/package.json.bak.vault b/package.json.bak.vault new file mode 100644 index 0000000..0537ff0 --- /dev/null +++ b/package.json.bak.vault @@ -0,0 +1,187 @@ +{ + "name": "alfred-commander", + "displayName": "Alfred IDE Assistant \u2014 Full IDE Chat & Voice", + "description": "Alfred Commander v5 Kingdom Edition \u2014 AI chat, voice AI, model routing, memory engine, cost tracking, session persistence, fleet commander. The sovereign IDE brain.", + "version": "5.0.0", + "publisher": "gositeme", + "repository": { + "type": "git", + "url": "https://alfredlinux.com/forge/commander/alfred-ide.git" + }, + "homepage": "https://alfredlinux.com/forge/commander/alfred-ide", + "engines": { + "vscode": "^1.70.0" + }, + "categories": [ + "Other" + ], + "activationEvents": [ + "onStartupFinished" + ], + "main": "./extension.js", + "contributes": { + "configurationDefaults": { + "window.menuBarVisibility": "visible" + }, + "commands": [ + { + "command": "alfred-commander.open", + "title": "Alfred: Open Panel" + }, + { + "command": "alfred-commander.toggle", + "title": "Alfred: Toggle Mic" + }, + { + "command": "alfred-commander.showStats", + "title": "Alfred: Account & Usage Stats" + }, + { + "command": "alfred-commander.welcome", + "title": "Alfred: Getting Started" + }, + { + "command": "alfred-commander.workspaceStatus", + "title": "Alfred: Workspace Status" + }, + { + "command": "alfred-commander.voicePanel", + "title": "Alfred: Voice AI Panel" + }, + { + "command": "alfred-commander.memoryPanel", + "title": "Alfred: Memory Engine" + }, + { + "command": "alfred-commander.costPanel", + "title": "Alfred: Cost & Usage Tracker" + }, + { + "command": "alfred-commander.vaultPanel", + "title": "Alfred: Kingdom Vault" + } + ], + "keybindings": [ + { + "command": "alfred-commander.open", + "key": "ctrl+shift+alt+o", + "mac": "cmd+shift+alt+o" + }, + { + "command": "alfred-commander.toggle", + "key": "ctrl+shift+alt+a", + "mac": "cmd+shift+alt+a" + }, + { + "command": "alfred-commander.voicePanel", + "key": "ctrl+shift+alt+v", + "mac": "cmd+shift+alt+v" + } + ], + "viewsContainers": { + "activitybar": [ + { + "id": "alfred-commander-container", + "title": "Alfred", + "icon": "media/alfred-icon.svg" + } + ] + }, + "chatParticipants": [ + { + "id": "alfred", + "fullName": "Alfred AI", + "name": "alfred", + "description": "Your sovereign AI coding assistant \u2014 powered by GoSiteMe", + "isDefault": true, + "isSticky": true, + "commands": [ + { + "name": "explain", + "description": "Explain the selected code" + }, + { + "name": "fix", + "description": "Fix issues in the selected code" + }, + { + "name": "voice", + "description": "Open Alfred Voice AI panel" + } + ] + } + ], + "views": { + "alfred-commander-container": [ + { + "type": "webview", + "id": "alfred-commander.panel", + "name": "Alfred", + "visibility": "visible" + } + ] + }, + "walkthroughs": [ + { + "id": "alfred-ide-getting-started", + "title": "Getting Started with Alfred IDE", + "description": "Your sovereign development environment \u2014 AI-powered, zero-tracking, fully yours.", + "steps": [ + { + "id": "meet-alfred", + "title": "Meet Alfred \u2014 Your AI Companion", + "description": "Alfred lives in the sidebar. Click the Alfred icon in the activity bar to open the chat panel. Ask anything \u2014 code questions, file operations, debugging help.\n\n[Open Alfred Panel](command:alfred-commander.open)", + "media": { + "markdown": "media/walkthrough/meet-alfred.md" + } + }, + { + "id": "voice-commands", + "title": "Talk to Your IDE", + "description": "Alfred supports voice input. Click the microphone button or press ``Ctrl+Shift+Alt+A`` to toggle voice mode. Speak naturally \u2014 Alfred transcribes and responds.\n\n[Toggle Voice](command:alfred-commander.toggle)", + "media": { + "markdown": "media/walkthrough/voice.md" + } + }, + { + "id": "choose-model", + "title": "Choose Your AI Model", + "description": "Switch between AI providers and models using the dropdown at the top of the Alfred panel. Available models include Claude, GPT, local Ollama models, and more.", + "media": { + "markdown": "media/walkthrough/models.md" + } + }, + { + "id": "account-stats", + "title": "Check Your Usage & Plan", + "description": "Click your username in the status bar (bottom-left) to see your account details, token usage, plan info, and billing.\n\n[View Account Stats](command:alfred-commander.showStats)", + "media": { + "markdown": "media/walkthrough/stats.md" + } + }, + { + "id": "keyboard-shortcuts", + "title": "Essential Shortcuts", + "description": "Master these shortcuts to work faster:\n- ``Ctrl+Shift+Alt+O`` \u2014 Open Alfred Panel\n- ``Ctrl+Shift+Alt+A`` \u2014 Toggle Voice\n- ``Ctrl+``` `` \u2014 Open Terminal\n- ``Ctrl+P`` \u2014 Quick File Open\n- ``Ctrl+Shift+P`` \u2014 Command Palette", + "media": { + "markdown": "media/walkthrough/shortcuts.md" + } + }, + { + "id": "sovereign-ide", + "title": "Your Sovereign IDE", + "description": "Alfred IDE tracks nothing. No telemetry, no usage analytics, no data collection. Your code stays on your machine. Your conversations stay private. Welcome to sovereign development.", + "media": { + "markdown": "media/walkthrough/sovereign.md" + } + } + ] + } + ] + }, + "__metadata": { + "installedTimestamp": 1774281381634, + "targetPlatform": "undefined", + "size": 75665 + } +} \ No newline at end of file