cc-prompter 0.2.0 → 0.3.1
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/README.md +74 -15
- package/dist/client-entry.js +17 -0
- package/dist/index.cjs +203 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +53 -1
- package/dist/index.d.ts +53 -1
- package/dist/index.js +221 -25
- package/dist/index.js.map +1 -1
- package/dist/inject.js +46 -9
- package/dist/next-plugin.cjs +1148 -0
- package/dist/next-plugin.cjs.map +1 -0
- package/dist/next-plugin.d.cts +44 -0
- package/dist/next-plugin.d.ts +44 -0
- package/dist/next-plugin.js +1131 -0
- package/dist/next-plugin.js.map +1 -0
- package/dist/webpack-plugin.cjs +1078 -0
- package/dist/webpack-plugin.cjs.map +1 -0
- package/dist/webpack-plugin.d.cts +42 -0
- package/dist/webpack-plugin.d.ts +42 -0
- package/dist/webpack-plugin.js +1047 -0
- package/dist/webpack-plugin.js.map +1 -0
- package/package.json +23 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/webpack-plugin.ts","../src/sidecar.ts","../src/pty-session.ts","../src/assets.ts"],"sourcesContent":["/**\n * CC Prompter — Webpack Plugin\n *\n * 通用 webpack 插件,可在任意 webpack 项目中使用(不限于 Next.js)。\n *\n * 功能:\n * 1. 启动 Sidecar Express server 管理 PTY sessions\n * 2. 内置 code-inspector-plugin(Shift+Alt 悬停定位源码)\n * 3. 通过 DefinePlugin + entry 注入轻量脚本\n *\n * 仅在 dev 模式生效(可通过 dev 选项控制)。\n *\n * 用法:\n * // webpack.config.js\n * const { CcPromptWebpackPlugin } = require('cc-prompter/webpack');\n * module.exports = {\n * plugins: [\n * new CcPromptWebpackPlugin(),\n * ],\n * };\n */\n\nimport type { Server } from 'http';\nimport { join, dirname } from 'path';\nimport { fileURLToPath } from 'url';\nimport { codeInspectorPlugin } from 'code-inspector-plugin';\nimport { startSidecar } from './sidecar.js';\nimport { getInjectScript } from './assets.js';\n\nconst _dirname = typeof __dirname !== 'undefined'\n ? __dirname\n : dirname(fileURLToPath(import.meta.url));\n\nexport interface CcPromptWebpackOptions {\n /** Sidecar 启动端口,默认 3456(被占用时自动 +1) */\n port?: number;\n /** 项目根目录,默认 process.cwd() */\n root?: string;\n /** 是否启用 code-inspector,默认 true */\n inspector?: boolean;\n /** 是否 dev 模式,默认 process.env.NODE_ENV !== 'production' */\n dev?: boolean;\n}\n\nexport class CcPromptWebpackPlugin {\n private options: CcPromptWebpackOptions;\n private sidecarServer: Server | null = null;\n private sidecarStarted = false;\n private cleanedUp = false;\n\n constructor(options?: CcPromptWebpackOptions) {\n this.options = options || {};\n }\n\n apply(compiler: any): void {\n const isDev = this.options.dev !== undefined\n ? this.options.dev\n : process.env.NODE_ENV !== 'production';\n\n // Only activate in dev mode\n if (!isDev) return;\n\n const startPort = this.options.port || 3456;\n const clientEntryPath = join(_dirname, 'client-entry.js');\n\n // ── 1. Start sidecar server (once per plugin instance) ──\n if (!this.sidecarStarted) {\n this.sidecarStarted = true;\n const projectRoot = this.options.root || process.cwd();\n this.sidecarServer = startSidecar(projectRoot, { startPort });\n\n // Sidecar port will be logged by startSidecar itself\n }\n\n // Register cleanup hooks\n compiler.hooks.thisCompilation.tap('CcPromptWebpackPlugin', () => {\n // Ensure cleanup on process exit\n if (!this.cleanedUp) {\n this.setupCleanup();\n }\n });\n\n // ── 2. Add code-inspector-plugin ──\n if (this.options.inspector !== false) {\n const inspectorPlugin = codeInspectorPlugin({\n bundler: 'webpack',\n behavior: {\n locate: false,\n copy: false,\n },\n hideDomPathAttr: true,\n hideConsole: true,\n });\n // codeInspectorPlugin returns a webpack plugin instance\n if (inspectorPlugin && typeof inspectorPlugin.apply === 'function') {\n inspectorPlugin.apply(compiler);\n } else if (Array.isArray(inspectorPlugin)) {\n // Some versions return an array\n for (const p of inspectorPlugin) {\n if (p && typeof p.apply === 'function') p.apply(compiler);\n }\n }\n }\n\n // ── 3. Inject client script via DefinePlugin ──\n const webpack = require('webpack');\n const injectScript = getInjectScript();\n\n new webpack.DefinePlugin({\n '__CC_PROMPTER_INJECT_SCRIPT__': JSON.stringify(injectScript),\n '__CC_PROMPTER_PORT__': JSON.stringify(startPort),\n }).apply(compiler);\n\n // ── 4. Prepend client-entry.js to all entries ──\n const originalEntry = compiler.options.entry;\n compiler.options.entry = async () => {\n const entries: Record<string, any> = typeof originalEntry === 'function'\n ? await originalEntry()\n : originalEntry;\n\n // Handle both object entries ({ name: [...] }) and string/array entries\n if (typeof entries === 'string') {\n return { main: [clientEntryPath, entries] };\n }\n if (Array.isArray(entries)) {\n return { main: [clientEntryPath, ...entries] };\n }\n if (typeof entries === 'object') {\n for (const key in entries) {\n if (Array.isArray(entries[key])) {\n entries[key].unshift(clientEntryPath);\n } else if (typeof entries[key] === 'string') {\n entries[key] = [clientEntryPath, entries[key]];\n }\n }\n }\n return entries;\n };\n }\n\n private setupCleanup(): void {\n const cleanup = () => {\n if (this.cleanedUp) return;\n this.cleanedUp = true;\n if (this.sidecarServer) {\n this.sidecarServer.close();\n this.sidecarServer = null;\n }\n };\n process.on('SIGTERM', () => { cleanup(); process.exit(0); });\n process.on('SIGINT', () => { cleanup(); process.exit(0); });\n process.on('exit', cleanup);\n }\n}\n","/**\n * CC Prompter — Sidecar API Server\n *\n * Express server 运行在端口 3456,管理 PTY session 生命周期。\n * 提供 REST API + SSE 流式响应。\n */\n\nimport express from 'express';\nimport { createServer, type Server } from 'http';\nimport { PtySession } from './pty-session.js';\nimport { getPanelHtml } from './assets.js';\nimport type {\n SessionInfo,\n CreateSessionRequest,\n SendMessageRequest,\n SendCommandRequest,\n SseEvent,\n} from './types.js';\n\n// ── Session Manager ─────────────────────────────────────\n\nclass SessionManager {\n private sessions = new Map<string, PtySession>();\n private counter = 0;\n\n async create(cwd: string): Promise<PtySession> {\n const id = `s${++this.counter}-${Date.now().toString(36)}`;\n const session = new PtySession(id, cwd);\n this.sessions.set(id, session);\n\n // Clean up on exit\n session.on('exit', () => {\n // Keep in map for history, but mark exited\n });\n\n await session.spawn();\n return session;\n }\n\n get(id: string): PtySession | undefined {\n return this.sessions.get(id);\n }\n\n list(): SessionInfo[] {\n return Array.from(this.sessions.values()).map(s => {\n const info = s.getInfo();\n return {\n id: info.id,\n title: info.title,\n status: info.status,\n createdAt: info.createdAt,\n lastActivityAt: info.lastActivityAt,\n messageCount: info.messageCount,\n lastMessagePreview: info.lastMessagePreview,\n };\n });\n }\n\n destroy(id: string): boolean {\n const session = this.sessions.get(id);\n if (!session) return false;\n session.kill();\n this.sessions.delete(id);\n return true;\n }\n\n destroyAll(): void {\n for (const session of this.sessions.values()) {\n session.kill();\n }\n this.sessions.clear();\n }\n}\n\n// ── Sidecar Server ──────────────────────────────────────\n\nexport interface SidecarOptions {\n startPort?: number;\n}\n\nexport function startSidecar(projectRoot: string, options?: SidecarOptions): Server {\n const startPort = options?.startPort || 3456;\n const app = express();\n app.use(express.json());\n\n const manager = new SessionManager();\n\n // ── CORS for iframe ──\n app.use((req, res, next) => {\n res.header('Access-Control-Allow-Origin', '*');\n res.header('Access-Control-Allow-Methods', 'GET, POST, DELETE, OPTIONS');\n res.header('Access-Control-Allow-Headers', 'Content-Type');\n if (req.method === 'OPTIONS') {\n res.sendStatus(204);\n return;\n }\n next();\n });\n\n // ── Panel HTML (served to iframe) ──\n app.get('/__panel/', (_req, res) => {\n const html = getPanelHtml();\n res.setHeader('Content-Type', 'text/html; charset=utf-8');\n res.setHeader('Content-Length', Buffer.byteLength(html));\n res.end(html);\n });\n\n // ── Panel favicon (no-op) ──\n app.get('/favicon.ico', (_req, res) => {\n res.sendStatus(204);\n });\n\n // ── List sessions ──\n app.get('/api/sessions', (_req, res) => {\n res.json(manager.list());\n });\n\n // ── Create session ──\n app.post<Record<string, string>, any, CreateSessionRequest>('/api/sessions', async (req, res) => {\n try {\n const cwd = req.body?.cwd || projectRoot;\n const session = await manager.create(cwd);\n res.json(session.getInfo());\n } catch (err: any) {\n console.error('[cc-prompter] Failed to create session:', err);\n res.status(500).json({ error: err.message, stack: err.stack });\n }\n });\n\n // ── Send message (SSE stream) ──\n app.post<Record<string, string>, any, SendMessageRequest>(\n '/api/sessions/:id/message',\n async (req, res) => {\n const session = manager.get(req.params.id);\n if (!session) {\n res.status(404).json({ error: 'Session not found' });\n return;\n }\n if (session.status === 'exited') {\n res.status(410).json({ error: 'Session exited' });\n return;\n }\n if (session.status === 'busy') {\n res.status(409).json({ error: 'Session busy' });\n return;\n }\n\n const { content, sourceInfo } = req.body;\n if (!content) {\n res.status(400).json({ error: 'Missing content' });\n return;\n }\n\n // Build prompt with optional source context (single-line to avoid multi-line input mode)\n let prompt = content;\n if (sourceInfo) {\n const relPath = sourceInfo.path;\n const parts = [\n `[source: ${relPath}:${sourceInfo.line}:${sourceInfo.column}]`,\n ];\n if (sourceInfo.elementInfo) {\n parts.push(`[element: ${sourceInfo.elementInfo}]`);\n }\n prompt = parts.join(' ') + ' ' + content;\n }\n\n // SSE headers\n res.setHeader('Content-Type', 'text/event-stream');\n res.setHeader('Cache-Control', 'no-cache');\n res.setHeader('Connection', 'keep-alive');\n res.setHeader('X-Accel-Buffering', 'no');\n res.flushHeaders();\n\n // Forward session events as SSE\n const onMessage = (evt: SseEvent) => {\n res.write(`data: ${JSON.stringify(evt)}\\n\\n`);\n\n // Stop streaming on 'done'\n if (evt.type === 'done') {\n cleanup();\n }\n };\n\n const onError = (err: Error) => {\n res.write(`data: ${JSON.stringify({ type: 'error', content: err.message })}\\n\\n`);\n cleanup();\n };\n\n const cleanup = () => {\n if (cleanedUp) return;\n cleanedUp = true;\n session.removeListener('message', onMessage);\n session.removeListener('error', onError);\n res.end();\n };\n\n session.on('message', onMessage);\n session.on('error', onError);\n\n // Client disconnect — delay registration to avoid premature close\n // (Express/Node HTTP can fire 'close' early on SSE connections)\n let cleanedUp = false;\n setTimeout(() => {\n req.on('close', () => {\n if (!cleanedUp) {\n cleanup();\n }\n });\n }, 3000);\n\n // Send to PTY\n try {\n await session.sendMessage(prompt);\n } catch (err: any) {\n res.write(`data: ${JSON.stringify({ type: 'error', content: err.message })}\\n\\n`);\n cleanup();\n }\n },\n );\n\n // ── Send command ──\n app.post<Record<string, string>, any, SendCommandRequest>(\n '/api/sessions/:id/command',\n (req, res) => {\n const session = manager.get(req.params.id);\n if (!session) {\n res.status(404).json({ error: 'Session not found' });\n return;\n }\n\n const { command } = req.body;\n if (!command) {\n res.status(400).json({ error: 'Missing command' });\n return;\n }\n\n try {\n session.sendCommand(command);\n res.json({ ok: true });\n } catch (err: any) {\n res.status(500).json({ error: err.message });\n }\n },\n );\n\n // ── Interrupt session (Escape key) ──\n app.post('/api/sessions/:id/interrupt', (req, res) => {\n const session = manager.get(req.params.id);\n if (!session) {\n res.status(404).json({ error: 'Session not found' });\n return;\n }\n try {\n session.interrupt();\n res.json({ ok: true });\n } catch (err: any) {\n res.status(500).json({ error: err.message });\n }\n });\n\n // ── Delete session ──\n app.delete('/api/sessions/:id', (req, res) => {\n if (manager.destroy(req.params.id)) {\n res.json({ ok: true });\n } else {\n res.status(404).json({ error: 'Session not found' });\n }\n });\n\n // ── Session history ──\n app.get('/api/sessions/:id/history', (req, res) => {\n const session = manager.get(req.params.id);\n if (!session) {\n res.status(404).json({ error: 'Session not found' });\n return;\n }\n res.json(session.getHistory());\n });\n\n const server = createServer(app);\n let actualPort = startPort;\n\n // ── Port discovery endpoint (used by inject.js for Next.js and other setups) ──\n app.get('/__cc-port', (_req, res) => {\n const addr = server.address();\n const port = addr && typeof addr === 'object' ? addr.port : actualPort;\n res.setHeader('Access-Control-Allow-Origin', '*');\n res.end(String(port));\n });\n\n const MAX_PORT = startPort + 10;\n\n function tryListen(port: number): Promise<Server> {\n return new Promise((resolve, reject) => {\n server.listen(port, () => {\n actualPort = port;\n console.log(`[cc-prompter] Sidecar running on http://localhost:${port}`);\n resolve(server);\n });\n server.on('error', (err: any) => {\n if (err.code === 'EADDRINUSE' && port < MAX_PORT) {\n console.log(`[cc-prompter] Port ${port} in use, trying ${port + 1}...`);\n tryListen(port + 1).then(resolve, reject);\n } else {\n reject(err);\n }\n });\n });\n }\n\n // Fire-and-forget listen (returns server immediately for API compat)\n tryListen(startPort).catch((err) => {\n console.error(`[cc-prompter] Failed to start sidecar:`, err.message);\n });\n\n // Graceful shutdown\n server.on('close', () => {\n manager.destroyAll();\n });\n\n return server;\n}\n","/**\n * CC Prompter — PTY Session\n *\n * 每个实例管理一个常驻的 claude CLI 进程(通过 node-pty)。\n *\n * 输出解析策略(双通道):\n * 1. PTY 输出解析(主要)— 实时从 TUI 输出提取响应文本\n * 2. JSONL transcript(辅助)— 结构化事件,用于 tool_use 等\n *\n * 就绪检测:解析 PTY 输出中的提示符(\"for shortcuts\"、\"/effort\")。\n */\n\nimport { createRequire } from 'module';\nimport { fileURLToPath } from 'url';\nimport { dirname } from 'path';\nconst _metaUrl = typeof __filename !== 'undefined' ? __filename : fileURLToPath(import.meta.url);\nconst require = createRequire(_metaUrl);\nimport { EventEmitter } from 'events';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as os from 'os';\nimport type { IPty } from 'node-pty-prebuilt-multiarch';\nimport type {\n SessionStatus,\n ChatMessage,\n ToolUseInfo,\n JsonlEvent,\n SseEvent,\n} from './types.js';\n\n// Try multiple PTY packages for cross-platform compatibility\nconst PTY_PACKAGES = [\n 'node-pty-prebuilt-multiarch', // macOS / Linux prebuilt\n '@homebridge/node-pty-prebuilt-multiarch', // Better Windows support\n 'node-pty', // Original (needs build tools)\n];\n\nlet _ptyModule: any = null;\nfunction loadPty(): any {\n if (_ptyModule) return _ptyModule;\n const errors: string[] = [];\n for (const pkg of PTY_PACKAGES) {\n try {\n const mod = require(pkg);\n // Verify native binary actually exists — require() can succeed without it\n const modDir = path.dirname(require.resolve(pkg + '/package.json'));\n const buildDir = path.join(modDir, 'build', 'Release');\n if (!fs.existsSync(buildDir) || fs.readdirSync(buildDir).filter(f => f.endsWith('.node')).length === 0) {\n errors.push(`${pkg}: no native binary in ${buildDir}`);\n continue;\n }\n console.log(`[cc-prompter] Loaded PTY from: ${pkg}`);\n _ptyModule = mod;\n return _ptyModule;\n } catch (err: any) {\n errors.push(`${pkg}: ${err.message}`);\n }\n }\n throw new Error(\n `No PTY module available. Tried:\\n${errors.map(e => ' ' + e).join('\\n')}\\n` +\n `Install one: npm install node-pty-prebuilt-multiarch (macOS/Linux) or @homebridge/node-pty-prebuilt-multiarch (Windows)`\n );\n}\n\n// ── Helpers ─────────────────────────────────────────────\n\nfunction resolveClaudeBin(cwd: string): { file: string; args: string[] } {\n // Windows: find node.exe + claude.js directly (bypass broken .cmd wrapper)\n if (process.platform === 'win32') {\n // Check local install first\n const localJs = path.resolve(cwd, 'node_modules/@anthropic-ai/claude-code/bin/claude.js');\n if (fs.existsSync(localJs)) {\n return { file: process.execPath, args: [localJs] };\n }\n // Check global npm install (nvm4w puts global modules next to node.exe)\n const globalPrefix = path.dirname(process.execPath);\n const globalJs = path.join(globalPrefix, 'node_modules/@anthropic-ai/claude-code/bin/claude.js');\n if (fs.existsSync(globalJs)) {\n return { file: process.execPath, args: [globalJs] };\n }\n // Check npm global prefix via APPDATA (standard npm location)\n const appDataJs = path.join(process.env.APPDATA || '', 'npm/node_modules/@anthropic-ai/claude-code/bin/claude.js');\n if (fs.existsSync(appDataJs)) {\n return { file: process.execPath, args: [appDataJs] };\n }\n // Fallback: try cmd.exe\n return { file: process.env.COMSPEC || 'cmd.exe', args: ['/c', 'claude'] };\n }\n\n // macOS/Linux\n const local = path.resolve(cwd, 'node_modules/@anthropic-ai/claude-code/bin/claude');\n if (fs.existsSync(local)) return { file: local, args: [] };\n return { file: 'claude', args: [] };\n}\n\nfunction findClaudeProjectsDir(): string {\n return path.join(os.homedir(), '.claude', 'projects');\n}\n\n/** Convert a cwd path to the Claude projects directory name */\nfunction cwdToProjectDir(cwd: string): string {\n // Normalize path separators and handle both Unix and Windows paths\n // D:/code/agentplat → -D--code-agentplat\n // /Users/ryan/demo → -Users-ryan-demo\n const normalized = cwd.replace(/\\\\/g, '/').replace(/^[A-Za-z]:/, m => '-' + m[0].toLowerCase());\n return normalized.replace(/^\\//, '').replace(/\\/+/g, '-').replace(/^-+/, '');\n}\n\n/** Scan for the most recently modified .jsonl in project dirs */\nfunction findRecentJsonl(cwd: string, afterMs: number): string | null {\n const projectsDir = findClaudeProjectsDir();\n if (!fs.existsSync(projectsDir)) return null;\n\n // Collect candidate JSONL files from target dir and all subdirectories\n const candidates: { path: string; mtime: number }[] = [];\n\n const collectFromDir = (dir: string) => {\n try {\n const files = fs.readdirSync(dir).filter(f => f.endsWith('.jsonl'));\n for (const f of files) {\n const fp = path.join(dir, f);\n try {\n const stat = fs.statSync(fp);\n if (stat.mtimeMs > afterMs) {\n candidates.push({ path: fp, mtime: stat.mtimeMs });\n }\n } catch { /* skip */ }\n }\n } catch { /* dir might not exist */ }\n };\n\n // Try exact match first\n const projectSubdir = cwdToProjectDir(cwd);\n const targetDir = path.join(projectsDir, projectSubdir);\n collectFromDir(targetDir);\n\n // Fallback: scan ALL project subdirectories (handles Windows path format differences)\n if (candidates.length === 0) {\n try {\n const entries = fs.readdirSync(projectsDir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.isDirectory() && entry.name !== projectSubdir) {\n collectFromDir(path.join(projectsDir, entry.name));\n }\n }\n } catch { /* ignore */ }\n }\n\n if (candidates.length === 0) return null;\n candidates.sort((a, b) => b.mtime - a.mtime);\n return candidates[0].path;\n}\n\nfunction sessionIdFromJsonlPath(jsonPath: string): string | null {\n const base = path.basename(jsonPath, '.jsonl');\n const match = base.match(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/);\n return match ? match[0] : null;\n}\n\n/** Strip ANSI escape sequences for analysis */\nfunction stripAnsi(s: string): string {\n return s\n .replace(/\\x1b\\[[0-9;]*[a-zA-Z]/g, '')\n .replace(/\\x1b\\].*?(?:\\x07|\\x1b\\\\)/g, '')\n .replace(/\\x1b\\[[\\?]?[0-9;]*[a-zA-Z]/g, '')\n .replace(/\\x1b\\[[0-9;]*m/g, '')\n .replace(/\\x1b\\[[0-9;]*[a-zA-Z]/g, '')\n .replace(/\\x1b[^[\\]()]?.?/g, '')\n .replace(/\\r/g, '');\n}\n\n/** Strip Claude TUI spinner noise from PTY output */\nfunction stripSpinner(s: string): string {\n return s\n .replace(/[✻✶✽✢·●✳◇◆▸▹⏵⏶]+/g, '')\n .replace(/\\w{3,}ing[…\\s]*\\(\\d{1,3}s?\\)?/g, '') // \"Gesticulating… (28s)\"\n .replace(/\\w{3,}ing…/g, '') // \"Topsy-turvying…\"\n .replace(/\\s{2,}/g, ' ')\n .trim();\n}\n\n// ── PtySession ──────────────────────────────────────────\n\nexport class PtySession extends EventEmitter {\n readonly id: string;\n readonly cwd: string;\n status: SessionStatus = 'spawning';\n\n private pty: IPty | null = null;\n private jsonlPath: string | null = null;\n private sessionId: string | null = null;\n private history: ChatMessage[] = [];\n private jsonlOffset = 0;\n private jsonlWatcher: fs.FSWatcher | null = null;\n private spawnTime: number;\n private messageSentAt = 0;\n private busySince = 0; // timestamp when last message was sent (for grace period)\n private title = 'New Session';\n private lastActivityAt: number;\n private killed = false;\n private ptyBuffer = ''; // accumulated for prompt detection\n private jsonlDiscoverPromise: Promise<void> | null = null;\n\n // ── PTY streaming fields ──\n private busyBuffer = ''; // accumulated during busy state\n private lastUserContent = ''; // last user message text\n private ptyResponseText = ''; // extracted response text so far\n private ptyResponseEmitted = 0; // chars already emitted\n private usedJsonl = false; // JSONL events received this turn\n private ptyDoneEmitted = false;\n private lastProgress = ''; // last emitted progress text\n private interrupted = false; // set when user sends interrupt\n private lastSpinnerSec = 0; // highest spinner seconds counter seen\n private lastSpinnerAt = 0; // timestamp when spinner was last active\n private emittedTools = new Set<string>(); // dedup tool call emissions\n\n constructor(id: string, cwd: string) {\n super();\n this.id = id;\n this.cwd = cwd;\n this.spawnTime = Date.now();\n this.lastActivityAt = this.spawnTime;\n }\n\n /** Spawn the claude process via PTY */\n async spawn(): Promise<void> {\n const ptyModule = loadPty();\n const { file, args } = resolveClaudeBin(this.cwd);\n\n console.log(`[pty-session ${this.id}] spawning: ${file} ${args.join(' ')} cwd: ${this.cwd}`);\n\n this.pty = ptyModule.spawn(file, args, {\n name: 'xterm-256color',\n cols: 120,\n rows: 30,\n cwd: this.cwd,\n env: { ...process.env } as Record<string, string>,\n });\n\n console.log(`[pty-session ${this.id}] PID: ${this.pty.pid}`);\n\n // Watch PTY output\n this.pty.onData((data: string) => {\n // Debug: log first 500 chars of output to diagnose spawn failures\n if (this.status === 'spawning') {\n console.log(`[pty-session ${this.id}] output: ${JSON.stringify(data.substring(0, 500))}`);\n }\n const clean = stripAnsi(data);\n this.ptyBuffer += clean;\n\n this.detectPrompt();\n\n // Parse for streaming response when busy and JSONL not active\n if (this.status === 'busy' && !this.usedJsonl) {\n this.busyBuffer += clean;\n this.parseBusyOutput();\n }\n });\n\n this.pty.onExit(({ exitCode }) => {\n console.log(`[pty-session ${this.id}] exited with code: ${exitCode}`);\n this.status = 'exited';\n this.lastActivityAt = Date.now();\n this.emit('exit', exitCode);\n this.cleanup();\n });\n }\n\n // ── Prompt Detection ──────────────────────────────────\n\n private detectPrompt(): void {\n const indicators = [\n /for shortcuts/,\n /\\/effort/,\n /refactor/,\n ];\n\n for (const re of indicators) {\n if (re.test(this.ptyBuffer) && this.status === 'spawning') {\n console.log(`[pty-session ${this.id}] detected prompt → ready`);\n this.status = 'ready';\n this.emit('ready');\n return;\n }\n }\n\n // After interrupt, detect prompt returning to finish the stream\n if (this.interrupted && this.status === 'busy') {\n for (const re of indicators) {\n if (re.test(this.ptyBuffer)) {\n console.log(`[pty-session ${this.id}] detected prompt after interrupt → done`);\n this.interrupted = false;\n this.ptyDoneEmitted = true;\n this.status = 'ready';\n this.lastActivityAt = Date.now();\n this.emit('message', { type: 'done', durationMs: 0 } as SseEvent);\n return;\n }\n }\n }\n }\n\n private async waitUntilReady(timeoutMs = 30_000): Promise<void> {\n if (this.status === 'ready') return;\n if (this.status === 'exited') throw new Error('Session exited');\n\n return new Promise((resolve, reject) => {\n const deadline = Date.now() + timeoutMs;\n const timer = setInterval(() => {\n if (this.status === 'ready') {\n clearInterval(timer);\n resolve();\n } else if (this.status === 'exited') {\n clearInterval(timer);\n reject(new Error('Session exited while waiting'));\n } else if (Date.now() > deadline) {\n clearInterval(timer);\n reject(new Error('Timeout waiting for session to be ready'));\n }\n }, 100);\n });\n }\n\n // ── Send Message ──────────────────────────────────────\n\n async sendMessage(content: string): Promise<void> {\n if (!this.pty || this.status === 'exited') {\n throw new Error('Session not active');\n }\n if (this.status === 'busy') {\n throw new Error('Session busy');\n }\n\n // Wait for claude prompt to be ready\n if (this.status !== 'ready') {\n console.log(`[pty-session ${this.id}] waiting for prompt before sending message...`);\n await this.waitUntilReady();\n }\n\n await new Promise(r => setTimeout(r, 200));\n\n this.status = 'busy';\n this.lastActivityAt = Date.now();\n this.busySince = Date.now();\n\n // Reset streaming state for this turn\n this.busyBuffer = '';\n this.ptyBuffer = ''; // Clear accumulated prompt text to avoid false done detection\n this.lastUserContent = content;\n this.ptyResponseText = '';\n this.ptyResponseEmitted = 0;\n this.usedJsonl = false;\n this.ptyDoneEmitted = false;\n this.lastProgress = '';\n this.interrupted = false;\n this.lastSpinnerSec = 0;\n this.lastSpinnerAt = 0;\n this.emittedTools.clear();\n\n // JSONL discovery in background\n if (!this.messageSentAt) {\n this.messageSentAt = Date.now();\n console.log(`[pty-session ${this.id}] first message, starting JSONL discovery`);\n this.jsonlDiscoverPromise = this.discoverJsonl();\n }\n\n console.log(`[pty-session ${this.id}] writing to PTY: ${JSON.stringify(content.slice(0, 100))}`);\n\n // Write content + double Enter for reliable submission\n this.pty.write(content + '\\r');\n await new Promise(r => setTimeout(r, 150));\n this.pty.write('\\r');\n }\n\n /** Send a slash command to the PTY */\n sendCommand(command: string): void {\n if (!this.pty || this.status === 'exited') {\n throw new Error('Session not active');\n }\n\n this.pty.write(command + '\\r');\n\n if (command === '/new') {\n this.history = [];\n this.title = 'New Session';\n this.jsonlPath = null;\n this.jsonlOffset = 0;\n this.jsonlWatcher?.close();\n this.jsonlWatcher = null;\n this.sessionId = null;\n this.messageSentAt = 0;\n this.status = 'ready';\n this.ptyBuffer = '';\n }\n }\n\n /** Send Escape to PTY to interrupt current generation */\n interrupt(): void {\n if (!this.pty || this.status === 'exited') {\n throw new Error('Session not active');\n }\n if (this.status !== 'busy') return;\n this.interrupted = true;\n this.pty.write('\\x1b');\n\n // Safety timeout: if prompt detection fails, force finish after 5s\n setTimeout(() => {\n if (this.interrupted && this.status === 'busy') {\n console.log(`[pty-session ${this.id}] interrupt timeout → force done`);\n this.interrupted = false;\n this.ptyDoneEmitted = true;\n this.status = 'ready';\n this.lastActivityAt = Date.now();\n this.emit('message', { type: 'done', durationMs: 0 } as SseEvent);\n }\n }, 5000);\n }\n\n // ── PTY Output Parsing (streaming fallback) ───────────\n\n /**\n * Parse PTY output during busy state to extract streaming response.\n *\n * Claude Code TUI patterns:\n * - Spinner frames: ✳ ✶ ✻ ✽ ✢ · (ignore — just animation)\n * - Response text: ⏺<text> or ●<text>\n * - Tool use: ⚡<tool_name> or ✢ editing <file>\n * - Completion: \"Brewed for Xs\" (ONLY reliable indicator)\n * - ⚠️ ❯ appears in input echo too — NOT a completion signal!\n * - Timing: (Xs · ↓NNN tokens)\n */\n private parseBusyOutput(): void {\n // ── 0. Sliding window — prevent unbounded buffer growth from spinner frames ──\n // Windows ConPTY sends character-by-character spinner updates, causing massive buffers.\n // Keep only the last 2000 chars so completion markers and recent tool calls stay visible.\n if (this.busyBuffer.length > 3000) {\n this.busyBuffer = this.busyBuffer.slice(-2000);\n }\n\n // ── 1. Extract progress for UI feedback ──\n this.emitProgress();\n\n // ── 2. Track spinner activity (detect Claude still working) ──\n // Extract seconds counter from spinner text: \"Gesticulating… (28s)\", \"Seasoning… (21s)\"\n // On Windows, these verbs are random (Gesticulating, Seasoning, Topsy-turvying, etc.)\n const secMatches = [...this.busyBuffer.matchAll(/\\w{3,}ing[…\\s]*\\((\\d{1,3})s?/g)];\n for (const m of secMatches) {\n const sec = parseInt(m[1]);\n if (sec > this.lastSpinnerSec) {\n this.lastSpinnerSec = sec;\n this.lastSpinnerAt = Date.now();\n }\n }\n\n // ── 3. Try to extract response text ──\n const respMatch = this.busyBuffer.match(/⏺([一-鿿 -〿-].+)/s);\n if (respMatch) {\n let raw = respMatch[1];\n raw = raw.replace(/[✳✶✻✽✢·].*$/s, '').trim();\n raw = raw.replace(/─{3,}.*$/s, '').trim();\n raw = raw.replace(/\\w{3,}ed (?:for|in) \\d{1,4}s?.*$/s, '').trim();\n raw = raw.replace(/esctointerrupt.*$/s, '').trim();\n\n if (raw.length > this.ptyResponseText.length) {\n this.ptyResponseText = raw;\n this.emitIncrementalText();\n }\n }\n\n // ── 4. Extract tool calls (with dedup to prevent infinite re-emission) ──\n // macOS format: ⏺ Read(file) | Windows format: ● Reading 1 file… ⎿ file\n const toolCallMatch = this.busyBuffer.match(/⏺(Update|Read|Edit|Write|Bash)\\(([^)]+)\\)/);\n if (toolCallMatch) {\n const sig = `${toolCallMatch[1]}:${toolCallMatch[2]}`;\n if (!this.emittedTools.has(sig)) {\n this.emittedTools.add(sig);\n this.emit('message', {\n type: 'assistant_tool',\n tool: { name: toolCallMatch[1], input: { file: toolCallMatch[2] } },\n } as SseEvent);\n }\n }\n // Windows format: \"● Reading 1 file…\\n ⎿ src\\\\components\\\\Foo.tsx\"\n const winToolMatch = this.busyBuffer.match(/● (Reading|Editing|Writing|Searching|Bashing)[^\\n]*\\n\\s*⎿\\s*(.+)/);\n if (!toolCallMatch && winToolMatch) {\n const filePath = winToolMatch[2].trim();\n const sig = `${winToolMatch[1]}:${filePath}`;\n if (!this.emittedTools.has(sig)) {\n this.emittedTools.add(sig);\n this.emit('message', {\n type: 'assistant_tool',\n tool: { name: winToolMatch[1], input: { file: filePath } },\n } as SseEvent);\n }\n }\n\n // ── 5. Detect completion ──\n if (this.ptyDoneEmitted) return;\n\n // 5a. Explicit completion marker: \"Brewed for Xs\", \"Sautéed for Xs\", etc.\n // Use broad pattern since Claude uses random creative verbs.\n const cleanBuf = stripSpinner(this.busyBuffer);\n const hasDoneMarker = /\\b\\w+ed (?:for|in) \\d{1,4}s?\\b/i.test(cleanBuf);\n\n // 5b. Spinner timeout: spinner was active, then stopped for 10+ seconds.\n // On Windows ConPTY, Claude's TUI sends spinner frames continuously while working.\n // If spinner stops, Claude has finished (or errored out).\n const spinnerTimeout = this.lastSpinnerAt > 0\n && Date.now() - this.lastSpinnerAt > 10000\n && this.ptyResponseEmitted > 0;\n\n if (hasDoneMarker || spinnerTimeout) {\n const reason = hasDoneMarker\n ? 'completion marker'\n : `spinner timeout (${Math.round((Date.now() - this.lastSpinnerAt) / 1000)}s since last activity)`;\n console.log(`[pty-session ${this.id}] detected done via ${reason}`);\n this.ptyDoneEmitted = true;\n\n // Final flush: emit any remaining text\n if (this.ptyResponseText.length > this.ptyResponseEmitted) {\n this.emitIncrementalText();\n }\n\n // If no response was emitted at all, try one more aggressive extraction\n if (this.ptyResponseEmitted === 0) {\n const finalMatch = this.busyBuffer.match(/⏺(.+)/s);\n if (finalMatch) {\n let text = finalMatch[1]\n .replace(/[✳✶✻✽✢·].*$/s, '')\n .replace(/─{3,}.*$/s, '')\n .replace(/\\w{3,}ed (?:for|in) \\d{1,4}s?.*$/s, '')\n .replace(/esctointerrupt.*$/s, '')\n .trim();\n if (text.length > 0) {\n this.emitUserIfNeeded();\n this.history.push({\n role: 'assistant', content: text, timestamp: Date.now(),\n });\n this.emit('message', { type: 'assistant_text', content: text } as SseEvent);\n this.ptyResponseEmitted = text.length;\n }\n }\n }\n\n // Extract duration\n const durMatch = cleanBuf.match(/\\w+ed (?:for|in) (\\d{1,4})s?/i);\n const durationMs = durMatch ? parseInt(durMatch[1]) * 1000 : 0;\n\n // Update title from first user message\n if (this.history.filter(m => m.role === 'user').length <= 1 && this.lastUserContent) {\n this.title = this.lastUserContent.slice(0, 60);\n this.emit('title-change', this.title);\n }\n\n this.status = 'ready';\n this.lastActivityAt = Date.now();\n this.emit('message', { type: 'done', durationMs } as SseEvent);\n }\n }\n\n /** Emit only the newly arrived characters (incremental streaming) */\n private emitIncrementalText(): void {\n const newText = this.ptyResponseText.slice(this.ptyResponseEmitted);\n if (newText.length === 0) return;\n\n // First chunk → emit user message + start assistant\n if (this.ptyResponseEmitted === 0) {\n this.emitUserIfNeeded();\n }\n\n this.ptyResponseEmitted = this.ptyResponseText.length;\n this.emit('message', { type: 'assistant_text', content: newText } as SseEvent);\n }\n\n /**\n * Extract and emit progress updates from busyBuffer.\n *\n * Parses PTY output for Claude Code's progress indicators:\n * - \"Thinking for Xs, reading N files\"\n * - \"Thought for Xs, read N files\"\n * - \"Crafting… (Xs · ↓NN tokens)\"\n * - \"Update(file)\" / \"Read(file)\"\n * - \"⎿ Removed N lines\"\n * - \"(Xs · ↓NN tokens)\" timing\n */\n private emitProgress(): void {\n // Strip spinner chars + noise, collapse whitespace\n const text = this.busyBuffer\n .replace(/[✳✶✻✽✢·][a-zA-Z0-9…]{0,4}/g, '')\n .replace(/\\s+/g, ' ');\n\n // Ordered by specificity — last match wins (most recent progress)\n const patterns: [RegExp, (m: RegExpMatchArray) => string][] = [\n // Thinking phase\n [/Thinking for (\\d+s)[^─]{0,60}(reading \\d+ file[^)]*)?/, (m) => {\n return m[0].replace(/\\s+/g, ' ').replace(/\\s*\\(ctrl.*$/, '').trim();\n }],\n // Thought completed\n [/Thought for (\\d+s)[^─]{0,60}(read \\d+ file[^)]*)?/, (m) => {\n return m[0].replace(/\\s+/g, ' ').replace(/\\s*\\(ctrl.*$/, '').trim();\n }],\n // Tool call: Update(file) / Read(file)\n [/⏺(Update|Read|Edit|Write|Bash)\\(([^)]+)\\)/, (m) => {\n return m[1] + ': ' + m[2].split('/').slice(-2).join('/');\n }],\n // Tool result: ⎿ Removed N lines\n [/⎿\\s*(Removed|Added|Modified|Created)\\s+(\\d+)\\s+(lines?)/, (m) => {\n return m[1] + ' ' + m[2] + ' ' + m[3];\n }],\n // Crafting with timing\n [/Crafting[^─]{0,30}\\(\\d+s[^)]*\\)/, (m) => {\n return m[0].replace(/\\s+/g, ' ').trim();\n }],\n // Simple timing: (5s · ↓9 tokens)\n [/\\((\\d+s)\\s*·\\s*[↓↑]\\s*(\\d+)\\s*tokens?\\)/, (m) => {\n return m[1] + ' · ' + m[2] + ' tokens';\n }],\n ];\n\n // Find the last matching pattern\n let progress = '';\n for (const [re, fn] of patterns) {\n const m = text.match(re);\n if (m) progress = fn(m);\n }\n\n // Emit only if changed\n if (progress && progress !== this.lastProgress) {\n this.lastProgress = progress;\n this.emit('message', { type: 'progress', content: progress } as SseEvent);\n }\n }\n\n /** Emit user message event (only if not already emitted this turn) */\n private emitUserIfNeeded(): void {\n if (!this.lastUserContent) return;\n // Check if user message already in history\n const already = this.history.some(\n m => m.role === 'user' && m.content === this.lastUserContent,\n );\n if (!already) {\n this.history.push({\n role: 'user',\n content: this.lastUserContent,\n timestamp: Date.now(),\n });\n this.emit('message', { type: 'user', content: this.lastUserContent } as SseEvent);\n }\n }\n\n // ── JSONL Discovery & Parsing (structured events) ─────\n\n private async discoverJsonl(): Promise<void> {\n const searchStart = this.messageSentAt - 2000;\n const projectsDir = findClaudeProjectsDir();\n const expectedSubdir = cwdToProjectDir(this.cwd);\n console.log(`[pty-session ${this.id}] JSONL discovery: projectsDir=${projectsDir}, expected=${expectedSubdir}, cwd=${this.cwd}`);\n\n // Poll for up to 60 seconds (120 × 500ms)\n for (let i = 0; i < 120; i++) {\n if (this.killed) return;\n const jsonl = findRecentJsonl(this.cwd, searchStart);\n if (jsonl) {\n this.jsonlPath = jsonl;\n this.sessionId = sessionIdFromJsonlPath(jsonl) || null;\n console.log(`[pty-session ${this.id}] found JSONL: ${jsonl} (session: ${this.sessionId})`);\n this.startTailingJsonl();\n return;\n }\n // Log available dirs after 5s for debugging\n if (i === 10) {\n try {\n if (fs.existsSync(projectsDir)) {\n const dirs = fs.readdirSync(projectsDir, { withFileTypes: true })\n .filter(d => d.isDirectory())\n .map(d => d.name);\n console.log(`[pty-session ${this.id}] JSONL not found in expected dir. Available project dirs: ${dirs.join(', ')}`);\n } else {\n console.log(`[pty-session ${this.id}] projectsDir does not exist: ${projectsDir}`);\n }\n } catch { /* ignore */ }\n }\n await new Promise(r => setTimeout(r, 500));\n }\n console.warn(`[pty-session ${this.id}] JSONL not found after 60s — using PTY output parsing`);\n }\n\n private startTailingJsonl(): void {\n if (!this.jsonlPath) return;\n\n this.readNewJsonlLines();\n\n try {\n this.jsonlWatcher = fs.watch(\n path.dirname(this.jsonlPath),\n (eventType, filename) => {\n if (filename === path.basename(this.jsonlPath!)) {\n this.readNewJsonlLines();\n }\n },\n );\n } catch (err) {\n console.warn(`[pty-session ${this.id}] fs.watch failed:`, err);\n }\n }\n\n private readNewJsonlLines(): void {\n if (!this.jsonlPath) return;\n\n try {\n const stat = fs.statSync(this.jsonlPath);\n if (stat.size <= this.jsonlOffset) return;\n\n const fd = fs.openSync(this.jsonlPath, 'r');\n const buf = Buffer.alloc(stat.size - this.jsonlOffset);\n fs.readSync(fd, buf, 0, buf.length, this.jsonlOffset);\n fs.closeSync(fd);\n this.jsonlOffset = stat.size;\n\n const text = buf.toString('utf8');\n for (const line of text.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n try {\n const evt: JsonlEvent = JSON.parse(trimmed);\n this.processJsonlEvent(evt);\n } catch {\n // skip malformed lines\n }\n }\n } catch {\n // file might be temporarily unavailable\n }\n }\n\n /** Process a JSONL event — marks usedJsonl to disable PTY parsing */\n private processJsonlEvent(evt: JsonlEvent): void {\n // Once JSONL events arrive, disable PTY output parsing\n this.usedJsonl = true;\n\n if (!this.sessionId && evt.sessionId) {\n this.sessionId = evt.sessionId;\n }\n\n switch (evt.type) {\n case 'user': {\n const text = typeof evt.message?.content === 'string'\n ? evt.message.content\n : Array.isArray(evt.message?.content)\n ? evt.message.content\n .filter((c: any) => c.type === 'text')\n .map((c: any) => c.text)\n .join('\\n')\n : '';\n this.history.push({\n role: 'user',\n content: text,\n timestamp: evt.timestamp ? new Date(evt.timestamp).getTime() : Date.now(),\n });\n this.lastActivityAt = Date.now();\n this.emit('message', { type: 'user', content: text } as SseEvent);\n if (this.history.filter(m => m.role === 'user').length === 1 && text) {\n this.title = text.slice(0, 60);\n this.emit('title-change', this.title);\n }\n break;\n }\n case 'assistant': {\n const content = evt.message?.content;\n if (!Array.isArray(content)) break;\n\n const texts = content\n .filter((c: any) => c.type === 'text')\n .map((c: any) => c.text)\n .join('\\n')\n .trim();\n\n const tools: ToolUseInfo[] = content\n .filter((c: any) => c.type === 'tool_use')\n .map((c: any) => ({\n name: c.name,\n input: c.input || {},\n }));\n\n if (texts || tools.length) {\n this.history.push({\n role: 'assistant',\n content: texts,\n toolUse: tools.length ? tools : undefined,\n timestamp: evt.timestamp ? new Date(evt.timestamp).getTime() : Date.now(),\n });\n }\n\n if (texts) {\n this.emit('message', { type: 'assistant_text', content: texts } as SseEvent);\n }\n for (const t of tools) {\n this.emit('message', { type: 'assistant_tool', tool: t } as SseEvent);\n }\n break;\n }\n case 'system': {\n if (evt.subtype === 'tool_result') {\n const lastAssistant = [...this.history].reverse().find(m => m.role === 'assistant' && m.toolUse?.length);\n if (lastAssistant?.toolUse?.length) {\n const lastTool = lastAssistant.toolUse[lastAssistant.toolUse.length - 1];\n const resultText = typeof evt.message?.content === 'string'\n ? evt.message.content : '';\n lastTool.result = resultText.slice(0, 500);\n }\n const resultContent = typeof evt.message?.content === 'string'\n ? evt.message.content\n : Array.isArray(evt.message?.content)\n ? evt.message.content.map((c: any) => c.text || '').join('')\n : '';\n this.emit('message', { type: 'system', content: resultContent.slice(0, 200) } as SseEvent);\n } else if (evt.subtype === 'turn_duration') {\n this.status = 'ready';\n this.lastActivityAt = Date.now();\n this.emit('message', { type: 'done', durationMs: evt.durationMs } as SseEvent);\n }\n break;\n }\n }\n }\n\n // ── Lifecycle ─────────────────────────────────────────\n\n kill(): void {\n this.killed = true;\n this.cleanup();\n if (this.pty) {\n try { this.pty.kill(); } catch { /* already dead */ }\n this.pty = null;\n }\n this.status = 'exited';\n }\n\n private cleanup(): void {\n if (this.jsonlWatcher) {\n this.jsonlWatcher.close();\n this.jsonlWatcher = null;\n }\n }\n\n getInfo(): {\n id: string;\n title: string;\n status: SessionStatus;\n createdAt: number;\n lastActivityAt: number;\n messageCount: number;\n lastMessagePreview: string;\n sessionId: string | null;\n } {\n const lastMsg = this.history[this.history.length - 1];\n return {\n id: this.id,\n title: this.title,\n status: this.status,\n createdAt: this.spawnTime,\n lastActivityAt: this.lastActivityAt,\n messageCount: this.history.length,\n lastMessagePreview: lastMsg ? lastMsg.content.slice(0, 80) : '',\n sessionId: this.sessionId,\n };\n }\n\n getHistory(): ChatMessage[] {\n return [...this.history];\n }\n}\n","/**\n * CC Prompter — Asset Loader\n *\n * 运行时从包根目录读取 panel.html 和 inject.js。\n * 兼容 ESM(import.meta.url)和 CJS(__dirname)。\n *\n * 解析策略:\n * - tsup 构建后:资产文件复制到 dist/,__dirname 是 dist/\n * - Vite 直接引用 TS:__dirname 是 src/,资产文件在上一级\n */\n\nimport { readFileSync, existsSync } from 'fs';\nimport { join, dirname } from 'path';\nimport { fileURLToPath } from 'url';\n\n// Resolve __dirname in both ESM and CJS contexts\nconst _dirname = typeof __dirname !== 'undefined'\n ? __dirname\n : dirname(fileURLToPath(import.meta.url));\n\n/** Resolve asset path — checks dist/ (build) then parent (dev) */\nfunction assetPath(filename: string): string {\n // 1. Same dir as this file (dist/ after build, or src/ in dev)\n const here = join(_dirname, filename);\n if (existsSync(here)) return here;\n\n // 2. Parent dir (package root — when running from src/ via vite)\n const parent = join(_dirname, '..', filename);\n if (existsSync(parent)) return parent;\n\n // 3. Fallback — let it throw with a clear message\n throw new Error(\n `[cc-prompter] Asset not found: ${filename}\\n` +\n ` Tried: ${here}\\n` +\n ` Tried: ${parent}\\n` +\n ` __dirname: ${_dirname}`\n );\n}\n\nexport function getPanelHtml(): string {\n return readFileSync(assetPath('panel.html'), 'utf8');\n}\n\nexport function getInjectScript(): string {\n return readFileSync(assetPath('inject.js'), 'utf8');\n}\n"],"mappings":"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","names":["import_path","import_url","require","resolve","import_url","import_meta","express","resolve","import_meta","_dirname"]}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CC Prompter — Webpack Plugin
|
|
3
|
+
*
|
|
4
|
+
* 通用 webpack 插件,可在任意 webpack 项目中使用(不限于 Next.js)。
|
|
5
|
+
*
|
|
6
|
+
* 功能:
|
|
7
|
+
* 1. 启动 Sidecar Express server 管理 PTY sessions
|
|
8
|
+
* 2. 内置 code-inspector-plugin(Shift+Alt 悬停定位源码)
|
|
9
|
+
* 3. 通过 DefinePlugin + entry 注入轻量脚本
|
|
10
|
+
*
|
|
11
|
+
* 仅在 dev 模式生效(可通过 dev 选项控制)。
|
|
12
|
+
*
|
|
13
|
+
* 用法:
|
|
14
|
+
* // webpack.config.js
|
|
15
|
+
* const { CcPromptWebpackPlugin } = require('cc-prompter/webpack');
|
|
16
|
+
* module.exports = {
|
|
17
|
+
* plugins: [
|
|
18
|
+
* new CcPromptWebpackPlugin(),
|
|
19
|
+
* ],
|
|
20
|
+
* };
|
|
21
|
+
*/
|
|
22
|
+
interface CcPromptWebpackOptions {
|
|
23
|
+
/** Sidecar 启动端口,默认 3456(被占用时自动 +1) */
|
|
24
|
+
port?: number;
|
|
25
|
+
/** 项目根目录,默认 process.cwd() */
|
|
26
|
+
root?: string;
|
|
27
|
+
/** 是否启用 code-inspector,默认 true */
|
|
28
|
+
inspector?: boolean;
|
|
29
|
+
/** 是否 dev 模式,默认 process.env.NODE_ENV !== 'production' */
|
|
30
|
+
dev?: boolean;
|
|
31
|
+
}
|
|
32
|
+
declare class CcPromptWebpackPlugin {
|
|
33
|
+
private options;
|
|
34
|
+
private sidecarServer;
|
|
35
|
+
private sidecarStarted;
|
|
36
|
+
private cleanedUp;
|
|
37
|
+
constructor(options?: CcPromptWebpackOptions);
|
|
38
|
+
apply(compiler: any): void;
|
|
39
|
+
private setupCleanup;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export { type CcPromptWebpackOptions, CcPromptWebpackPlugin };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CC Prompter — Webpack Plugin
|
|
3
|
+
*
|
|
4
|
+
* 通用 webpack 插件,可在任意 webpack 项目中使用(不限于 Next.js)。
|
|
5
|
+
*
|
|
6
|
+
* 功能:
|
|
7
|
+
* 1. 启动 Sidecar Express server 管理 PTY sessions
|
|
8
|
+
* 2. 内置 code-inspector-plugin(Shift+Alt 悬停定位源码)
|
|
9
|
+
* 3. 通过 DefinePlugin + entry 注入轻量脚本
|
|
10
|
+
*
|
|
11
|
+
* 仅在 dev 模式生效(可通过 dev 选项控制)。
|
|
12
|
+
*
|
|
13
|
+
* 用法:
|
|
14
|
+
* // webpack.config.js
|
|
15
|
+
* const { CcPromptWebpackPlugin } = require('cc-prompter/webpack');
|
|
16
|
+
* module.exports = {
|
|
17
|
+
* plugins: [
|
|
18
|
+
* new CcPromptWebpackPlugin(),
|
|
19
|
+
* ],
|
|
20
|
+
* };
|
|
21
|
+
*/
|
|
22
|
+
interface CcPromptWebpackOptions {
|
|
23
|
+
/** Sidecar 启动端口,默认 3456(被占用时自动 +1) */
|
|
24
|
+
port?: number;
|
|
25
|
+
/** 项目根目录,默认 process.cwd() */
|
|
26
|
+
root?: string;
|
|
27
|
+
/** 是否启用 code-inspector,默认 true */
|
|
28
|
+
inspector?: boolean;
|
|
29
|
+
/** 是否 dev 模式,默认 process.env.NODE_ENV !== 'production' */
|
|
30
|
+
dev?: boolean;
|
|
31
|
+
}
|
|
32
|
+
declare class CcPromptWebpackPlugin {
|
|
33
|
+
private options;
|
|
34
|
+
private sidecarServer;
|
|
35
|
+
private sidecarStarted;
|
|
36
|
+
private cleanedUp;
|
|
37
|
+
constructor(options?: CcPromptWebpackOptions);
|
|
38
|
+
apply(compiler: any): void;
|
|
39
|
+
private setupCleanup;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export { type CcPromptWebpackOptions, CcPromptWebpackPlugin };
|