[tab] src/extension.ts (typescript)
import * as vscode from 'vscode';

export function activate(context: vscode.ExtensionContext) {

	console.log('[Crowd Pilot] Extension activated');

	// Configure terminal to allow tab keybinding to work
	(async () => {
		const config = vscode.workspace.getConfiguration('terminal.integrated');
		const commandsToSkipShell = config.get<string[]>('commandsToSkipShell', []);
		let updated = false;
		if (!commandsToSkipShell.includes('crowd-pilot.testRun')) {
			commandsToSkipShell.push('crowd-pilot.testRun');
			updated = true;
		}
		if (!commandsToSkipShell.includes('crowd-pilot.hideUi')) {
			commandsToSkipShell.push('crowd-pilot.hideUi');
			updated = true;
		}
		if (updated) {
			await config.update('commandsToSkipShell', commandsToSkipShell, vscode.ConfigurationTarget.Global);
		}
		// Prime terminal subsystem after intercept is enabled (NOTE: this is a workaround)
		await primeTerminalSubsystem();
	})().catch((err) => console.error('[Crowd Pilot] Startup initialization error:', err));

	const testRun = vscode.commands.registerCommand('crowd-pilot.testRun', async () => {
		// If preview UI is not open, show it first and return. Next Tab will execute actions.
		if (!uiPanel) {
			showPreviewUI();
			return;
		}

		const editor = vscode.window.activeTextEditor;
		const doc = editor!.document;
		const term = vscode.window.terminals[0] ?? vscode.window.createTerminal('Test');
		const git = vscode.extensions.getExtension('vscode.git')?.exports?.getAPI(1);
		const repo = git?.repositories?.[0];
	
		// Close preview UI before executing actions
		hidePreviewUI();

		await vscode.window.showTextDocument(doc);
		editor!.selections = [new vscode.Selection(0, 0, 0, 0)];
		await editor!.edit(e => e.insert(new vscode.Position(0, 0), 'hello world
'));
		term.show();
		term.sendText('echo VSCode test');
		//await repo?.pull();
	
		vscode.window.showInformationMessage('All actions emitted');
	  });

	const hideUi = vscode.commands.registerCommand('crowd-pilot.hideUi', () => {
		hidePreviewUI();
	});

	context.subscriptions.push(testRun, hideUi);
}

export function deactivate() {}

async function primeTerminalSubsystem(): Promise<void> {
	try {
		if (vscode.window.terminals.length > 0) {
			return;
		}
		const opened = new Promise<void>((resolve) => {
			const d = vscode.window.onDidOpenTerminal(() => {
				try { d.dispose(); } catch {}
				resolve();
			});
		});
		const t = vscode.window.createTerminal('Crowd Pilot Prime');
		await Promise.race([
			opened,
			new Promise<void>(r => setTimeout(r, 150))
		]);
		try { t.dispose(); } catch {}
		await new Promise<void>(r => setTimeout(r, 50));
		console.log('[Crowd Pilot] Primed terminal subsystem');
	} catch (err) {
		console.error('[Crowd Pilot] Failed to prime terminal subsystem:', err);
	}
}

// -------------------- UI State & Helpers --------------------
const UI_CONTEXT_KEY = 'crowdPilot.uiVisible';
let uiPanel: vscode.WebviewPanel | undefined;

function showPreviewUI(): void {
	if (uiPanel) {
		try {
			uiPanel.reveal(undefined, true /* preserveFocus */);
		} catch {}
		return;
	}
	uiPanel = vscode.window.createWebviewPanel(
		'crowdPilotPreview',
		'Crowd Pilot Preview',
		{ viewColumn: vscode.ViewColumn.Beside, preserveFocus: true },
		{ enableScripts: true, retainContextWhenHidden: true }
	);
	uiPanel.webview.html = getPreviewHtml();
	vscode.commands.executeCommand('setContext', UI_CONTEXT_KEY, true);
	uiPanel.onDidDispose(() => {
		uiPanel = undefined;
		vscode.commands.executeCommand('setContext', UI_CONTEXT_KEY, false);
	});

	// Allow Escape within the webview to close it
	uiPanel.webview.onDidReceiveMessage((msg) => {
		if (msg?.type === 'escape') {
			hidePreviewUI();
		}
	});
}

function hidePreviewUI(): void {
	if (!uiPanel) {
		vscode.commands.executeCommand('setContext', UI_CONTEXT_KEY, false);
		return;
	}
	try { uiPanel.dispose(); } catch {}
	uiPanel = undefined;
	vscode.commands.executeCommand('setContext', UI_CONTEXT_KEY, false);
}

function getPreviewHtml(): string {
	const styles = `
		body { font-family: var(--vscode-font-family); color: var(--vscode-foreground); background: var(--vscode-editor-background); margin: 0; }
		.container { padding: 16px; }
		h1 { font-size: 16px; margin: 0 0 8px; }
		p { margin: 0 0 12px; }
		ul { margin: 0 0 12px 18px; }
		.code { font-family: var(--vscode-editor-font-family); background: var(--vscode-editor-inactiveSelectionBackground); padding: 2px 4px; border-radius: 3px; }
		.hint { opacity: 0.8; }
	`;
	const script = `
		const vscode = acquireVsCodeApi();
		window.addEventListener('keydown', (e) => {
			if (e.key === 'Escape') {
				vscode.postMessage({ type: 'escape' });
			}
		});
	`;
	return `<!DOCTYPE html>
	<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<title>Crowd Pilot Preview</title>
		<style>${styles}</style>
	</head>
	<body>
		<div class="container">
			<h1>Upcoming actions</h1>
			<p>This step will perform the following changes:</p>
			<ul>
				<li>Focus the active text document</li>
				<li>Edit the document by inserting <span class="code">hello world</span> at the top</li>
				<li>Focus the terminal</li>
				<li>Run <span class="code">echo VSCode test</span> in the terminal</li>
			</ul>
			<p class="hint">Press <span class="code">Tab</span> again to run, or <span class="code">Esc</span> to hide.</p>
		</div>
		<script>${script}</script>
	</body>
	</html>`;
}