@inspecto-dev/plugin 0.2.0-alpha.2 → 0.2.0-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +29 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +29 -13
- package/dist/index.js.map +1 -1
- package/dist/legacy/rspack/index.cjs +30 -14
- package/dist/legacy/rspack/index.cjs.map +1 -1
- package/dist/legacy/rspack/index.js +30 -14
- package/dist/legacy/rspack/index.js.map +1 -1
- package/dist/legacy/webpack4/index.cjs +30 -14
- package/dist/legacy/webpack4/index.cjs.map +1 -1
- package/dist/legacy/webpack4/index.js +30 -14
- package/dist/legacy/webpack4/index.js.map +1 -1
- package/dist/rollup.cjs +29 -13
- package/dist/rollup.cjs.map +1 -1
- package/dist/rollup.js +29 -13
- package/dist/rollup.js.map +1 -1
- package/dist/rspack.cjs +29 -13
- package/dist/rspack.cjs.map +1 -1
- package/dist/rspack.js +29 -13
- package/dist/rspack.js.map +1 -1
- package/dist/vite.cjs +29 -13
- package/dist/vite.cjs.map +1 -1
- package/dist/vite.js +29 -13
- package/dist/vite.js.map +1 -1
- package/dist/webpack.cjs +29 -13
- package/dist/webpack.cjs.map +1 -1
- package/dist/webpack.js +29 -13
- package/dist/webpack.js.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/legacy/webpack4/index.ts","../../../../../node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.8_typescript@5.9.3_yaml@2.8.3/node_modules/tsup/assets/cjs_shims.js","../../../src/injectors/webpack.ts","../../../src/injectors/utils.ts","../../../src/server/index.ts","../../../src/server/snippet.ts","../../../src/config.ts","../../../src/utils/logger.ts"],"sourcesContent":["import { getWebpackHtmlScript } from '../../injectors/webpack'\nimport { resolveClientModule } from '../../injectors/utils'\nimport { startServer } from '../../server'\nimport path from 'node:path'\n\nexport class InspectoWebpack4Plugin {\n private options: any\n\n constructor(options: any = {}) {\n this.options = options\n }\n\n apply(compiler: any) {\n const clientPath = resolveClientModule()\n\n // 1. Inject the loader dynamically so we don't have to require users to configure loaders manually\n compiler.hooks.afterEnvironment.tap('InspectoWebpack4Plugin', () => {\n const inspectoLoader = path.resolve(__dirname, 'loader.cjs')\n compiler.options.module.rules.push({\n test: /\\.[jt]sx?$/,\n enforce: 'pre',\n exclude: /node_modules/,\n use: [\n {\n loader: inspectoLoader,\n options: {\n ...this.options,\n clientPath,\n },\n },\n ],\n })\n })\n\n // 2. Inject initialization script into HTML\n compiler.hooks.compilation.tap('InspectoWebpack4Plugin', (compilation: any) => {\n // Find HtmlWebpackPlugin from compiler plugins to ensure we get the same instance\n const htmlPlugin = compiler.options.plugins.find(\n (p: any) => p && p.constructor && p.constructor.name === 'HtmlWebpackPlugin',\n )\n\n const HtmlWebpackPlugin = htmlPlugin ? htmlPlugin.constructor : null\n\n if (HtmlWebpackPlugin && HtmlWebpackPlugin.getHooks) {\n HtmlWebpackPlugin.getHooks(compilation).alterAssetTagGroups.tapAsync(\n 'InspectoWebpack4Plugin',\n async (data: any, cb: any) => {\n const port = await startServer()\n data.headTags.unshift({\n tagName: 'script',\n voidTag: false,\n attributes: { 'data-plugin': 'inspecto-overlay' },\n innerHTML: getWebpackHtmlScript(port),\n })\n cb(null, data)\n },\n )\n } else if (compilation.hooks.htmlWebpackPluginAlterAssetTags) {\n // Fallback for html-webpack-plugin v3\n compilation.hooks.htmlWebpackPluginAlterAssetTags.tapAsync(\n 'InspectoWebpack4Plugin',\n async (data: any, cb: any) => {\n const port = await startServer()\n data.head.unshift({\n tagName: 'script',\n voidTag: false,\n attributes: { 'data-plugin': 'inspecto-overlay' },\n innerHTML: getWebpackHtmlScript(port),\n })\n cb(null, data)\n },\n )\n }\n })\n }\n}\n\nexport const webpack4Plugin = (options?: any) => new InspectoWebpack4Plugin(options)\n","// Shim globals in cjs bundle\n// There's a weird bug that esbuild will always inject importMetaUrl\n// if we export it as `const importMetaUrl = ... __filename ...`\n// But using a function will not cause this issue\n\nconst getImportMetaUrl = () => \n typeof document === \"undefined\" \n ? new URL(`file:${__filename}`).href \n : (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') \n ? document.currentScript.src \n : new URL(\"main.js\", document.baseURI).href;\n\nexport const importMetaUrl = /* @__PURE__ */ getImportMetaUrl()\n","export function getWebpackHtmlScript(serverPort: number) {\n return `\nwindow.__AI_INSPECTOR_PORT__ = ${serverPort};\nwindow.addEventListener('load', () => {\n if (window.InspectoClient) {\n window.InspectoClient.mountInspector({\n serverUrl: 'http://127.0.0.1:' + window.__AI_INSPECTOR_PORT__,\n });\n }\n});\n`\n}\n\nexport function getWebpackAssetScript(serverPort: number) {\n return `\nif (typeof window !== 'undefined') {\n window.__AI_INSPECTOR_PORT__ = ${serverPort};\n const _initInspecto = () => {\n if (window.InspectoClient) {\n window.InspectoClient.mountInspector({\n serverUrl: 'http://127.0.0.1:' + window.__AI_INSPECTOR_PORT__,\n });\n } else {\n setTimeout(_initInspecto, 100);\n }\n };\n if (document.readyState === 'complete') {\n _initInspecto();\n } else {\n window.addEventListener('load', _initInspecto);\n }\n}\n`\n}\n\nexport function injectWebpack(\n compiler: any,\n serverPortFn: () => Promise<number>,\n resolveClientModule: () => string,\n) {\n const inspectoClientPath = resolveClientModule()\n\n // Inject the client logic directly using the absolute path\n if (compiler.webpack && compiler.webpack.EntryPlugin) {\n // Webpack 5+\n new compiler.webpack.EntryPlugin(compiler.context, inspectoClientPath, {\n name: undefined,\n }).apply(compiler)\n }\n\n compiler.hooks.compilation.tap('inspecto-overlay', (compilation: any) => {\n // Find HtmlWebpackPlugin (standard Webpack)\n const HtmlWebpackPlugin = compiler.options.plugins.find(\n (p: any) => p && p.constructor && p.constructor.name === 'HtmlWebpackPlugin',\n )\n if (HtmlWebpackPlugin) {\n const hooks = (HtmlWebpackPlugin.constructor as any).getHooks(compilation)\n hooks.alterAssetTagGroups.tapPromise('inspecto-overlay', async (data: any) => {\n const port = await serverPortFn()\n data.headTags.unshift({\n tagName: 'script',\n voidTag: false,\n meta: { plugin: 'inspecto-overlay' },\n innerHTML: getWebpackHtmlScript(port),\n })\n return data\n })\n } else {\n // Fallback for frameworks like Next.js that don't use HtmlWebpackPlugin\n compilation.hooks.processAssets.tapPromise(\n {\n name: 'inspecto-overlay',\n stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONS,\n },\n async (assets: any) => {\n const port = await serverPortFn()\n\n // Only inject into the main client entry chunks (e.g. main-app or main.js)\n const mainAssetKey = Object.keys(assets).find(\n key => key.endsWith('.js') && (key.includes('main') || key.includes('app')),\n )\n if (!mainAssetKey) return\n\n const originalSource = assets[mainAssetKey].source()\n assets[mainAssetKey] = new compiler.webpack.sources.RawSource(\n getWebpackAssetScript(port) + '\\n' + originalSource,\n )\n },\n )\n }\n })\n}\n","import { createRequire } from 'node:module'\n\n// Safely resolve the client module without breaking ESM/CJS or bundling\nexport const resolveClientModule = () => {\n try {\n return createRequire(import.meta.url).resolve('@inspecto-dev/core')\n } catch {\n try {\n return require.resolve('@inspecto-dev/core')\n } catch {\n console.warn(\n '[inspecto] Could not resolve @inspecto-dev/core — falling back to bare specifier',\n )\n return '@inspecto-dev/core'\n }\n }\n}\n","import http from 'node:http'\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport os from 'node:os'\nimport crypto from 'node:crypto'\nimport { execSync, execFileSync } from 'node:child_process'\nimport portfinder from 'portfinder'\nimport { Editor, launchIDE } from 'launch-ide'\nimport type {\n ServerState,\n OpenFileRequest,\n SendToAiRequest,\n SendToAiResponse,\n IdeType,\n Provider,\n} from '@inspecto-dev/types'\nimport { INSPECTO_API_PATHS } from '@inspecto-dev/types'\nimport { extractSnippet } from './snippet.js'\nimport {\n loadUserConfigSync,\n loadPromptsConfig,\n resolveProviderMode,\n extractToolOverrides,\n watchConfig,\n unwatchConfig,\n resolveTargetTool,\n getGlobalLogLevel,\n resolveIntents,\n} from '../config.js'\nimport { createLogger } from '../utils/logger.js'\n\nconst serverLogger = createLogger('inspecto:server', { logLevel: getGlobalLogLevel() })\n\n// In-memory store for large payloads to bypass OS URI length limits.\n// Keys are ticket UUIDs, values are JSON stringified AiPayload objects.\nconst payloadTickets = new Map<string, string>()\n\n// Clean up old tickets to prevent memory leaks (e.g., if IDE never fetches them)\nfunction createTicket(payload: any): string {\n const ticketId = crypto.randomUUID()\n payloadTickets.set(ticketId, JSON.stringify(payload))\n\n // Auto-expire tickets after 5 minutes\n setTimeout(\n () => {\n payloadTickets.delete(ticketId)\n },\n 5 * 60 * 1000,\n )\n\n return ticketId\n}\n\nexport const serverState: ServerState = {\n port: null,\n running: false,\n projectRoot: '',\n configRoot: '',\n cwd: process.cwd(),\n}\n\nlet serverInstance: http.Server | null = null\n\n// Remove unused detectTraeScheme function\n\nfunction resolveProjectRoot(): string {\n let gitRoot: string\n try {\n serverLogger.info('Resolving project root...')\n gitRoot = execSync('git rev-parse --show-toplevel', { encoding: 'utf-8' }).trim()\n serverLogger.info('Resolved project root: ' + gitRoot)\n } catch (e) {\n serverLogger.error('Failed to resolve project root:', e)\n gitRoot = process.cwd()\n }\n\n // Walk upward from gitRoot looking for the nearest ancestor that contains .inspecto/.\n // This handles nested-git-repo playgrounds (e.g. playground/nextjs has its own .git\n // but the real config lives in the monorepo root two levels up).\n let current = gitRoot\n while (true) {\n if (fs.existsSync(path.join(current, '.inspecto'))) return current\n const parent = path.dirname(current)\n if (parent === current) break\n current = parent\n }\n\n // No .inspecto/ found anywhere — fall back to the git root (or cwd)\n return gitRoot\n}\n\n// Function to safely launch a URI to avoid launch-ide swallow bugs on macOS\nfunction launchURI(uri: string): void {\n try {\n if (process.platform === 'darwin') {\n execFileSync('open', [uri])\n } else if (process.platform === 'win32') {\n execFileSync('cmd', ['/c', 'start', '\"\"', uri])\n } else {\n execFileSync('xdg-open', [uri])\n }\n } catch (e) {\n serverLogger.error('Failed to launch URI via execFileSync, falling back to launchIDE:', e)\n launchIDE({ file: uri })\n }\n}\n\nexport async function startServer(): Promise<number> {\n if (serverState.running && serverState.port !== null) {\n return serverState.port\n }\n\n // Resolve project root at server start time so process.cwd() reflects the\n // actual project directory, not the module load-time cwd.\n serverState.projectRoot = resolveProjectRoot()\n serverState.configRoot = serverState.projectRoot\n serverState.cwd = process.cwd()\n\n portfinder.basePort = 5678\n const port = await portfinder.getPortPromise()\n\n // Watch for user config changes to trigger hot-reloads internally if needed\n watchConfig(\n () => {\n serverLogger.info('user config reloaded.')\n },\n serverState.cwd,\n serverState.configRoot,\n )\n\n serverInstance = http.createServer((req, res) => {\n res.setHeader('Access-Control-Allow-Origin', '*')\n res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type')\n\n if (req.method === 'OPTIONS') {\n res.writeHead(204)\n res.end()\n return\n }\n\n const url = new URL(req.url ?? '/', `http://localhost:${port}`)\n handleRequest(url, req, res).catch(err => {\n serverLogger.error('server error:', err)\n res.writeHead(500, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify({ success: false, error: String(err) }))\n })\n })\n\n await new Promise<void>((resolve, reject) => {\n serverInstance!.listen(port, '127.0.0.1', () => {\n serverInstance!.unref() // Allow process to exit\n resolve()\n })\n serverInstance!.once('error', reject)\n })\n\n // Add persistent error handler after successful startup\n serverInstance!.on('error', err => {\n serverLogger.error('persistent server error:', err)\n })\n\n serverState.port = port\n serverState.running = true\n\n // Write port file so the IDE extension can discover the server without scanning ports\n const portFile = path.join(os.tmpdir(), 'inspecto.port.json')\n try {\n let portData: Record<string, number> = {}\n if (fs.existsSync(portFile)) {\n try {\n portData = JSON.parse(fs.readFileSync(portFile, 'utf-8'))\n } catch (e) {\n // Invalid JSON, start fresh\n }\n }\n // Hash the project root to avoid invalid keys or paths in JSON\n const rootHash = crypto.createHash('md5').update(serverState.projectRoot).digest('hex')\n portData[rootHash] = port\n fs.writeFileSync(portFile, JSON.stringify(portData, null, 2), 'utf-8')\n } catch (e) {\n serverLogger.warn('Failed to write port file:', e)\n /* non-fatal — extension will fall back to scanning */\n }\n // Clean up on process exit (Vite terminates the process, not stopServer)\n process.once('exit', () => {\n try {\n if (fs.existsSync(portFile)) {\n const portData = JSON.parse(fs.readFileSync(portFile, 'utf-8'))\n const rootHash = crypto.createHash('md5').update(serverState.projectRoot).digest('hex')\n delete portData[rootHash]\n if (Object.keys(portData).length === 0) {\n fs.unlinkSync(portFile)\n } else {\n fs.writeFileSync(portFile, JSON.stringify(portData, null, 2), 'utf-8')\n }\n }\n } catch {\n /* ignore */\n }\n })\n\n serverLogger.info(`server running at http://127.0.0.1:${port}`)\n\n return port\n}\n\nexport function stopServer(): void {\n if (serverInstance) {\n serverInstance.close()\n serverInstance = null\n }\n unwatchConfig()\n serverState.running = false\n serverState.port = null\n try {\n fs.unlinkSync(path.join(os.tmpdir(), 'inspecto.port'))\n } catch {\n /* ignore */\n }\n}\n\nasync function readBody(req: http.IncomingMessage): Promise<string> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = []\n req.on('data', (chunk: Buffer) => chunks.push(chunk))\n req.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')))\n req.on('error', reject)\n })\n}\n\nasync function handleRequest(\n url: URL,\n req: http.IncomingMessage,\n res: http.ServerResponse,\n): Promise<void> {\n const pathname = url.pathname\n\n // Health check - root or /inspecto/api/v1/health\n if ((pathname === '/health' || pathname === INSPECTO_API_PATHS.HEALTH) && req.method === 'GET') {\n res.writeHead(200, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify({ ok: true, port: serverState.port }))\n return\n }\n\n // Browser Client requests\n if (pathname === INSPECTO_API_PATHS.CLIENT_CONFIG && req.method === 'GET') {\n const userConfig = loadUserConfigSync(false, serverState.cwd, serverState.configRoot)\n const promptsConfig = await loadPromptsConfig(false, serverState.cwd, serverState.configRoot)\n const effectiveIde = (userConfig.ide ?? 'vscode') as IdeType\n\n let info: any\n if (!serverState.ideInfo) {\n info = {\n ide: effectiveIde,\n }\n } else {\n const { scheme: _scheme, ...rest } = serverState.ideInfo as any\n info = rest\n }\n\n const config = {\n ...info,\n prompts: resolveIntents(promptsConfig),\n hotKeys: userConfig['inspector.hotKey'] ?? 'alt',\n theme: userConfig['inspector.theme'] ?? 'auto',\n includeSnippet: userConfig['prompt.includeSnippet'] ?? false,\n autoSend: userConfig['prompt.autoSend'] ?? false,\n }\n\n // Omit providers from the response sent to the client\n delete config.providers\n\n res.writeHead(200, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify(config))\n return\n }\n\n if (pathname === INSPECTO_API_PATHS.IDE_INFO && req.method === 'POST') {\n try {\n const body = JSON.parse(await readBody(req))\n\n // Workspace matching defense mechanism against multiple IDE connections\n const ideWorkspace = body.workspaceRoot || ''\n const serverProjectRoot = serverState.projectRoot || ''\n\n // Only accept IDE info if it's from the same project to prevent hijacking\n // Or if either is empty (fallback for older extensions or undetermined roots)\n const isSameProject =\n !ideWorkspace ||\n !serverProjectRoot ||\n ideWorkspace === serverProjectRoot ||\n serverProjectRoot.startsWith(ideWorkspace)\n\n if (isSameProject) {\n serverState.ideInfo = body\n serverLogger.debug(\n `Accepted IDE info from matched workspace (ide-${body.ide} / schema-${body.scheme})`,\n )\n } else {\n serverLogger.debug(\n `Ignored IDE info from unrelated workspace (IDE Workspace: ${ideWorkspace}, Server: ${serverProjectRoot}, Scheme: ${body.scheme}, IDE: ${body.ide})`,\n )\n }\n\n res.writeHead(200, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify({ success: true }))\n } catch (e) {\n serverLogger.error(`Error parsing ${INSPECTO_API_PATHS.IDE_INFO} POST request:`, e)\n res.writeHead(400, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify({ error: 'Invalid JSON body' }))\n }\n return\n }\n\n if (pathname === INSPECTO_API_PATHS.IDE_OPEN && req.method === 'POST') {\n let body: OpenFileRequest\n try {\n body = JSON.parse(await readBody(req)) as OpenFileRequest\n } catch (e) {\n res.writeHead(400, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify({ error: 'Invalid JSON body' }))\n return\n }\n\n const absolutePath = path.isAbsolute(body.file)\n ? path.resolve(body.file)\n : path.resolve(serverState.cwd, body.file)\n\n // Security: Prevent path traversal attacks\n const relativeToRoot = path.relative(serverState.projectRoot, absolutePath)\n if (relativeToRoot.startsWith('..') || path.isAbsolute(relativeToRoot)) {\n serverLogger.warn(`Security: Blocked path traversal attempt in IDE_OPEN: ${body.file}`)\n res.writeHead(403, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify({ error: 'Access denied: File is outside of project workspace' }))\n return\n }\n\n const userConfig = loadUserConfigSync(false, serverState.cwd, serverState.configRoot)\n\n // Strict Config Override: Respect user config if explicitly set and differs from active IDE\n const configuredIde = userConfig.ide\n const activeIde = serverState.ideInfo?.ide\n const activeIdeScheme = serverState.ideInfo?.scheme\n\n // Priority: 1. User config 2. Active IDE detection 3. Fallback\n const rawEditorHint = configuredIde || activeIde || activeIdeScheme || 'code'\n\n if (configuredIde && activeIdeScheme && !activeIdeScheme.includes(configuredIde)) {\n serverLogger.warn(\n `Active IDE is ${activeIdeScheme}, but config forces ${configuredIde}. Using configured IDE.`,\n )\n }\n\n let editorHint = rawEditorHint\n if (rawEditorHint === 'vscode') editorHint = 'code'\n else if (rawEditorHint === 'vscode-insiders') editorHint = 'code-insiders'\n else if (rawEditorHint === 'vscodium') editorHint = 'codium'\n // Map trae-cn back to trae for launchIDE to recognize it correctly,\n // since launchIDE only maps 'trae' in its keys.\n else if (rawEditorHint === 'trae-cn' || rawEditorHint === 'trae') editorHint = 'trae'\n\n serverLogger.debug(\n `IDE_OPEN: activeIde=${activeIde}, activeIdeScheme=${activeIdeScheme}, configuredIde=${configuredIde} -> rawEditorHint=${rawEditorHint}, finalEditorHint=${editorHint}`,\n )\n\n // Bypass launchIDE for VSCode family IDEs that support URL schemes.\n // launch-ide has a hardcoded dictionary that maps 'trae-cn' to 'trae://', which fails on macOS.\n // Using the URL scheme directly is more reliable and supports opening files even if the IDE isn't running yet.\n const VSCODE_FAMILY_SCHEMES = [\n 'vscode',\n 'vscode-insiders',\n 'cursor',\n 'windsurf',\n 'trae',\n 'trae-cn',\n 'vscodium',\n 'codebuddy',\n 'codebuddy-cn',\n 'antigravity',\n ]\n\n if (VSCODE_FAMILY_SCHEMES.includes(rawEditorHint)) {\n const uri = `${rawEditorHint}://file${absolutePath}:${body.line}:${body.column}`\n serverLogger.debug(`IDE_OPEN: Bypassing launchIDE, using URI scheme directly: ${uri}`)\n\n try {\n if (process.platform === 'darwin') {\n execFileSync('open', [uri])\n } else if (process.platform === 'win32') {\n execFileSync('cmd', ['/c', 'start', '\"\"', uri])\n } else {\n execFileSync('xdg-open', [uri])\n }\n } catch (e) {\n serverLogger.error(`Failed to launch URI for IDE_OPEN (${uri}):`, e)\n // Fallback to launchIDE if scheme launch fails\n launchIDE({\n file: absolutePath,\n line: body.line,\n column: body.column,\n editor: editorHint as Editor,\n type: process.platform === 'darwin' ? 'open' : 'exec',\n })\n }\n } else {\n launchIDE({\n file: absolutePath,\n line: body.line,\n column: body.column,\n editor: editorHint as Editor,\n type: process.platform === 'darwin' ? 'open' : 'exec',\n })\n }\n\n res.writeHead(200, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify({ success: true }))\n return\n }\n\n if (pathname === INSPECTO_API_PATHS.PROJECT_SNIPPET && req.method === 'GET') {\n const file = url.searchParams.get('file') ?? ''\n const line = parseInt(url.searchParams.get('line') ?? '1', 10)\n const column = parseInt(url.searchParams.get('column') ?? '1', 10)\n const maxLines = parseInt(url.searchParams.get('maxLines') ?? '100', 10)\n\n try {\n const absolutePath = path.isAbsolute(file)\n ? path.resolve(file)\n : path.resolve(serverState.cwd, file)\n\n // Security: Prevent path traversal attacks\n const relativeToRoot = path.relative(serverState.projectRoot, absolutePath)\n if (relativeToRoot.startsWith('..') || path.isAbsolute(relativeToRoot)) {\n serverLogger.warn(`Security: Blocked path traversal attempt in PROJECT_SNIPPET: ${file}`)\n res.writeHead(403, { 'Content-Type': 'application/json' })\n res.end(\n JSON.stringify({\n success: false,\n error: 'Access denied: File is outside of project workspace',\n errorCode: 'FORBIDDEN',\n }),\n )\n return\n }\n\n const result = await extractSnippet({ file: absolutePath, line, column, maxLines })\n res.writeHead(200, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify(result))\n } catch (err: any) {\n const message = String(err.message || err)\n const errorCode = message.startsWith('FILE_NOT_FOUND') ? 'FILE_NOT_FOUND' : 'UNKNOWN'\n res.writeHead(404, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify({ success: false, error: message, errorCode }))\n }\n return\n }\n\n if (pathname === INSPECTO_API_PATHS.AI_DISPATCH && req.method === 'POST') {\n try {\n const rawBody = await readBody(req)\n const body = JSON.parse(rawBody) as SendToAiRequest\n const result = await dispatchToAi(body)\n res.writeHead(result.success ? 200 : 500, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify(result))\n } catch (e) {\n serverLogger.error(`Error parsing ${INSPECTO_API_PATHS.AI_DISPATCH} request:`, e)\n res.writeHead(500, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify({ success: false, error: String(e), errorCode: 'INTERNAL_ERROR' }))\n }\n return\n }\n\n // Handle IDE payload ticket retrieval\n if (pathname.startsWith(`${INSPECTO_API_PATHS.AI_TICKET}/`) && req.method === 'GET') {\n const ticketId = pathname.substring(INSPECTO_API_PATHS.AI_TICKET.length + 1)\n const payloadStr = payloadTickets.get(ticketId)\n\n if (!payloadStr) {\n res.writeHead(404, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify({ success: false, error: 'Ticket not found or expired' }))\n return\n }\n\n res.writeHead(200, { 'Content-Type': 'application/json' })\n res.end(payloadStr)\n return\n }\n\n res.writeHead(404, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify({ error: 'not found' }))\n}\n\nasync function dispatchToAi(\n req: SendToAiRequest,\n): Promise<SendToAiResponse & { fallbackPayload?: { prompt: string; file: string } }> {\n const { location, snippet, prompt } = req\n\n const userConfig = loadUserConfigSync(false, serverState.cwd, serverState.configRoot)\n const resolvedTarget = resolveTargetTool(userConfig)\n\n const formattedPrompt =\n prompt ??\n `Please help me with this code from \\`${location.file}\\` (line ${location.line}):\\n\\n\\`\\`\\`\\n${snippet}\\n\\`\\`\\`\\n`\n\n const ideReportedMode = serverState.ideInfo?.providers[resolvedTarget]?.mode\n\n // Generate the full payload\n const configuredIde = userConfig.ide\n const activeIde = serverState.ideInfo?.ide\n const activeIdeScheme = serverState.ideInfo?.scheme\n\n // Priority: 1. User config 2. Active IDE Scheme (for URI construction) 3. Active IDE fallback\n const finalIde: string = configuredIde || activeIdeScheme || activeIde || 'vscode'\n\n if (configuredIde && activeIdeScheme && !activeIdeScheme.includes(configuredIde)) {\n serverLogger.warn(\n `dispatchToAi: Active IDE is ${activeIdeScheme}, but config forces ${configuredIde}. Using configured IDE.`,\n )\n }\n\n const mode = resolveProviderMode(resolvedTarget, finalIde as IdeType, userConfig)\n const overrides = extractToolOverrides(finalIde as IdeType, userConfig)[resolvedTarget] || {}\n overrides.type = mode\n\n const fullPayload = {\n ide: finalIde,\n target: resolvedTarget,\n targetType: mode,\n prompt: formattedPrompt,\n filePath: location.file,\n line: location.line,\n column: location.column,\n snippet,\n overrides: Object.keys(overrides).length > 0 ? overrides : undefined,\n autoSend:\n userConfig['prompt.autoSend'] !== undefined\n ? Boolean(userConfig['prompt.autoSend'])\n : undefined,\n }\n\n // Create a ticket and store the full payload in memory\n const ticketId = createTicket(fullPayload)\n\n // Only pass the ticket and critical routing info via URI\n const params = new URLSearchParams()\n params.set('ticket', ticketId)\n params.set('target', resolvedTarget)\n\n // Use the exact scheme reported by the extension if available, fallback to user config or 'vscode'\n const uri = `${finalIde}://inspecto.inspecto/send?${params.toString()}`\n\n serverLogger.debug(`dispatchToAi: Generated URI: ${uri}`)\n\n launchURI(uri)\n\n // Return success along with the payload so the browser can fallback to clipboard\n return {\n success: true,\n fallbackPayload: {\n prompt: formattedPrompt,\n file: location.file,\n },\n }\n}\n","import * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport * as parser from '@babel/parser'\nimport traverse_ from '@babel/traverse'\n// Support both ESM default and CommonJS module.exports\nconst traverse =\n typeof traverse_ === 'function' ? traverse_ : (traverse_ as any).default || traverse_\nimport type { NodePath } from '@babel/traverse'\nimport type { Node } from '@babel/types'\nimport type { SnippetRequest, SnippetResponse } from '@inspecto-dev/types'\n\ninterface CacheEntry {\n mtime: number\n /** The full parsed source lines */\n lines: string[]\n}\n\n/** In-memory cache keyed by absolute file path */\nconst snippetCache = new Map<string, CacheEntry>()\n\nconst DEFAULT_MAX_LINES = 100\nconst DEFAULT_CONTEXT_LINES_BEFORE = 5\n\nexport async function extractSnippet(req: SnippetRequest): Promise<SnippetResponse> {\n const { file, line, column, maxLines = DEFAULT_MAX_LINES } = req\n\n const absolutePath = path.resolve(file)\n\n let stat: fs.Stats\n try {\n stat = await fs.promises.stat(absolutePath)\n } catch {\n throw new Error(`FILE_NOT_FOUND: ${absolutePath}`)\n }\n\n const mtime = stat.mtimeMs\n\n let lines: string[]\n const cached = snippetCache.get(absolutePath)\n if (cached && cached.mtime === mtime) {\n lines = cached.lines\n } else {\n const source = await fs.promises.readFile(absolutePath, 'utf-8')\n lines = source.split('\\n')\n snippetCache.set(absolutePath, { mtime, lines })\n }\n\n let snippetLines: string[]\n let startLine: number\n let componentName: string | undefined\n\n try {\n const result = extractComponentBoundary(lines.join('\\n'), line, column, maxLines)\n snippetLines = result.lines\n startLine = result.startLine\n componentName = result.name\n } catch {\n const before = Math.max(0, line - 1 - DEFAULT_CONTEXT_LINES_BEFORE)\n const after = Math.min(lines.length, before + maxLines)\n snippetLines = lines.slice(before, after)\n startLine = before + 1\n }\n\n if (snippetLines.length > maxLines) {\n snippetLines = snippetLines.slice(0, maxLines)\n }\n\n return {\n snippet: snippetLines.join('\\n'),\n startLine,\n file: absolutePath,\n ...(componentName ? { name: componentName } : {}),\n }\n}\n\ninterface BoundaryResult {\n lines: string[]\n startLine: number\n name?: string\n}\n\nfunction extractComponentBoundary(\n source: string,\n targetLine: number,\n _targetColumn: number,\n maxLines: number,\n): BoundaryResult {\n const ast = parser.parse(source, {\n sourceType: 'module',\n plugins: ['jsx', 'typescript', 'decorators-legacy', 'classProperties'],\n errorRecovery: true,\n })\n\n const allLines = source.split('\\n')\n\n let bestStart = 0\n let bestEnd = allLines.length - 1\n let bestName: string | undefined\n\n traverse(ast, {\n 'FunctionDeclaration|FunctionExpression|ArrowFunctionExpression|ClassMethod'(\n nodePath: NodePath<Node>,\n ) {\n const node = nodePath.node\n if (!node.loc) return\n\n const nodeStart = node.loc.start.line\n const nodeEnd = node.loc.end.line\n\n if (targetLine < nodeStart || targetLine > nodeEnd) return\n\n if (nodeEnd - nodeStart < bestEnd - bestStart) {\n bestStart = nodeStart - 1\n bestEnd = nodeEnd - 1\n bestName = extractFunctionName(nodePath)\n }\n },\n })\n\n let sliceStart = bestStart\n let sliceEnd = bestEnd + 1\n\n if (sliceEnd - sliceStart > maxLines) {\n const targetIdx = targetLine - 1\n sliceStart = Math.max(bestStart, targetIdx - Math.floor(maxLines / 3))\n sliceEnd = sliceStart + maxLines\n if (sliceEnd > bestEnd + 1) {\n sliceEnd = bestEnd + 1\n sliceStart = Math.max(0, sliceEnd - maxLines)\n }\n }\n\n return {\n lines: allLines.slice(sliceStart, sliceEnd),\n startLine: sliceStart + 1,\n ...(bestName ? { name: bestName } : {}),\n }\n}\n\nfunction extractFunctionName(nodePath: NodePath<Node>): string | undefined {\n const node = nodePath.node\n\n if (node.type === 'FunctionDeclaration' && node.id) {\n return node.id.name\n }\n\n const parent = nodePath.parent\n if (\n (node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression') &&\n parent.type === 'VariableDeclarator' &&\n parent.id.type === 'Identifier'\n ) {\n return parent.id.name\n }\n\n if (node.type === 'ClassMethod' && node.key.type === 'Identifier') {\n return node.key.name\n }\n\n return undefined\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport os from 'node:os'\nimport { createDefu } from 'defu'\nimport type {\n InspectoSettings,\n InspectoPromptsConfig,\n Provider,\n ProviderMode,\n ToolOverrides,\n IdeType,\n LogLevel,\n} from '@inspecto-dev/types'\nimport {\n DEFAULT_PROVIDER_MODE,\n VALID_MODES,\n DEFAULT_INTENTS,\n IntentConfig,\n} from '@inspecto-dev/types'\nimport { createLogger, setLoggerGlobalLevel } from './utils/logger.js'\n\nconst configLogger = createLogger('inspecto:config')\n\nlet loadedConfig: InspectoSettings | null = null\nlet loadedPrompts: InspectoPromptsConfig | null = null\nlet globalLogLevel: LogLevel = 'warn'\nlet isWatching = false\n\n// Custom array merge behavior for defu: overwrite arrays instead of concatenating them\nconst arrayReplaceMerge = createDefu((obj, key, val) => {\n if (Array.isArray(val)) {\n obj[key] = val\n return true\n }\n})\n\nexport function setGlobalLogLevel(level?: LogLevel) {\n if (level) {\n globalLogLevel = level\n setLoggerGlobalLevel(level)\n }\n}\n\nexport function getGlobalLogLevel() {\n return globalLogLevel\n}\n\n/**\n * Walk from cwd up to gitRoot (inclusive), collecting directories that contain\n * a .inspecto/ subdirectory. Returns them ordered highest-priority first\n * (closest to cwd first).\n *\n * If cwd is not under gitRoot, only cwd itself is checked.\n */\nexport function resolveConfigRoots(cwd: string, gitRoot: string): string[] {\n const roots: string[] = []\n let current = cwd\n\n // Ensure we don't walk past gitRoot (handles cwd above gitRoot case)\n const isUnderOrEqual = current === gitRoot || current.startsWith(gitRoot + path.sep)\n if (!isUnderOrEqual) {\n // cwd is not under gitRoot — only check cwd\n if (fs.existsSync(path.join(cwd, '.inspecto'))) roots.push(cwd)\n return roots\n }\n\n while (true) {\n if (fs.existsSync(path.join(current, '.inspecto'))) {\n roots.push(current)\n }\n if (current === gitRoot) break\n const parent = path.dirname(current)\n if (parent === current) break // filesystem root guard\n current = parent\n }\n\n return roots\n}\n\n/**\n * Load and merge user config from all discovered .inspecto/ layers:\n *\n * Priority (highest → lowest):\n * <cwd>/.inspecto/settings.local.json\n * <cwd>/.inspecto/settings.json\n * ...intermediate dirs...\n * <gitRoot>/.inspecto/settings.local.json\n * <gitRoot>/.inspecto/settings.json\n * ~/.inspecto/settings.json\n *\n * @param force Bust cache and re-read from disk\n * @param cwd Working directory to start resolution from (default: process.cwd())\n * @param gitRoot Git repository root — upward traversal stops here (optional)\n */\nexport function loadUserConfigSync(\n force = false,\n cwd = process.cwd(),\n gitRoot?: string,\n): InspectoSettings {\n if (loadedConfig && !force) return loadedConfig\n loadedConfig = null // force clear\n\n const layers: Partial<InspectoSettings>[] = []\n const roots = resolveConfigRoots(cwd, gitRoot ?? cwd)\n\n for (const root of roots) {\n layers.push(readJsonSafely(path.join(root, '.inspecto', 'settings.local.json')))\n layers.push(readJsonSafely(path.join(root, '.inspecto', 'settings.json')))\n }\n\n layers.push(readJsonSafely(path.join(os.homedir(), '.inspecto', 'settings.json')))\n layers.push({})\n\n const validLayers = layers.filter(l => l !== null)\n loadedConfig = arrayReplaceMerge(...(validLayers as [object, ...object[]])) as InspectoSettings\n return loadedConfig\n}\n\n/**\n * Load and merge prompts config from all discovered .inspecto/ layers:\n *\n * Priority (highest → lowest):\n * <cwd>/.inspecto/prompts.local.json\n * <cwd>/.inspecto/prompts.json\n * ...intermediate dirs...\n * <gitRoot>/.inspecto/prompts.local.json\n * <gitRoot>/.inspecto/prompts.json\n * ~/.inspecto/prompts.json\n *\n * Arrays in custom configurations are replaced instead of merged.\n */\nexport async function loadPromptsConfig(\n force = false,\n cwd = process.cwd(),\n gitRoot?: string,\n): Promise<InspectoPromptsConfig> {\n if (loadedPrompts && !force) return loadedPrompts\n\n const layers: any[] = []\n\n const roots = resolveConfigRoots(cwd, gitRoot ?? cwd)\n for (const root of roots) {\n const localPath = path.join(root, '.inspecto', 'prompts.local.json')\n const jsonPath = path.join(root, '.inspecto', 'prompts.json')\n layers.push(readJsonSafely(localPath))\n layers.push(readJsonSafely(jsonPath))\n }\n\n layers.push(readJsonSafely(path.join(os.homedir(), '.inspecto', 'prompts.json')))\n\n // Find the first layer that contains a valid prompts config (array or $replace object).\n // Highest-priority layer wins — no merging across layers for prompts.\n let finalPrompts: any = []\n for (const layer of layers) {\n if (Array.isArray(layer) && layer.length > 0) {\n finalPrompts = layer\n break\n }\n if (\n layer &&\n typeof layer === 'object' &&\n layer.$replace === true &&\n Array.isArray(layer.items)\n ) {\n finalPrompts = layer\n break\n }\n }\n\n loadedPrompts = finalPrompts as InspectoPromptsConfig\n return loadedPrompts\n}\n\nfunction readJsonSafely(filePath: string): any {\n try {\n if (fs.existsSync(filePath)) {\n const content = fs.readFileSync(filePath, 'utf-8').trim()\n if (!content) return null // Return null instead of [] so we know it's empty\n const parsed = JSON.parse(content)\n // Transition helper: if user still has {\"prompts\": [...]}, extract it\n if (!Array.isArray(parsed) && parsed.prompts && Array.isArray(parsed.prompts)) {\n return parsed.prompts\n }\n return parsed\n }\n } catch (e) {\n // Ignore JSON parsing errors for empty or malformed files during watch\n if (e instanceof SyntaxError) {\n configLogger.warn(`Failed to parse config at ${filePath}: Invalid JSON`)\n } else {\n configLogger.warn(`Failed to read config at ${filePath}:`, e)\n }\n }\n return null\n}\n\n/**\n * Resolve the exact target tool to dispatch to based on user config.\n */\nexport function resolveTargetTool(config: InspectoSettings, ide: IdeType = 'vscode'): Provider {\n // Support \"provider.default\" (e.g., \"claude-code.extension\")\n const defaultProvider = config['provider.default'] as string | undefined\n if (defaultProvider) {\n const tool = defaultProvider.split('.')[0]\n return tool as Provider\n }\n\n // Fallback\n return 'copilot'\n}\n\n/**\n * Resolve the effective mode/type for a tool in the context of an IDE.\n */\nexport function resolveProviderMode(\n tool: Provider,\n ide: IdeType,\n config: InspectoSettings,\n): ProviderMode {\n let requestedType: ProviderMode | undefined = undefined\n\n // V2 format: check provider.default for \"tool.mode\"\n const defaultProvider = config['provider.default'] as string | undefined\n if (defaultProvider && defaultProvider.startsWith(`${tool}.`)) {\n const mode = defaultProvider.split('.')[1]\n if (mode === 'extension') requestedType = 'extension'\n if (mode === 'cli') requestedType = 'cli'\n }\n\n requestedType = requestedType ?? DEFAULT_PROVIDER_MODE[tool]\n const valid = VALID_MODES[tool] || [DEFAULT_PROVIDER_MODE[tool]]\n return requestedType && valid.includes(requestedType) ? requestedType : valid[0]!\n}\n\n/**\n * Extract ToolOverrides (binaryPath, args, etc) for Extension consumption.\n */\nexport function extractToolOverrides(\n ide: IdeType,\n config: InspectoSettings,\n): Partial<Record<Provider, ToolOverrides>> {\n const result: Partial<Record<Provider, ToolOverrides>> = {}\n\n if (!config) return result\n\n // Parse new flat `provider.*` format\n for (const [key, value] of Object.entries(config)) {\n if (!key.startsWith('provider.')) continue\n\n // We only process tool specific overrides, ignore `.default`\n if (key === 'provider.default') continue\n\n // Handle `provider.[tool].[mode]`\n const toolIndex = 1\n const modeIndex = 2\n const propIndex = 3\n\n const parts = key.split('.')\n\n if (parts.length >= propIndex + 1) {\n const tool = parts[toolIndex] as Provider\n const mode = parts[modeIndex] as ProviderMode\n const prop = parts[propIndex]\n\n if (!result[tool]) {\n result[tool] = { type: mode }\n }\n\n const overrides = result[tool]!\n\n // If we see config for a mode that differs from what we've initialized,\n // it means both modes have config. In v2, mode is determined by provider.default.\n // We will just accumulate the settings for now and let resolveProviderMode decide the active type.\n\n if (prop === 'bin') overrides.binaryPath = value as string\n if (prop === 'args') overrides.args = value as string[]\n if (prop === 'cwd') overrides.cwd = value as string\n if (prop === 'coldStartDelay') overrides.coldStartDelay = value as number\n }\n }\n\n return result\n}\n\nexport function resolveIntents(serverPrompts?: InspectoPromptsConfig): IntentConfig[] {\n // Start with DEFAULT_INTENTS as base\n const baseMap = new Map<string, IntentConfig>()\n for (const intent of DEFAULT_INTENTS) {\n if (intent.id) baseMap.set(intent.id, { ...intent })\n }\n\n const defaults = () => ensureOpenInEditorLast(Array.from(baseMap.values()))\n\n if (!serverPrompts) return defaults()\n\n const isReplace =\n !Array.isArray(serverPrompts) &&\n typeof serverPrompts === 'object' &&\n serverPrompts.$replace === true\n const promptsArray = Array.isArray(serverPrompts)\n ? serverPrompts\n : isReplace\n ? serverPrompts.items\n : []\n\n if (!promptsArray || promptsArray.length === 0) return defaults()\n\n if (isReplace) {\n // $replace: true — exact list, user controls everything\n const result: IntentConfig[] = []\n for (const item of promptsArray) {\n if (typeof item === 'string') {\n if (baseMap.has(item)) {\n result.push(baseMap.get(item)!)\n } else {\n configLogger.warn(\n `Unknown built-in intent id: \"${item}\". Available: ${[...baseMap.keys()].join(', ')}`,\n )\n }\n } else if (typeof item === 'object') {\n if (!item.id) {\n configLogger.warn('Intent object missing required \"id\" field, skipping.')\n continue\n }\n if (item.enabled === false) {\n configLogger.warn(\n `Intent \"${item.id}\" is listed in $replace but has enabled:false — it will be excluded.`,\n )\n continue\n }\n if (item.isAction && item.id !== 'open-in-editor') {\n configLogger.warn(\n `isAction is reserved for built-in actions. Ignoring intent \"${item.id}\".`,\n )\n continue\n }\n result.push(baseMap.has(item.id) ? { ...baseMap.get(item.id)!, ...item } : item)\n }\n }\n return ensureOpenInEditorLast(result)\n }\n\n // Default: append / override mode.\n // - Objects with known id: merge over built-in (or remove if enabled:false)\n // - Objects with unknown id: append as new intent\n // - Strings: not meaningful in append mode (order is fixed to built-in order + appended)\n const merged = Array.from(baseMap.values())\n\n for (const item of promptsArray) {\n if (typeof item === 'string') {\n if (!baseMap.has(item)) {\n configLogger.warn(\n `Unknown built-in intent id: \"${item}\". In append mode, strings have no effect on ordering — use $replace to control order.`,\n )\n }\n // Known string ids are already in merged — nothing to do\n continue\n }\n\n if (typeof item === 'object') {\n if (!item.id) {\n configLogger.warn('Intent object missing required \"id\" field, skipping.')\n continue\n }\n if (item.isAction && item.id !== 'open-in-editor') {\n configLogger.warn(\n `isAction is reserved for built-in actions. Ignoring intent \"${item.id}\".`,\n )\n continue\n }\n\n const existingIdx = merged.findIndex(i => i.id === item.id)\n if (existingIdx !== -1) {\n if (item.enabled === false) {\n merged.splice(existingIdx, 1)\n } else {\n merged[existingIdx] = { ...merged[existingIdx], ...item }\n }\n } else {\n if (item.enabled !== false) {\n merged.push(item)\n }\n }\n }\n }\n\n return ensureOpenInEditorLast(merged)\n}\n\nfunction ensureOpenInEditorLast(intents: IntentConfig[]): IntentConfig[] {\n const idx = intents.findIndex(i => i.id === 'open-in-editor')\n if (idx === -1 || idx === intents.length - 1) return intents\n const result = [...intents]\n const item = result.splice(idx, 1)[0]!\n result.push(item)\n return result\n}\n\nlet watchers: fs.FSWatcher[] = []\n\nexport function watchConfig(onReload: () => void, cwd = process.cwd(), gitRoot?: string): void {\n if (isWatching) return\n isWatching = true\n\n // Watch .inspecto/ directories rather than individual files so that newly\n // created files (e.g. prompts.local.json added after server start) are picked up.\n const watchDirs: string[] = [path.join(os.homedir(), '.inspecto')]\n const roots = resolveConfigRoots(cwd, gitRoot ?? cwd)\n for (const root of roots) {\n watchDirs.push(path.join(root, '.inspecto'))\n }\n\n const CONFIG_FILES = new Set([\n 'settings.json',\n 'settings.local.json',\n 'prompts.json',\n 'prompts.local.json',\n ])\n\n for (const dir of watchDirs) {\n if (!fs.existsSync(dir)) continue\n try {\n const watcher = fs.watch(dir, async (eventType, filename) => {\n if (!filename || !CONFIG_FILES.has(filename)) return\n loadedConfig = null\n loadedPrompts = null\n loadUserConfigSync(true, cwd, gitRoot)\n await loadPromptsConfig(true, cwd, gitRoot)\n onReload()\n })\n watcher.unref()\n watchers.push(watcher)\n } catch (e) {\n // ignore watch errors (e.g. unsupported fs)\n }\n }\n}\n\nexport function unwatchConfig(): void {\n for (const watcher of watchers) {\n watcher.close()\n }\n watchers = []\n isWatching = false\n}\n","import type { LogLevel } from '@inspecto-dev/types'\n\nexport interface Logger {\n info(msg: string, ...args: any[]): void\n warn(msg: string, ...args: any[]): void\n error(msg: string, ...args: any[]): void\n debug(msg: string, ...args: any[]): void\n setLevel?(level: LogLevel): void\n}\n\nconst LOG_LEVELS: Record<LogLevel, number> = {\n silent: 0,\n error: 1,\n warn: 2,\n info: 3,\n}\n\n// Very simple implementation of a DEBUG matching string.\n// Supports `DEBUG=inspecto:*` or `DEBUG=inspecto:server,inspecto:ast`\nfunction isDebugEnabled(namespace: string): boolean {\n if (typeof process === 'undefined' || !process.env) return false\n const debugEnv = process.env.DEBUG\n if (!debugEnv) return false\n\n const namespaces = debugEnv.split(',').map(s => s.trim())\n for (const ns of namespaces) {\n if (ns === '*') return true\n if (ns.endsWith('*')) {\n const prefix = ns.slice(0, -1)\n if (namespace.startsWith(prefix)) return true\n } else if (ns === namespace) {\n return true\n }\n }\n return false\n}\n\n// Store global level locally to avoid circular dependency with config.ts\nlet globalLevel: LogLevel = 'warn'\nconst registeredLoggers: Set<Logger> = new Set()\n\nexport function setLoggerGlobalLevel(level: LogLevel) {\n globalLevel = level\n for (const logger of registeredLoggers) {\n if (logger.setLevel) {\n logger.setLevel(level)\n }\n }\n}\n\nexport function createLogger(namespace: string, options?: { logLevel?: LogLevel }): Logger {\n let currentLevel = options?.logLevel ?? globalLevel\n let numericLevel = LOG_LEVELS[currentLevel] ?? 2\n const debugEnabled = isDebugEnabled(namespace)\n\n const logger: Logger = {\n setLevel(level: LogLevel) {\n currentLevel = level\n numericLevel = LOG_LEVELS[level] ?? 2\n },\n info(msg: string, ...args: any[]) {\n if (numericLevel >= LOG_LEVELS.info) {\n console.log(`\\x1b[36m[inspecto]\\x1b[0m ${msg}`, ...args)\n }\n },\n warn(msg: string, ...args: any[]) {\n if (numericLevel >= LOG_LEVELS.warn) {\n console.warn(`\\x1b[33m[inspecto] WARN:\\x1b[0m ${msg}`, ...args)\n }\n },\n error(msg: string, ...args: any[]) {\n if (numericLevel >= LOG_LEVELS.error) {\n console.error(`\\x1b[31m[inspecto] ERROR:\\x1b[0m ${msg}`, ...args)\n }\n },\n debug(msg: string, ...args: any[]) {\n if (debugEnabled) {\n console.log(`\\x1b[90m[${namespace}]\\x1b[0m ${msg}`, ...args)\n }\n },\n }\n\n registeredLoggers.add(logger)\n\n return logger\n}\n"],"mappings":"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","names":["import_node_fs","import_node_path","import_node_os","import_types","traverse_","path","fs","os","crypto","fs","path","portfinder","http","resolve","os","resolve","path","import_node_path","path"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/legacy/webpack4/index.ts","../../../../../node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.8_typescript@5.9.3_yaml@2.8.3/node_modules/tsup/assets/cjs_shims.js","../../../src/injectors/webpack.ts","../../../src/injectors/utils.ts","../../../src/server/index.ts","../../../src/server/snippet.ts","../../../src/config.ts","../../../src/utils/logger.ts"],"sourcesContent":["import { getWebpackHtmlScript } from '../../injectors/webpack'\nimport { resolveClientModule } from '../../injectors/utils'\nimport { startServer } from '../../server'\nimport path from 'node:path'\n\nexport class InspectoWebpack4Plugin {\n private options: any\n\n constructor(options: any = {}) {\n this.options = options\n }\n\n apply(compiler: any) {\n const clientPath = resolveClientModule()\n\n // 1. Inject the loader dynamically so we don't have to require users to configure loaders manually\n compiler.hooks.afterEnvironment.tap('InspectoWebpack4Plugin', () => {\n const inspectoLoader = path.resolve(__dirname, 'loader.cjs')\n compiler.options.module.rules.push({\n test: /\\.[jt]sx?$/,\n enforce: 'pre',\n exclude: /node_modules/,\n use: [\n {\n loader: inspectoLoader,\n options: {\n ...this.options,\n clientPath,\n },\n },\n ],\n })\n })\n\n // 2. Inject initialization script into HTML\n compiler.hooks.compilation.tap('InspectoWebpack4Plugin', (compilation: any) => {\n // Find HtmlWebpackPlugin from compiler plugins to ensure we get the same instance\n const htmlPlugin = compiler.options.plugins.find(\n (p: any) => p && p.constructor && p.constructor.name === 'HtmlWebpackPlugin',\n )\n\n const HtmlWebpackPlugin = htmlPlugin ? htmlPlugin.constructor : null\n\n if (HtmlWebpackPlugin && HtmlWebpackPlugin.getHooks) {\n HtmlWebpackPlugin.getHooks(compilation).alterAssetTagGroups.tapAsync(\n 'InspectoWebpack4Plugin',\n async (data: any, cb: any) => {\n const port = await startServer()\n data.headTags.unshift({\n tagName: 'script',\n voidTag: false,\n attributes: { 'data-plugin': 'inspecto-overlay' },\n innerHTML: getWebpackHtmlScript(port),\n })\n cb(null, data)\n },\n )\n } else if (compilation.hooks.htmlWebpackPluginAlterAssetTags) {\n // Fallback for html-webpack-plugin v3\n compilation.hooks.htmlWebpackPluginAlterAssetTags.tapAsync(\n 'InspectoWebpack4Plugin',\n async (data: any, cb: any) => {\n const port = await startServer()\n data.head.unshift({\n tagName: 'script',\n voidTag: false,\n attributes: { 'data-plugin': 'inspecto-overlay' },\n innerHTML: getWebpackHtmlScript(port),\n })\n cb(null, data)\n },\n )\n }\n })\n }\n}\n\nexport const webpack4Plugin = (options?: any) => new InspectoWebpack4Plugin(options)\n","// Shim globals in cjs bundle\n// There's a weird bug that esbuild will always inject importMetaUrl\n// if we export it as `const importMetaUrl = ... __filename ...`\n// But using a function will not cause this issue\n\nconst getImportMetaUrl = () => \n typeof document === \"undefined\" \n ? new URL(`file:${__filename}`).href \n : (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') \n ? document.currentScript.src \n : new URL(\"main.js\", document.baseURI).href;\n\nexport const importMetaUrl = /* @__PURE__ */ getImportMetaUrl()\n","export function getWebpackHtmlScript(serverPort: number) {\n return `\nwindow.__AI_INSPECTOR_PORT__ = ${serverPort};\nwindow.addEventListener('load', () => {\n if (window.InspectoClient) {\n window.InspectoClient.mountInspector({\n serverUrl: 'http://127.0.0.1:' + window.__AI_INSPECTOR_PORT__,\n });\n }\n});\n`\n}\n\nexport function getWebpackAssetScript(serverPort: number) {\n return `\nif (typeof window !== 'undefined') {\n window.__AI_INSPECTOR_PORT__ = ${serverPort};\n const _initInspecto = () => {\n if (window.InspectoClient) {\n window.InspectoClient.mountInspector({\n serverUrl: 'http://127.0.0.1:' + window.__AI_INSPECTOR_PORT__,\n });\n } else {\n setTimeout(_initInspecto, 100);\n }\n };\n if (document.readyState === 'complete') {\n _initInspecto();\n } else {\n window.addEventListener('load', _initInspecto);\n }\n}\n`\n}\n\nexport function injectWebpack(\n compiler: any,\n serverPortFn: () => Promise<number>,\n resolveClientModule: () => string,\n) {\n const inspectoClientPath = resolveClientModule()\n\n // Inject the client logic directly using the absolute path\n if (compiler.webpack && compiler.webpack.EntryPlugin) {\n // Webpack 5+\n new compiler.webpack.EntryPlugin(compiler.context, inspectoClientPath, {\n name: undefined,\n }).apply(compiler)\n }\n\n compiler.hooks.compilation.tap('inspecto-overlay', (compilation: any) => {\n // Find HtmlWebpackPlugin (standard Webpack)\n const HtmlWebpackPlugin = compiler.options.plugins.find(\n (p: any) => p && p.constructor && p.constructor.name === 'HtmlWebpackPlugin',\n )\n if (HtmlWebpackPlugin) {\n const hooks = (HtmlWebpackPlugin.constructor as any).getHooks(compilation)\n hooks.alterAssetTagGroups.tapPromise('inspecto-overlay', async (data: any) => {\n const port = await serverPortFn()\n data.headTags.unshift({\n tagName: 'script',\n voidTag: false,\n meta: { plugin: 'inspecto-overlay' },\n innerHTML: getWebpackHtmlScript(port),\n })\n return data\n })\n } else {\n // Fallback for frameworks like Next.js that don't use HtmlWebpackPlugin\n compilation.hooks.processAssets.tapPromise(\n {\n name: 'inspecto-overlay',\n stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONS,\n },\n async (assets: any) => {\n const port = await serverPortFn()\n\n // Only inject into the main client entry chunks (e.g. main-app or main.js)\n const mainAssetKey = Object.keys(assets).find(\n key => key.endsWith('.js') && (key.includes('main') || key.includes('app')),\n )\n if (!mainAssetKey) return\n\n const originalSource = assets[mainAssetKey].source()\n assets[mainAssetKey] = new compiler.webpack.sources.RawSource(\n getWebpackAssetScript(port) + '\\n' + originalSource,\n )\n },\n )\n }\n })\n}\n","import { createRequire } from 'node:module'\n\n// Safely resolve the client module without breaking ESM/CJS or bundling\nexport const resolveClientModule = () => {\n try {\n return createRequire(import.meta.url).resolve('@inspecto-dev/core')\n } catch {\n try {\n return require.resolve('@inspecto-dev/core')\n } catch {\n console.warn(\n '[inspecto] Could not resolve @inspecto-dev/core — falling back to bare specifier',\n )\n return '@inspecto-dev/core'\n }\n }\n}\n","import http from 'node:http'\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport os from 'node:os'\nimport crypto from 'node:crypto'\nimport { execSync, execFileSync } from 'node:child_process'\nimport portfinder from 'portfinder'\nimport { Editor, launchIDE } from 'launch-ide'\nimport type {\n ServerState,\n OpenFileRequest,\n SendToAiRequest,\n SendToAiResponse,\n IdeType,\n Provider,\n} from '@inspecto-dev/types'\nimport { INSPECTO_API_PATHS } from '@inspecto-dev/types'\nimport { extractSnippet } from './snippet.js'\nimport {\n loadUserConfigSync,\n loadPromptsConfig,\n resolveProviderMode,\n extractToolOverrides,\n watchConfig,\n unwatchConfig,\n resolveTargetTool,\n getGlobalLogLevel,\n resolveIntents,\n} from '../config.js'\nimport { createLogger } from '../utils/logger.js'\n\nconst serverLogger = createLogger('inspecto:server', { logLevel: getGlobalLogLevel() })\n\n// In-memory store for large payloads to bypass OS URI length limits.\n// Keys are ticket UUIDs, values are JSON stringified AiPayload objects.\nconst payloadTickets = new Map<string, string>()\n\n// Clean up old tickets to prevent memory leaks (e.g., if IDE never fetches them)\nfunction createTicket(payload: any): string {\n const ticketId = crypto.randomUUID()\n payloadTickets.set(ticketId, JSON.stringify(payload))\n\n // Auto-expire tickets after 5 minutes\n setTimeout(\n () => {\n payloadTickets.delete(ticketId)\n },\n 5 * 60 * 1000,\n )\n\n return ticketId\n}\n\nexport const serverState: ServerState = {\n port: null,\n running: false,\n projectRoot: '',\n configRoot: '',\n cwd: process.cwd(),\n}\n\nlet serverInstance: http.Server | null = null\n\n// Remove unused detectTraeScheme function\n\nfunction resolveProjectRoot(): string {\n const cwd = process.cwd()\n let gitRoot: string\n try {\n gitRoot = execSync('git rev-parse --show-toplevel', { encoding: 'utf-8' }).trim()\n } catch (e) {\n serverLogger.warn('Failed to resolve git root via git rev-parse:', e)\n gitRoot = cwd\n }\n\n const visited = new Set<string>()\n const search = (start: string, stop: string) => {\n let current = start\n while (!visited.has(current)) {\n visited.add(current)\n if (fs.existsSync(path.join(current, '.inspecto'))) return current\n if (current === stop) break\n const parent = path.dirname(current)\n if (parent === current) break\n current = parent\n }\n return null\n }\n\n // First prefer cwd (handles nested packages with their own .inspecto)\n const cwdMatch = search(cwd, path.parse(cwd).root)\n if (cwdMatch) return cwdMatch\n\n // Then search from gitRoot upwards to filesystem root\n const repoMatch = search(gitRoot, path.parse(gitRoot).root)\n if (repoMatch) return repoMatch\n\n return gitRoot\n}\n\n// Function to safely launch a URI to avoid launch-ide swallow bugs on macOS\nfunction launchURI(uri: string): void {\n try {\n if (process.platform === 'darwin') {\n execFileSync('open', [uri])\n } else if (process.platform === 'win32') {\n execFileSync('cmd', ['/c', 'start', '\"\"', uri])\n } else {\n execFileSync('xdg-open', [uri])\n }\n } catch (e) {\n serverLogger.error('Failed to launch URI via execFileSync, falling back to launchIDE:', e)\n launchIDE({ file: uri })\n }\n}\n\nexport async function startServer(): Promise<number> {\n if (serverState.running && serverState.port !== null) {\n return serverState.port\n }\n\n // Resolve project root at server start time so process.cwd() reflects the\n // actual project directory, not the module load-time cwd.\n serverState.projectRoot = resolveProjectRoot()\n serverState.configRoot = serverState.projectRoot\n serverState.cwd = process.cwd()\n\n portfinder.basePort = 5678\n const port = await portfinder.getPortPromise()\n\n // Watch for user config changes to trigger hot-reloads internally if needed\n watchConfig(\n () => {\n serverLogger.info('user config reloaded.')\n },\n serverState.cwd,\n serverState.configRoot,\n )\n\n serverInstance = http.createServer((req, res) => {\n res.setHeader('Access-Control-Allow-Origin', '*')\n res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type')\n\n if (req.method === 'OPTIONS') {\n res.writeHead(204)\n res.end()\n return\n }\n\n const url = new URL(req.url ?? '/', `http://localhost:${port}`)\n handleRequest(url, req, res).catch(err => {\n serverLogger.error('server error:', err)\n res.writeHead(500, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify({ success: false, error: String(err) }))\n })\n })\n\n await new Promise<void>((resolve, reject) => {\n serverInstance!.listen(port, '127.0.0.1', () => {\n serverInstance!.unref() // Allow process to exit\n resolve()\n })\n serverInstance!.once('error', reject)\n })\n\n // Add persistent error handler after successful startup\n serverInstance!.on('error', err => {\n serverLogger.error('persistent server error:', err)\n })\n\n serverState.port = port\n serverState.running = true\n\n // Write port file so the IDE extension can discover the server without scanning ports\n const portFile = path.join(os.tmpdir(), 'inspecto.port.json')\n try {\n let portData: Record<string, number> = {}\n if (fs.existsSync(portFile)) {\n try {\n portData = JSON.parse(fs.readFileSync(portFile, 'utf-8'))\n } catch (e) {\n // Invalid JSON, start fresh\n }\n }\n // Hash the project root to avoid invalid keys or paths in JSON\n const rootHash = crypto.createHash('md5').update(serverState.projectRoot).digest('hex')\n portData[rootHash] = port\n fs.writeFileSync(portFile, JSON.stringify(portData, null, 2), 'utf-8')\n } catch (e) {\n serverLogger.warn('Failed to write port file:', e)\n /* non-fatal — extension will fall back to scanning */\n }\n // Clean up on process exit (Vite terminates the process, not stopServer)\n process.once('exit', () => {\n try {\n if (fs.existsSync(portFile)) {\n const portData = JSON.parse(fs.readFileSync(portFile, 'utf-8'))\n const rootHash = crypto.createHash('md5').update(serverState.projectRoot).digest('hex')\n delete portData[rootHash]\n if (Object.keys(portData).length === 0) {\n fs.unlinkSync(portFile)\n } else {\n fs.writeFileSync(portFile, JSON.stringify(portData, null, 2), 'utf-8')\n }\n }\n } catch {\n /* ignore */\n }\n })\n\n serverLogger.info(`server running at http://127.0.0.1:${port}`)\n\n return port\n}\n\nexport function stopServer(): void {\n if (serverInstance) {\n serverInstance.close()\n serverInstance = null\n }\n unwatchConfig()\n serverState.running = false\n serverState.port = null\n try {\n fs.unlinkSync(path.join(os.tmpdir(), 'inspecto.port'))\n } catch {\n /* ignore */\n }\n}\n\nasync function readBody(req: http.IncomingMessage): Promise<string> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = []\n req.on('data', (chunk: Buffer) => chunks.push(chunk))\n req.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')))\n req.on('error', reject)\n })\n}\n\nasync function handleRequest(\n url: URL,\n req: http.IncomingMessage,\n res: http.ServerResponse,\n): Promise<void> {\n const pathname = url.pathname\n\n // Health check - root or /inspecto/api/v1/health\n if ((pathname === '/health' || pathname === INSPECTO_API_PATHS.HEALTH) && req.method === 'GET') {\n res.writeHead(200, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify({ ok: true, port: serverState.port }))\n return\n }\n\n // Browser Client requests\n if (pathname === INSPECTO_API_PATHS.CLIENT_CONFIG && req.method === 'GET') {\n const userConfig = loadUserConfigSync(false, serverState.cwd, serverState.configRoot)\n const promptsConfig = await loadPromptsConfig(false, serverState.cwd, serverState.configRoot)\n const effectiveIde = (userConfig.ide ?? 'vscode') as IdeType\n\n let info: any\n if (!serverState.ideInfo) {\n info = {\n ide: effectiveIde,\n }\n } else {\n const { scheme: _scheme, ...rest } = serverState.ideInfo as any\n info = rest\n }\n\n const config = {\n ...info,\n prompts: resolveIntents(promptsConfig),\n hotKeys: userConfig['inspector.hotKey'] ?? 'alt',\n theme: userConfig['inspector.theme'] ?? 'auto',\n includeSnippet: userConfig['prompt.includeSnippet'] ?? false,\n autoSend: userConfig['prompt.autoSend'] ?? false,\n }\n\n // Omit providers from the response sent to the client\n delete config.providers\n\n res.writeHead(200, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify(config))\n return\n }\n\n if (pathname === INSPECTO_API_PATHS.IDE_INFO && req.method === 'POST') {\n try {\n const body = JSON.parse(await readBody(req))\n\n // Workspace matching defense mechanism against multiple IDE connections\n const ideWorkspace = body.workspaceRoot || ''\n const serverProjectRoot = serverState.projectRoot || ''\n\n const normalizedIdeRoot = ideWorkspace ? path.resolve(ideWorkspace) : ''\n const normalizedServerRoot = serverProjectRoot ? path.resolve(serverProjectRoot) : ''\n\n const isSameProject =\n !normalizedIdeRoot ||\n !normalizedServerRoot ||\n normalizedIdeRoot === normalizedServerRoot ||\n normalizedServerRoot.startsWith(normalizedIdeRoot + path.sep) ||\n normalizedIdeRoot.startsWith(normalizedServerRoot + path.sep)\n\n if (isSameProject) {\n serverState.ideInfo = body\n serverLogger.debug(\n `Accepted IDE info from matched workspace (ide-${body.ide} / schema-${body.scheme})`,\n )\n } else {\n serverLogger.debug(\n `Ignored IDE info from unrelated workspace (IDE Workspace: ${ideWorkspace}, Server: ${serverProjectRoot}, Scheme: ${body.scheme}, IDE: ${body.ide})`,\n )\n }\n\n res.writeHead(200, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify({ success: true }))\n } catch (e) {\n serverLogger.error(`Error parsing ${INSPECTO_API_PATHS.IDE_INFO} POST request:`, e)\n res.writeHead(400, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify({ error: 'Invalid JSON body' }))\n }\n return\n }\n\n if (pathname === INSPECTO_API_PATHS.IDE_OPEN && req.method === 'POST') {\n let body: OpenFileRequest\n try {\n body = JSON.parse(await readBody(req)) as OpenFileRequest\n } catch (e) {\n res.writeHead(400, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify({ error: 'Invalid JSON body' }))\n return\n }\n\n const absolutePath = path.isAbsolute(body.file)\n ? path.resolve(body.file)\n : path.resolve(serverState.cwd, body.file)\n\n // Security: Prevent path traversal attacks\n const relativeToRoot = path.relative(serverState.projectRoot, absolutePath)\n if (relativeToRoot.startsWith('..') || path.isAbsolute(relativeToRoot)) {\n serverLogger.warn(`Security: Blocked path traversal attempt in IDE_OPEN: ${body.file}`)\n res.writeHead(403, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify({ error: 'Access denied: File is outside of project workspace' }))\n return\n }\n\n const userConfig = loadUserConfigSync(false, serverState.cwd, serverState.configRoot)\n\n // Strict Config Override: Respect user config if explicitly set and differs from active IDE\n const configuredIde = userConfig.ide\n const activeIde = serverState.ideInfo?.ide\n const activeIdeScheme = serverState.ideInfo?.scheme\n\n // Priority: 1. User config 2. Active IDE detection 3. Fallback\n const rawEditorHint = configuredIde || activeIde || activeIdeScheme || 'code'\n\n if (configuredIde && activeIdeScheme && !activeIdeScheme.includes(configuredIde)) {\n serverLogger.warn(\n `Active IDE is ${activeIdeScheme}, but config forces ${configuredIde}. Using configured IDE.`,\n )\n }\n\n let editorHint = rawEditorHint\n if (rawEditorHint === 'vscode') editorHint = 'code'\n else if (rawEditorHint === 'vscode-insiders') editorHint = 'code-insiders'\n else if (rawEditorHint === 'vscodium') editorHint = 'codium'\n // Map trae-cn back to trae for launchIDE to recognize it correctly,\n // since launchIDE only maps 'trae' in its keys.\n else if (rawEditorHint === 'trae-cn' || rawEditorHint === 'trae') editorHint = 'trae'\n\n serverLogger.debug(\n `IDE_OPEN: activeIde=${activeIde}, activeIdeScheme=${activeIdeScheme}, configuredIde=${configuredIde} -> rawEditorHint=${rawEditorHint}, finalEditorHint=${editorHint}`,\n )\n\n // Bypass launchIDE for VSCode family IDEs that support URL schemes.\n // launch-ide has a hardcoded dictionary that maps 'trae-cn' to 'trae://', which fails on macOS.\n // Using the URL scheme directly is more reliable and supports opening files even if the IDE isn't running yet.\n const VSCODE_FAMILY_SCHEMES = [\n 'vscode',\n 'vscode-insiders',\n 'cursor',\n 'windsurf',\n 'trae',\n 'trae-cn',\n 'vscodium',\n 'codebuddy',\n 'codebuddy-cn',\n 'antigravity',\n ]\n\n if (VSCODE_FAMILY_SCHEMES.includes(rawEditorHint)) {\n let normalizedPath = absolutePath.replace(/\\\\/g, '/')\n if (!normalizedPath.startsWith('/')) {\n normalizedPath = '/' + normalizedPath\n }\n const encodedPath = encodeURI(normalizedPath)\n const uri = `${rawEditorHint}://file${encodedPath}:${body.line}:${body.column}`\n serverLogger.debug(`IDE_OPEN: Bypassing launchIDE, using URI scheme directly: ${uri}`)\n\n try {\n if (process.platform === 'darwin') {\n execFileSync('open', [uri])\n } else if (process.platform === 'win32') {\n execFileSync('cmd', ['/c', 'start', '\"\"', uri])\n } else {\n execFileSync('xdg-open', [uri])\n }\n } catch (e) {\n serverLogger.error(`Failed to launch URI for IDE_OPEN (${uri}):`, e)\n // Fallback to launchIDE if scheme launch fails\n launchIDE({\n file: absolutePath,\n line: body.line,\n column: body.column,\n editor: editorHint as Editor,\n type: process.platform === 'darwin' ? 'open' : 'exec',\n })\n }\n } else {\n launchIDE({\n file: absolutePath,\n line: body.line,\n column: body.column,\n editor: editorHint as Editor,\n type: process.platform === 'darwin' ? 'open' : 'exec',\n })\n }\n\n res.writeHead(200, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify({ success: true }))\n return\n }\n\n if (pathname === INSPECTO_API_PATHS.PROJECT_SNIPPET && req.method === 'GET') {\n const file = url.searchParams.get('file') ?? ''\n const line = parseInt(url.searchParams.get('line') ?? '1', 10)\n const column = parseInt(url.searchParams.get('column') ?? '1', 10)\n const maxLines = parseInt(url.searchParams.get('maxLines') ?? '100', 10)\n\n try {\n const absolutePath = path.isAbsolute(file)\n ? path.resolve(file)\n : path.resolve(serverState.cwd, file)\n\n // Security: Prevent path traversal attacks\n const relativeToRoot = path.relative(serverState.projectRoot, absolutePath)\n if (relativeToRoot.startsWith('..') || path.isAbsolute(relativeToRoot)) {\n serverLogger.warn(`Security: Blocked path traversal attempt in PROJECT_SNIPPET: ${file}`)\n res.writeHead(403, { 'Content-Type': 'application/json' })\n res.end(\n JSON.stringify({\n success: false,\n error: 'Access denied: File is outside of project workspace',\n errorCode: 'FORBIDDEN',\n }),\n )\n return\n }\n\n const result = await extractSnippet({ file: absolutePath, line, column, maxLines })\n res.writeHead(200, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify(result))\n } catch (err: any) {\n const message = String(err.message || err)\n const errorCode = message.startsWith('FILE_NOT_FOUND') ? 'FILE_NOT_FOUND' : 'UNKNOWN'\n res.writeHead(404, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify({ success: false, error: message, errorCode }))\n }\n return\n }\n\n if (pathname === INSPECTO_API_PATHS.AI_DISPATCH && req.method === 'POST') {\n try {\n const rawBody = await readBody(req)\n const body = JSON.parse(rawBody) as SendToAiRequest\n const result = await dispatchToAi(body)\n res.writeHead(result.success ? 200 : 500, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify(result))\n } catch (e) {\n serverLogger.error(`Error parsing ${INSPECTO_API_PATHS.AI_DISPATCH} request:`, e)\n res.writeHead(500, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify({ success: false, error: String(e), errorCode: 'INTERNAL_ERROR' }))\n }\n return\n }\n\n // Handle IDE payload ticket retrieval\n if (pathname.startsWith(`${INSPECTO_API_PATHS.AI_TICKET}/`) && req.method === 'GET') {\n const ticketId = pathname.substring(INSPECTO_API_PATHS.AI_TICKET.length + 1)\n const payloadStr = payloadTickets.get(ticketId)\n\n if (!payloadStr) {\n res.writeHead(404, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify({ success: false, error: 'Ticket not found or expired' }))\n return\n }\n\n res.writeHead(200, { 'Content-Type': 'application/json' })\n res.end(payloadStr)\n return\n }\n\n res.writeHead(404, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify({ error: 'not found' }))\n}\n\nasync function dispatchToAi(\n req: SendToAiRequest,\n): Promise<SendToAiResponse & { fallbackPayload?: { prompt: string; file: string } }> {\n const { location, snippet, prompt } = req\n\n const userConfig = loadUserConfigSync(false, serverState.cwd, serverState.configRoot)\n const resolvedTarget = resolveTargetTool(userConfig)\n\n const formattedPrompt =\n prompt ??\n `Please help me with this code from \\`${location.file}\\` (line ${location.line}):\\n\\n\\`\\`\\`\\n${snippet}\\n\\`\\`\\`\\n`\n\n const ideReportedMode = serverState.ideInfo?.providers[resolvedTarget]?.mode\n\n // Generate the full payload\n const configuredIde = userConfig.ide\n const activeIde = serverState.ideInfo?.ide\n const activeIdeScheme = serverState.ideInfo?.scheme\n\n // Priority: 1. User config 2. Active IDE Scheme (for URI construction) 3. Active IDE fallback\n const finalIde: string = configuredIde || activeIdeScheme || activeIde || 'vscode'\n\n if (configuredIde && activeIdeScheme && !activeIdeScheme.includes(configuredIde)) {\n serverLogger.warn(\n `dispatchToAi: Active IDE is ${activeIdeScheme}, but config forces ${configuredIde}. Using configured IDE.`,\n )\n }\n\n const mode = resolveProviderMode(resolvedTarget, finalIde as IdeType, userConfig)\n const overrides = extractToolOverrides(finalIde as IdeType, userConfig)[resolvedTarget] || {}\n overrides.type = mode\n\n const fullPayload = {\n ide: finalIde,\n target: resolvedTarget,\n targetType: mode,\n prompt: formattedPrompt,\n filePath: location.file,\n line: location.line,\n column: location.column,\n snippet,\n overrides: Object.keys(overrides).length > 0 ? overrides : undefined,\n autoSend:\n userConfig['prompt.autoSend'] !== undefined\n ? Boolean(userConfig['prompt.autoSend'])\n : undefined,\n }\n\n // Create a ticket and store the full payload in memory\n const ticketId = createTicket(fullPayload)\n\n // Only pass the ticket and critical routing info via URI\n const params = new URLSearchParams()\n params.set('ticket', ticketId)\n params.set('target', resolvedTarget)\n\n // Use the exact scheme reported by the extension if available, fallback to user config or 'vscode'\n const uri = `${finalIde}://inspecto.inspecto/send?${params.toString()}`\n\n serverLogger.debug(`dispatchToAi: Generated URI: ${uri}`)\n\n launchURI(uri)\n\n // Return success along with the payload so the browser can fallback to clipboard\n return {\n success: true,\n fallbackPayload: {\n prompt: formattedPrompt,\n file: location.file,\n },\n }\n}\n","import * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport * as parser from '@babel/parser'\nimport traverse_ from '@babel/traverse'\n// Support both ESM default and CommonJS module.exports\nconst traverse =\n typeof traverse_ === 'function' ? traverse_ : (traverse_ as any).default || traverse_\nimport type { NodePath } from '@babel/traverse'\nimport type { Node } from '@babel/types'\nimport type { SnippetRequest, SnippetResponse } from '@inspecto-dev/types'\n\ninterface CacheEntry {\n mtime: number\n /** The full parsed source lines */\n lines: string[]\n}\n\n/** In-memory cache keyed by absolute file path */\nconst snippetCache = new Map<string, CacheEntry>()\n\nconst DEFAULT_MAX_LINES = 100\nconst DEFAULT_CONTEXT_LINES_BEFORE = 5\n\nexport async function extractSnippet(req: SnippetRequest): Promise<SnippetResponse> {\n const { file, line, column, maxLines = DEFAULT_MAX_LINES } = req\n\n const absolutePath = path.resolve(file)\n\n let stat: fs.Stats\n try {\n stat = await fs.promises.stat(absolutePath)\n } catch {\n throw new Error(`FILE_NOT_FOUND: ${absolutePath}`)\n }\n\n const mtime = stat.mtimeMs\n\n let lines: string[]\n const cached = snippetCache.get(absolutePath)\n if (cached && cached.mtime === mtime) {\n lines = cached.lines\n } else {\n const source = await fs.promises.readFile(absolutePath, 'utf-8')\n lines = source.split('\\n')\n snippetCache.set(absolutePath, { mtime, lines })\n }\n\n let snippetLines: string[]\n let startLine: number\n let componentName: string | undefined\n\n try {\n const result = extractComponentBoundary(lines.join('\\n'), line, column, maxLines)\n snippetLines = result.lines\n startLine = result.startLine\n componentName = result.name\n } catch {\n const before = Math.max(0, line - 1 - DEFAULT_CONTEXT_LINES_BEFORE)\n const after = Math.min(lines.length, before + maxLines)\n snippetLines = lines.slice(before, after)\n startLine = before + 1\n }\n\n if (snippetLines.length > maxLines) {\n snippetLines = snippetLines.slice(0, maxLines)\n }\n\n return {\n snippet: snippetLines.join('\\n'),\n startLine,\n file: absolutePath,\n ...(componentName ? { name: componentName } : {}),\n }\n}\n\ninterface BoundaryResult {\n lines: string[]\n startLine: number\n name?: string\n}\n\nfunction extractComponentBoundary(\n source: string,\n targetLine: number,\n _targetColumn: number,\n maxLines: number,\n): BoundaryResult {\n const ast = parser.parse(source, {\n sourceType: 'module',\n plugins: ['jsx', 'typescript', 'decorators-legacy', 'classProperties'],\n errorRecovery: true,\n })\n\n const allLines = source.split('\\n')\n\n let bestStart = 0\n let bestEnd = allLines.length - 1\n let bestName: string | undefined\n\n traverse(ast, {\n 'FunctionDeclaration|FunctionExpression|ArrowFunctionExpression|ClassMethod'(\n nodePath: NodePath<Node>,\n ) {\n const node = nodePath.node\n if (!node.loc) return\n\n const nodeStart = node.loc.start.line\n const nodeEnd = node.loc.end.line\n\n if (targetLine < nodeStart || targetLine > nodeEnd) return\n\n if (nodeEnd - nodeStart < bestEnd - bestStart) {\n bestStart = nodeStart - 1\n bestEnd = nodeEnd - 1\n bestName = extractFunctionName(nodePath)\n }\n },\n })\n\n let sliceStart = bestStart\n let sliceEnd = bestEnd + 1\n\n if (sliceEnd - sliceStart > maxLines) {\n const targetIdx = targetLine - 1\n sliceStart = Math.max(bestStart, targetIdx - Math.floor(maxLines / 3))\n sliceEnd = sliceStart + maxLines\n if (sliceEnd > bestEnd + 1) {\n sliceEnd = bestEnd + 1\n sliceStart = Math.max(0, sliceEnd - maxLines)\n }\n }\n\n return {\n lines: allLines.slice(sliceStart, sliceEnd),\n startLine: sliceStart + 1,\n ...(bestName ? { name: bestName } : {}),\n }\n}\n\nfunction extractFunctionName(nodePath: NodePath<Node>): string | undefined {\n const node = nodePath.node\n\n if (node.type === 'FunctionDeclaration' && node.id) {\n return node.id.name\n }\n\n const parent = nodePath.parent\n if (\n (node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression') &&\n parent.type === 'VariableDeclarator' &&\n parent.id.type === 'Identifier'\n ) {\n return parent.id.name\n }\n\n if (node.type === 'ClassMethod' && node.key.type === 'Identifier') {\n return node.key.name\n }\n\n return undefined\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport os from 'node:os'\nimport { createDefu } from 'defu'\nimport type {\n InspectoSettings,\n InspectoPromptsConfig,\n Provider,\n ProviderMode,\n ToolOverrides,\n IdeType,\n LogLevel,\n} from '@inspecto-dev/types'\nimport {\n DEFAULT_PROVIDER_MODE,\n VALID_MODES,\n DEFAULT_INTENTS,\n IntentConfig,\n} from '@inspecto-dev/types'\nimport { createLogger, setLoggerGlobalLevel } from './utils/logger.js'\n\nconst configLogger = createLogger('inspecto:config')\n\nlet loadedConfig: InspectoSettings | null = null\nlet loadedPrompts: InspectoPromptsConfig | null = null\nlet globalLogLevel: LogLevel = 'warn'\nlet isWatching = false\n\n// Custom array merge behavior for defu: overwrite arrays instead of concatenating them\nconst arrayReplaceMerge = createDefu((obj, key, val) => {\n if (Array.isArray(val)) {\n obj[key] = val\n return true\n }\n})\n\nexport function setGlobalLogLevel(level?: LogLevel) {\n if (level) {\n globalLogLevel = level\n setLoggerGlobalLevel(level)\n }\n}\n\nexport function getGlobalLogLevel() {\n return globalLogLevel\n}\n\n/**\n * Walk from cwd up to gitRoot (inclusive), collecting directories that contain\n * a .inspecto/ subdirectory. Returns them ordered highest-priority first\n * (closest to cwd first).\n *\n * If cwd is not under gitRoot, only cwd itself is checked.\n */\nexport function resolveConfigRoots(cwd: string, gitRoot: string): string[] {\n const roots: string[] = []\n let current = cwd\n\n // Ensure we don't walk past gitRoot (handles cwd above gitRoot case)\n const isUnderOrEqual = current === gitRoot || current.startsWith(gitRoot + path.sep)\n if (!isUnderOrEqual) {\n // cwd is not under gitRoot — only check cwd\n if (fs.existsSync(path.join(cwd, '.inspecto'))) roots.push(cwd)\n return roots\n }\n\n while (true) {\n if (fs.existsSync(path.join(current, '.inspecto'))) {\n roots.push(current)\n }\n if (current === gitRoot) break\n const parent = path.dirname(current)\n if (parent === current) break // filesystem root guard\n current = parent\n }\n\n return roots\n}\n\n/**\n * Load and merge user config from all discovered .inspecto/ layers:\n *\n * Priority (highest → lowest):\n * <cwd>/.inspecto/settings.local.json\n * <cwd>/.inspecto/settings.json\n * ...intermediate dirs...\n * <gitRoot>/.inspecto/settings.local.json\n * <gitRoot>/.inspecto/settings.json\n * ~/.inspecto/settings.json\n *\n * @param force Bust cache and re-read from disk\n * @param cwd Working directory to start resolution from (default: process.cwd())\n * @param gitRoot Git repository root — upward traversal stops here (optional)\n */\nexport function loadUserConfigSync(\n force = false,\n cwd = process.cwd(),\n gitRoot?: string,\n): InspectoSettings {\n if (loadedConfig && !force) return loadedConfig\n loadedConfig = null // force clear\n\n const layers: Partial<InspectoSettings>[] = []\n const roots = resolveConfigRoots(cwd, gitRoot ?? cwd)\n\n for (const root of roots) {\n layers.push(readJsonSafely(path.join(root, '.inspecto', 'settings.local.json')))\n layers.push(readJsonSafely(path.join(root, '.inspecto', 'settings.json')))\n }\n\n layers.push(readJsonSafely(path.join(os.homedir(), '.inspecto', 'settings.json')))\n layers.push({})\n\n const validLayers = layers.filter(l => l !== null)\n loadedConfig = arrayReplaceMerge(...(validLayers as [object, ...object[]])) as InspectoSettings\n return loadedConfig\n}\n\n/**\n * Load and merge prompts config from all discovered .inspecto/ layers:\n *\n * Priority (highest → lowest):\n * <cwd>/.inspecto/prompts.local.json\n * <cwd>/.inspecto/prompts.json\n * ...intermediate dirs...\n * <gitRoot>/.inspecto/prompts.local.json\n * <gitRoot>/.inspecto/prompts.json\n * ~/.inspecto/prompts.json\n *\n * Arrays in custom configurations are replaced instead of merged.\n */\nexport async function loadPromptsConfig(\n force = false,\n cwd = process.cwd(),\n gitRoot?: string,\n): Promise<InspectoPromptsConfig> {\n if (loadedPrompts && !force) return loadedPrompts\n\n const layers: any[] = []\n\n const roots = resolveConfigRoots(cwd, gitRoot ?? cwd)\n for (const root of roots) {\n const localPath = path.join(root, '.inspecto', 'prompts.local.json')\n const jsonPath = path.join(root, '.inspecto', 'prompts.json')\n layers.push(readJsonSafely(localPath))\n layers.push(readJsonSafely(jsonPath))\n }\n\n layers.push(readJsonSafely(path.join(os.homedir(), '.inspecto', 'prompts.json')))\n\n // Find the first layer that contains a valid prompts config (array or $replace object).\n // Highest-priority layer wins — no merging across layers for prompts.\n let finalPrompts: any = []\n for (const layer of layers) {\n if (Array.isArray(layer) && layer.length > 0) {\n finalPrompts = layer\n break\n }\n if (\n layer &&\n typeof layer === 'object' &&\n layer.$replace === true &&\n Array.isArray(layer.items)\n ) {\n finalPrompts = layer\n break\n }\n }\n\n loadedPrompts = finalPrompts as InspectoPromptsConfig\n return loadedPrompts\n}\n\nfunction readJsonSafely(filePath: string): any {\n try {\n if (fs.existsSync(filePath)) {\n const content = fs.readFileSync(filePath, 'utf-8').trim()\n if (!content) return null // Return null instead of [] so we know it's empty\n const parsed = JSON.parse(content)\n // Transition helper: if user still has {\"prompts\": [...]}, extract it\n if (!Array.isArray(parsed) && parsed.prompts && Array.isArray(parsed.prompts)) {\n return parsed.prompts\n }\n return parsed\n }\n } catch (e) {\n // Ignore JSON parsing errors for empty or malformed files during watch\n if (e instanceof SyntaxError) {\n configLogger.warn(`Failed to parse config at ${filePath}: Invalid JSON`)\n } else {\n configLogger.warn(`Failed to read config at ${filePath}:`, e)\n }\n }\n return null\n}\n\n/**\n * Resolve the exact target tool to dispatch to based on user config.\n */\nexport function resolveTargetTool(config: InspectoSettings, ide: IdeType = 'vscode'): Provider {\n // Support \"provider.default\" (e.g., \"claude-code.extension\")\n const defaultProvider = config['provider.default'] as string | undefined\n if (defaultProvider) {\n const tool = defaultProvider.split('.')[0]\n return tool as Provider\n }\n\n // Fallback\n return 'copilot'\n}\n\n/**\n * Resolve the effective mode/type for a tool in the context of an IDE.\n */\nexport function resolveProviderMode(\n tool: Provider,\n ide: IdeType,\n config: InspectoSettings,\n): ProviderMode {\n let requestedType: ProviderMode | undefined = undefined\n\n // V2 format: check provider.default for \"tool.mode\"\n const defaultProvider = config['provider.default'] as string | undefined\n if (defaultProvider && defaultProvider.startsWith(`${tool}.`)) {\n const mode = defaultProvider.split('.')[1]\n if (mode === 'extension') requestedType = 'extension'\n if (mode === 'cli') requestedType = 'cli'\n }\n\n requestedType = requestedType ?? DEFAULT_PROVIDER_MODE[tool]\n const valid = VALID_MODES[tool] || [DEFAULT_PROVIDER_MODE[tool]]\n return requestedType && valid.includes(requestedType) ? requestedType : valid[0]!\n}\n\n/**\n * Extract ToolOverrides (binaryPath, args, etc) for Extension consumption.\n */\nexport function extractToolOverrides(\n ide: IdeType,\n config: InspectoSettings,\n): Partial<Record<Provider, ToolOverrides>> {\n const result: Partial<Record<Provider, ToolOverrides>> = {}\n\n if (!config) return result\n\n // Parse new flat `provider.*` format\n for (const [key, value] of Object.entries(config)) {\n if (!key.startsWith('provider.')) continue\n\n // We only process tool specific overrides, ignore `.default`\n if (key === 'provider.default') continue\n\n // Handle `provider.[tool].[mode]`\n const toolIndex = 1\n const modeIndex = 2\n const propIndex = 3\n\n const parts = key.split('.')\n\n if (parts.length >= propIndex + 1) {\n const tool = parts[toolIndex] as Provider\n const mode = parts[modeIndex] as ProviderMode\n const prop = parts[propIndex]\n\n if (!result[tool]) {\n result[tool] = { type: mode }\n }\n\n const overrides = result[tool]!\n\n // If we see config for a mode that differs from what we've initialized,\n // it means both modes have config. In v2, mode is determined by provider.default.\n // We will just accumulate the settings for now and let resolveProviderMode decide the active type.\n\n if (prop === 'bin') overrides.binaryPath = value as string\n if (prop === 'args') overrides.args = value as string[]\n if (prop === 'cwd') overrides.cwd = value as string\n if (prop === 'coldStartDelay') overrides.coldStartDelay = value as number\n }\n }\n\n return result\n}\n\nexport function resolveIntents(serverPrompts?: InspectoPromptsConfig): IntentConfig[] {\n // Start with DEFAULT_INTENTS as base\n const baseMap = new Map<string, IntentConfig>()\n for (const intent of DEFAULT_INTENTS) {\n if (intent.id) baseMap.set(intent.id, { ...intent })\n }\n\n const defaults = () => ensureOpenInEditorLast(Array.from(baseMap.values()))\n\n if (!serverPrompts) return defaults()\n\n const isReplace =\n !Array.isArray(serverPrompts) &&\n typeof serverPrompts === 'object' &&\n serverPrompts.$replace === true\n const promptsArray = Array.isArray(serverPrompts)\n ? serverPrompts\n : isReplace\n ? serverPrompts.items\n : []\n\n if (!promptsArray || promptsArray.length === 0) return defaults()\n\n if (isReplace) {\n // $replace: true — exact list, user controls everything\n const result: IntentConfig[] = []\n for (const item of promptsArray) {\n if (typeof item === 'string') {\n if (baseMap.has(item)) {\n result.push(baseMap.get(item)!)\n } else {\n configLogger.warn(\n `Unknown built-in intent id: \"${item}\". Available: ${[...baseMap.keys()].join(', ')}`,\n )\n }\n } else if (typeof item === 'object') {\n if (!item.id) {\n configLogger.warn('Intent object missing required \"id\" field, skipping.')\n continue\n }\n if (item.enabled === false) {\n configLogger.warn(\n `Intent \"${item.id}\" is listed in $replace but has enabled:false — it will be excluded.`,\n )\n continue\n }\n if (item.isAction && item.id !== 'open-in-editor') {\n configLogger.warn(\n `isAction is reserved for built-in actions. Ignoring intent \"${item.id}\".`,\n )\n continue\n }\n result.push(baseMap.has(item.id) ? { ...baseMap.get(item.id)!, ...item } : item)\n }\n }\n return ensureOpenInEditorLast(result)\n }\n\n // Default: append / override mode.\n // - Objects with known id: merge over built-in (or remove if enabled:false)\n // - Objects with unknown id: append as new intent\n // - Strings: not meaningful in append mode (order is fixed to built-in order + appended)\n const merged = Array.from(baseMap.values())\n\n for (const item of promptsArray) {\n if (typeof item === 'string') {\n if (!baseMap.has(item)) {\n configLogger.warn(\n `Unknown built-in intent id: \"${item}\". In append mode, strings have no effect on ordering — use $replace to control order.`,\n )\n }\n // Known string ids are already in merged — nothing to do\n continue\n }\n\n if (typeof item === 'object') {\n if (!item.id) {\n configLogger.warn('Intent object missing required \"id\" field, skipping.')\n continue\n }\n if (item.isAction && item.id !== 'open-in-editor') {\n configLogger.warn(\n `isAction is reserved for built-in actions. Ignoring intent \"${item.id}\".`,\n )\n continue\n }\n\n const existingIdx = merged.findIndex(i => i.id === item.id)\n if (existingIdx !== -1) {\n if (item.enabled === false) {\n merged.splice(existingIdx, 1)\n } else {\n merged[existingIdx] = { ...merged[existingIdx], ...item }\n }\n } else {\n if (item.enabled !== false) {\n merged.push(item)\n }\n }\n }\n }\n\n return ensureOpenInEditorLast(merged)\n}\n\nfunction ensureOpenInEditorLast(intents: IntentConfig[]): IntentConfig[] {\n const idx = intents.findIndex(i => i.id === 'open-in-editor')\n if (idx === -1 || idx === intents.length - 1) return intents\n const result = [...intents]\n const item = result.splice(idx, 1)[0]!\n result.push(item)\n return result\n}\n\nlet watchers: fs.FSWatcher[] = []\n\nexport function watchConfig(onReload: () => void, cwd = process.cwd(), gitRoot?: string): void {\n if (isWatching) return\n isWatching = true\n\n // Watch .inspecto/ directories rather than individual files so that newly\n // created files (e.g. prompts.local.json added after server start) are picked up.\n const watchDirs: string[] = [path.join(os.homedir(), '.inspecto')]\n const roots = resolveConfigRoots(cwd, gitRoot ?? cwd)\n for (const root of roots) {\n watchDirs.push(path.join(root, '.inspecto'))\n }\n\n const CONFIG_FILES = new Set([\n 'settings.json',\n 'settings.local.json',\n 'prompts.json',\n 'prompts.local.json',\n ])\n\n for (const dir of watchDirs) {\n if (!fs.existsSync(dir)) continue\n try {\n const watcher = fs.watch(dir, async (eventType, filename) => {\n if (!filename || !CONFIG_FILES.has(filename)) return\n loadedConfig = null\n loadedPrompts = null\n loadUserConfigSync(true, cwd, gitRoot)\n await loadPromptsConfig(true, cwd, gitRoot)\n onReload()\n })\n watcher.unref()\n watchers.push(watcher)\n } catch (e) {\n // ignore watch errors (e.g. unsupported fs)\n }\n }\n}\n\nexport function unwatchConfig(): void {\n for (const watcher of watchers) {\n watcher.close()\n }\n watchers = []\n isWatching = false\n}\n","import type { LogLevel } from '@inspecto-dev/types'\n\nexport interface Logger {\n info(msg: string, ...args: any[]): void\n warn(msg: string, ...args: any[]): void\n error(msg: string, ...args: any[]): void\n debug(msg: string, ...args: any[]): void\n setLevel?(level: LogLevel): void\n}\n\nconst LOG_LEVELS: Record<LogLevel, number> = {\n silent: 0,\n error: 1,\n warn: 2,\n info: 3,\n}\n\n// Very simple implementation of a DEBUG matching string.\n// Supports `DEBUG=inspecto:*` or `DEBUG=inspecto:server,inspecto:ast`\nfunction isDebugEnabled(namespace: string): boolean {\n if (typeof process === 'undefined' || !process.env) return false\n const debugEnv = process.env.DEBUG\n if (!debugEnv) return false\n\n const namespaces = debugEnv.split(',').map(s => s.trim())\n for (const ns of namespaces) {\n if (ns === '*') return true\n if (ns.endsWith('*')) {\n const prefix = ns.slice(0, -1)\n if (namespace.startsWith(prefix)) return true\n } else if (ns === namespace) {\n return true\n }\n }\n return false\n}\n\n// Store global level locally to avoid circular dependency with config.ts\nlet globalLevel: LogLevel = 'warn'\nconst registeredLoggers: Set<Logger> = new Set()\n\nexport function setLoggerGlobalLevel(level: LogLevel) {\n globalLevel = level\n for (const logger of registeredLoggers) {\n if (logger.setLevel) {\n logger.setLevel(level)\n }\n }\n}\n\nexport function createLogger(namespace: string, options?: { logLevel?: LogLevel }): Logger {\n let currentLevel = options?.logLevel ?? globalLevel\n let numericLevel = LOG_LEVELS[currentLevel] ?? 2\n const debugEnabled = isDebugEnabled(namespace)\n\n const logger: Logger = {\n setLevel(level: LogLevel) {\n currentLevel = level\n numericLevel = LOG_LEVELS[level] ?? 2\n },\n info(msg: string, ...args: any[]) {\n if (numericLevel >= LOG_LEVELS.info) {\n console.log(`\\x1b[36m[inspecto]\\x1b[0m ${msg}`, ...args)\n }\n },\n warn(msg: string, ...args: any[]) {\n if (numericLevel >= LOG_LEVELS.warn) {\n console.warn(`\\x1b[33m[inspecto] WARN:\\x1b[0m ${msg}`, ...args)\n }\n },\n error(msg: string, ...args: any[]) {\n if (numericLevel >= LOG_LEVELS.error) {\n console.error(`\\x1b[31m[inspecto] ERROR:\\x1b[0m ${msg}`, ...args)\n }\n },\n debug(msg: string, ...args: any[]) {\n if (debugEnabled) {\n console.log(`\\x1b[90m[${namespace}]\\x1b[0m ${msg}`, ...args)\n }\n },\n }\n\n registeredLoggers.add(logger)\n\n return logger\n}\n"],"mappings":"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","names":["import_node_fs","import_node_path","import_node_os","import_types","traverse_","path","fs","os","crypto","fs","path","portfinder","http","resolve","os","resolve","path","import_node_path","path"]}
|
|
@@ -516,22 +516,31 @@ var serverState = {
|
|
|
516
516
|
};
|
|
517
517
|
var serverInstance = null;
|
|
518
518
|
function resolveProjectRoot() {
|
|
519
|
+
const cwd = process.cwd();
|
|
519
520
|
let gitRoot;
|
|
520
521
|
try {
|
|
521
|
-
serverLogger.info("Resolving project root...");
|
|
522
522
|
gitRoot = execSync("git rev-parse --show-toplevel", { encoding: "utf-8" }).trim();
|
|
523
|
-
serverLogger.info("Resolved project root: " + gitRoot);
|
|
524
523
|
} catch (e) {
|
|
525
|
-
serverLogger.
|
|
526
|
-
gitRoot =
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
524
|
+
serverLogger.warn("Failed to resolve git root via git rev-parse:", e);
|
|
525
|
+
gitRoot = cwd;
|
|
526
|
+
}
|
|
527
|
+
const visited = /* @__PURE__ */ new Set();
|
|
528
|
+
const search = (start, stop) => {
|
|
529
|
+
let current = start;
|
|
530
|
+
while (!visited.has(current)) {
|
|
531
|
+
visited.add(current);
|
|
532
|
+
if (fs3.existsSync(path4.join(current, ".inspecto"))) return current;
|
|
533
|
+
if (current === stop) break;
|
|
534
|
+
const parent = path4.dirname(current);
|
|
535
|
+
if (parent === current) break;
|
|
536
|
+
current = parent;
|
|
537
|
+
}
|
|
538
|
+
return null;
|
|
539
|
+
};
|
|
540
|
+
const cwdMatch = search(cwd, path4.parse(cwd).root);
|
|
541
|
+
if (cwdMatch) return cwdMatch;
|
|
542
|
+
const repoMatch = search(gitRoot, path4.parse(gitRoot).root);
|
|
543
|
+
if (repoMatch) return repoMatch;
|
|
535
544
|
return gitRoot;
|
|
536
545
|
}
|
|
537
546
|
function launchURI(uri) {
|
|
@@ -671,7 +680,9 @@ async function handleRequest(url, req, res) {
|
|
|
671
680
|
const body = JSON.parse(await readBody(req));
|
|
672
681
|
const ideWorkspace = body.workspaceRoot || "";
|
|
673
682
|
const serverProjectRoot = serverState.projectRoot || "";
|
|
674
|
-
const
|
|
683
|
+
const normalizedIdeRoot = ideWorkspace ? path4.resolve(ideWorkspace) : "";
|
|
684
|
+
const normalizedServerRoot = serverProjectRoot ? path4.resolve(serverProjectRoot) : "";
|
|
685
|
+
const isSameProject = !normalizedIdeRoot || !normalizedServerRoot || normalizedIdeRoot === normalizedServerRoot || normalizedServerRoot.startsWith(normalizedIdeRoot + path4.sep) || normalizedIdeRoot.startsWith(normalizedServerRoot + path4.sep);
|
|
675
686
|
if (isSameProject) {
|
|
676
687
|
serverState.ideInfo = body;
|
|
677
688
|
serverLogger.debug(
|
|
@@ -739,7 +750,12 @@ async function handleRequest(url, req, res) {
|
|
|
739
750
|
"antigravity"
|
|
740
751
|
];
|
|
741
752
|
if (VSCODE_FAMILY_SCHEMES.includes(rawEditorHint)) {
|
|
742
|
-
|
|
753
|
+
let normalizedPath = absolutePath.replace(/\\/g, "/");
|
|
754
|
+
if (!normalizedPath.startsWith("/")) {
|
|
755
|
+
normalizedPath = "/" + normalizedPath;
|
|
756
|
+
}
|
|
757
|
+
const encodedPath = encodeURI(normalizedPath);
|
|
758
|
+
const uri = `${rawEditorHint}://file${encodedPath}:${body.line}:${body.column}`;
|
|
743
759
|
serverLogger.debug(`IDE_OPEN: Bypassing launchIDE, using URI scheme directly: ${uri}`);
|
|
744
760
|
try {
|
|
745
761
|
if (process.platform === "darwin") {
|