From ab501fdb251b947ad91b7c76423efac5793a444f Mon Sep 17 00:00:00 2001 From: Alfred Date: Tue, 7 Apr 2026 13:00:19 -0400 Subject: [PATCH] v2.1.0: Add update-check and pair-desktop platform tools (50 tools total) --- extension.js | 134 +++++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 2 +- 2 files changed, 135 insertions(+), 1 deletion(-) diff --git a/extension.js b/extension.js index a9ad331..9ed9e78 100644 --- a/extension.js +++ b/extension.js @@ -605,6 +605,9 @@ const TOOL_REGISTRY = [ // EXECUTION { name: 'run-terminal', description: 'Execute a command in a new terminal', params: { command: 'string' } }, { name: 'insert-code', description: 'Insert code at cursor position in active editor', params: { code: 'string' } }, + // PLATFORM + { name: 'update-check', description: 'Check for Alfred IDE updates (compares installed vs latest release)', params: { platform: 'string (windows|web|linux, default: auto-detect)' } }, + { name: 'pair-desktop', description: 'Pair this desktop IDE with your gositeme.com account (generates a code to confirm on the web)', params: {} }, ]; function buildToolAwareness() { @@ -890,6 +893,105 @@ function readLocalIdeToken() { } } +// ────── UPDATE CHECK ────── +function checkForUpdates(platform) { + return new Promise((resolve) => { + const p = platform || (process.platform === 'win32' ? 'windows' : process.platform === 'linux' ? 'linux' : 'web'); + const req = https.request({ + hostname: 'gositeme.com', port: 443, + path: `/api/alfred-ide-version.php?platform=${encodeURIComponent(p)}`, + method: 'GET', + headers: { 'X-Alfred-Source': 'ide-extension' }, + timeout: 15000 + }, (res) => { + let data = ''; + res.on('data', chunk => data += chunk); + res.on('end', () => { + try { + const j = JSON.parse(data); + if (j.error) { resolve({ error: j.error }); return; } + const currentVer = vscode.extensions.getExtension('gositeme.alfred-commander')?.packageJSON?.version || '2.0.1'; + resolve({ + platform: p, + currentVersion: currentVer, + latestVersion: j.version || 'unknown', + commanderVersion: j.commander_version || 'unknown', + releaseDate: j.release_date || '', + downloadUrl: j.download_url || '', + changelog: j.changelog || '', + updateAvailable: j.version && j.version !== currentVer + }); + } catch { resolve({ error: 'Invalid response from update server' }); } + }); + }); + req.on('error', (e) => resolve({ error: `Connection failed: ${e.message}` })); + req.on('timeout', () => { req.destroy(); resolve({ error: 'Update check timed out' }); }); + req.end(); + }); +} + +// ────── DESKTOP PAIRING ────── +function requestDesktopPairing() { + return new Promise((resolve) => { + const postData = JSON.stringify({ action: 'request' }); + const req = https.request({ + hostname: 'gositeme.com', port: 443, + path: '/api/alfred-ide-pair.php', + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Content-Length': Buffer.byteLength(postData), + 'X-Alfred-Source': 'ide-extension' + }, + timeout: 15000 + }, (res) => { + let data = ''; + res.on('data', chunk => data += chunk); + res.on('end', () => { + try { resolve(JSON.parse(data)); } + catch { resolve({ error: 'Invalid pairing response' }); } + }); + }); + req.on('error', (e) => resolve({ error: `Pairing request failed: ${e.message}` })); + req.on('timeout', () => { req.destroy(); resolve({ error: 'Pairing request timed out' }); }); + req.write(postData); + req.end(); + }); +} + +function pollPairingStatus(pairId) { + return new Promise((resolve) => { + const req = https.request({ + hostname: 'gositeme.com', port: 443, + path: `/api/alfred-ide-pair.php?action=poll&pair_id=${encodeURIComponent(pairId)}`, + method: 'GET', + headers: { 'X-Alfred-Source': 'ide-extension' }, + timeout: 10000 + }, (res) => { + let data = ''; + res.on('data', chunk => data += chunk); + res.on('end', () => { + try { resolve(JSON.parse(data)); } + catch { resolve({ error: 'Invalid poll response' }); } + }); + }); + req.on('error', (e) => resolve({ error: `Poll failed: ${e.message}` })); + req.on('timeout', () => { req.destroy(); resolve({ error: 'Poll timed out' }); }); + req.end(); + }); +} + +function savePairedToken(token) { + const sessionPath = '/home/gositeme/.alfred-ide/session.json'; + try { + const dir = require('path').dirname(sessionPath); + if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true }); + const session = { token, paired_at: Math.floor(Date.now() / 1000), expires_at: Math.floor(Date.now() / 1000) + 90 * 86400 }; + fs.writeFileSync(sessionPath, JSON.stringify(session, null, 2)); + return true; + } catch { return false; } +} + function activate(context) { const provider = new AlfredCommanderProvider(context.extensionUri, context); @@ -1486,6 +1588,38 @@ class AlfredCommanderProvider { } } webviewView.webview.postMessage({ type: 'diagnostics-detail-result', diagnostics: detailed.slice(0, 100), id: msg.id }); + // ────── PLATFORM TOOLS ────── + } else if (msg.type === 'update-check') { + checkForUpdates(msg.platform).then(result => { + webviewView.webview.postMessage({ type: 'update-check-result', result, id: msg.id }); + }); + } else if (msg.type === 'pair-desktop') { + requestDesktopPairing().then(result => { + if (result.error) { + webviewView.webview.postMessage({ type: 'pair-result', result, id: msg.id }); + return; + } + webviewView.webview.postMessage({ type: 'pair-code', code: result.pairing_code, pairId: result.pair_id, id: msg.id }); + let attempts = 0; + const maxAttempts = 60; + const pollInterval = setInterval(async () => { + attempts++; + if (attempts > maxAttempts) { + clearInterval(pollInterval); + webviewView.webview.postMessage({ type: 'pair-result', result: { error: 'Pairing expired — code was not confirmed within 10 minutes' }, id: msg.id }); + return; + } + const status = await pollPairingStatus(result.pair_id); + if (status.status === 'approved' && status.token) { + clearInterval(pollInterval); + savePairedToken(status.token); + webviewView.webview.postMessage({ type: 'pair-result', result: { success: true, message: 'Desktop paired successfully! You are now connected to your gositeme.com account.' }, id: msg.id }); + } else if (status.status === 'expired' || status.error) { + clearInterval(pollInterval); + webviewView.webview.postMessage({ type: 'pair-result', result: { error: status.error || 'Pairing code expired' }, id: msg.id }); + } + }, 10000); + }); } }); diff --git a/package.json b/package.json index 8f9074f..0cd80bf 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "alfred-commander", "displayName": "Alfred IDE Assistant — Full IDE Chat & Voice", "description": "Fresh Alfred panel: all agents & models, voice STT/TTS, attachments, hands-free. IDE shortcuts are explicit buttons — chat text always goes to AI.", - "version": "2.0.0", + "version": "2.1.0", "publisher": "gositeme", "repository": { "type": "git",