v2.1.0: Add update-check and pair-desktop platform tools (50 tools total)

This commit is contained in:
Alfred 2026-04-07 13:00:19 -04:00
parent 5ab18db74e
commit ab501fdb25
2 changed files with 135 additions and 1 deletions

View File

@ -605,6 +605,9 @@ const TOOL_REGISTRY = [
// EXECUTION // EXECUTION
{ name: 'run-terminal', description: 'Execute a command in a new terminal', params: { command: 'string' } }, { 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' } }, { 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() { 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) { function activate(context) {
const provider = new AlfredCommanderProvider(context.extensionUri, 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 }); 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);
});
} }
}); });

View File

@ -2,7 +2,7 @@
"name": "alfred-commander", "name": "alfred-commander",
"displayName": "Alfred IDE Assistant — Full IDE Chat & Voice", "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.", "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", "publisher": "gositeme",
"repository": { "repository": {
"type": "git", "type": "git",