/** * Workbench Patcher — Install/uninstall integration scripts into workbench.html. * * Handles the file-level modification of Antigravity's workbench.html * to include/remove custom script tags. * * @module integration/workbench-patcher * * @internal */ import * as fs from 'fs'; import * as path from 'path'; /** Default prefix for generated files */ const FILE_PREFIX = 'ag-sdk'; /** * Manages patching/unpatching of Antigravity's workbench.html. */ export class WorkbenchPatcher { private readonly _workbenchDir: string; private readonly _workbenchHtml: string; private readonly _scriptPath: string; private readonly _heartbeatPath: string; private readonly _slug: string; private readonly _markerStart: string; private readonly _markerEnd: string; /** * @param namespace - Unique slug for this extension (e.g. 'kanezal-better-antigravity'). * Used to namespace all generated files and HTML markers so multiple * SDK-based extensions can coexist without conflicts. */ constructor(namespace: string = 'default') { // Resolve Antigravity install path const appData = process.env.LOCALAPPDATA || ''; this._workbenchDir = path.join( appData, 'Programs', 'Antigravity', 'resources', 'app', 'out', 'vs', 'code', 'electron-browser', 'workbench', ); this._workbenchHtml = path.join(this._workbenchDir, 'workbench.html'); this._slug = namespace.replace(/[^a-zA-Z0-9-]/g, '-'); this._scriptPath = path.join(this._workbenchDir, `${FILE_PREFIX}-${this._slug}.js`); this._heartbeatPath = path.join(this._workbenchDir, `${FILE_PREFIX}-${this._slug}-heartbeat`); this._markerStart = ``; this._markerEnd = ``; } /** * Check if workbench.html exists and is accessible. */ isAvailable(): boolean { return fs.existsSync(this._workbenchHtml); } /** * Check if our integration is currently installed. */ isInstalled(): boolean { if (!this.isAvailable()) return false; try { const content = fs.readFileSync(this._workbenchHtml, 'utf8'); return content.includes(this._markerStart); } catch { return false; } } /** * Install the integration script. * * 1. Writes the script file to the workbench directory * 2. Patches workbench.html to include a `, this._markerEnd, ].join('\n'); html = html.replace('', `${scriptTag}\n`); fs.writeFileSync(this._workbenchHtml, html, 'utf8'); // Create empty titles JSON if it doesn't exist (prevents console 404) const titlesPath = path.join(this._workbenchDir, `ag-sdk-titles-${this._slug}.json`); if (!fs.existsSync(titlesPath)) { fs.writeFileSync(titlesPath, '{}', 'utf8'); } } /** * Remove the integration. * * 1. Removes the lines const legacyTagRegex = /