@yr-kits/dev-copilot 0.1.1 → 0.1.2
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/app/index.d.mts +2 -0
- package/dist/app/index.mjs +4 -0
- package/dist/bin/bridge.mjs +4 -916
- package/dist/bin/bridge.mjs.map +1 -1
- package/dist/bin/dev-copilot.mjs +13 -3
- package/dist/bin/dev-copilot.mjs.map +1 -1
- package/dist/bridge/app/index.d.mts +24 -0
- package/dist/bridge/app/index.d.mts.map +1 -0
- package/dist/bridge/app/index.mjs +3 -0
- package/dist/{types/index.d.mts → copilot-D8--qKgC.d.mts} +3 -3
- package/dist/copilot-D8--qKgC.d.mts.map +1 -0
- package/dist/copilot-overlay-ClRoIHew.mjs +1129 -0
- package/dist/copilot-overlay-ClRoIHew.mjs.map +1 -0
- package/dist/copilot-overlay-NlUgrMjy.d.mts +7 -0
- package/dist/copilot-overlay-NlUgrMjy.d.mts.map +1 -0
- package/dist/dev-copilot-context-CA9bqV_U.mjs +35 -0
- package/dist/dev-copilot-context-CA9bqV_U.mjs.map +1 -0
- package/dist/dev-copilot-provider-CP_gJvWG.d.mts +22 -0
- package/dist/dev-copilot-provider-CP_gJvWG.d.mts.map +1 -0
- package/dist/dev-copilot-provider-D0_wEEem.mjs +14 -0
- package/dist/dev-copilot-provider-D0_wEEem.mjs.map +1 -0
- package/dist/index.d.mts +5 -33
- package/dist/index.mjs +6 -863
- package/dist/run-bridge-cli-DVLGcVgq.mjs +1510 -0
- package/dist/run-bridge-cli-DVLGcVgq.mjs.map +1 -0
- package/dist/types.d.mts +2 -0
- package/dist/widgets/copilot-overlay/index.d.mts +2 -0
- package/dist/widgets/copilot-overlay/index.mjs +4 -0
- package/package.json +25 -7
- package/dist/index.d.mts.map +0 -1
- package/dist/index.mjs.map +0 -1
- package/dist/types/index.d.mts.map +0 -1
- /package/dist/{types/index.mjs → types.mjs} +0 -0
package/dist/bin/bridge.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bridge.mjs","names":["execFileAsync","execFileAsync","fs","execFileAsync","fs","fs"],"sources":["../../src/bridge/lib/config.ts","../../src/bridge/lib/guards.ts","../../src/bridge/internal/prompts.ts","../../src/bridge/internal/agents/claude-adapter.ts","../../src/bridge/internal/agents/codex-adapter.ts","../../src/bridge/internal/agents/index.ts","../../src/bridge/internal/project-context.ts","../../src/bridge/lib/patch.ts","../../src/bridge/lib/store.ts","../../src/bridge/server/http-server.ts","../../src/bridge/cli/run-http.ts","../../src/bin/bridge.ts"],"sourcesContent":["import type { CopilotAgent } from \"../types\";\n\nexport interface DevCopilotBridgeConfig {\n rootDir: string;\n host: string;\n port: number;\n corsOrigin: string;\n agent: CopilotAgent;\n allowedPaths: string[];\n}\n\nconst DEFAULT_ALLOWED_PATHS = [\n \"app\",\n \"src\",\n \"widgets\",\n \"features\",\n \"entities\",\n \"shared\",\n \"components\",\n];\n\nexport const createDevCopilotBridgeConfig = (\n config: Partial<DevCopilotBridgeConfig> & { rootDir: string },\n): DevCopilotBridgeConfig => {\n return {\n rootDir: config.rootDir,\n host: config.host ?? \"127.0.0.1\",\n port: config.port ?? 3339,\n corsOrigin: config.corsOrigin ?? \"*\",\n agent: config.agent ?? \"codex\",\n allowedPaths: config.allowedPaths ?? DEFAULT_ALLOWED_PATHS,\n };\n};\n","import path from \"node:path\";\n\nimport type { DevCopilotBridgeConfig } from \"./config\";\n\nexport const resolveAndValidatePath = (\n filePath: string,\n allowedPaths: DevCopilotBridgeConfig[\"allowedPaths\"],\n rootDir?: string,\n) => {\n if (!filePath) {\n throw new Error(\"허용되지 않은 파일 경로입니다.\");\n }\n\n let normalizedInput = filePath.replaceAll(\"\\\\\", \"/\");\n\n if (rootDir) {\n const normalizedRootDir = rootDir.replaceAll(\"\\\\\", \"/\").replace(/\\/+$/, \"\");\n\n if (normalizedInput.startsWith(`${normalizedRootDir}/`)) {\n normalizedInput = normalizedInput.slice(normalizedRootDir.length + 1);\n }\n }\n\n if (\n path.isAbsolute(normalizedInput) ||\n normalizedInput.includes(\"..\")\n ) {\n throw new Error(\"허용되지 않은 파일 경로입니다.\");\n }\n\n const normalized = normalizedInput;\n const firstSegment = normalized.split(\"/\")[0];\n const allowAll = allowedPaths.includes(\".\") || allowedPaths.includes(\"*\");\n\n if (!allowAll && !allowedPaths.includes(firstSegment)) {\n throw new Error(`허용 경로 외 파일은 수정할 수 없습니다: ${firstSegment}`);\n }\n\n return normalized;\n};\n","import type { CopilotMode } from \"../types\";\n\nexport interface AgentPromptRequest {\n selectedText: string;\n prompt: string;\n mode: CopilotMode;\n route?: string;\n fileHints?: string[];\n projectContext?: string;\n previousResponse?: string;\n}\n\nexport const buildAgentPrompt = (request: AgentPromptRequest) => {\n if (request.mode === \"answer\") {\n return [\n \"Answer the user's web overlay request.\",\n \"Do not modify files.\",\n \"Use the provided project context when it is relevant.\",\n \"Respond in Korean.\",\n \"Keep the answer concise and actionable.\",\n \"\",\n `Current route: ${request.route ?? \"unknown\"}`,\n `Selected text:\\n${request.selectedText || \"(none)\"}`,\n `User prompt:\\n${request.prompt}`,\n `Previous AI response:\\n${request.previousResponse ?? \"(none)\"}`,\n `Project context:\\n${request.projectContext ?? \"(none)\"}`,\n ].join(\"\\n\");\n }\n\n return [\n \"You are a local code-edit proposal generator called from a web overlay.\",\n \"Do not modify files directly.\",\n \"Return JSON only.\",\n \"Do not generate unified diff directly.\",\n \"Put repository-relative file path(path), exact old text(oldText), and replacement text(newText) into the changes array.\",\n \"Never use absolute paths. The path must be relative to the repository root, for example src/features/article/model/data.ts.\",\n \"oldText must exactly match the file content and must not use ellipsis.\",\n \"Ground the proposal in the selected text, user prompt, and provided project context.\",\n \"Write the message field in Korean.\",\n \"\",\n `Current route: ${request.route ?? \"unknown\"}`,\n `Allowed path hints: ${(request.fileHints ?? []).join(\", \") || \"(none)\"}`,\n `Selected text:\\n${request.selectedText || \"(none)\"}`,\n `User prompt:\\n${request.prompt}`,\n `Previous AI response:\\n${request.previousResponse ?? \"(none)\"}`,\n `Project context:\\n${request.projectContext ?? \"(none)\"}`,\n ].join(\"\\n\");\n};\n","import { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\n\nimport { buildAgentPrompt } from \"../prompts\";\nimport type {\n AgentAdapter,\n AgentBridgeRequest,\n AgentBridgeResponse,\n AgentStatus,\n} from \"./types\";\n\nconst execFileAsync = promisify(execFile);\n\ntype ClaudePrintJsonResponse = {\n result?: unknown;\n message?: unknown;\n output?: unknown;\n content?: unknown;\n};\n\nconst AUTH_ERROR_PATTERN =\n /401|authentication|invalid authentication credentials|please run \\/login|claude\\s*\\/login|로그인/i;\n\nconst extractErrorDetails = (error: unknown) => {\n const unknownRecord = error && typeof error === \"object\" ? (error as Record<string, unknown>) : null;\n const message = error instanceof Error ? error.message : String(error);\n const stderr = typeof unknownRecord?.stderr === \"string\" ? unknownRecord.stderr : \"\";\n const stdout = typeof unknownRecord?.stdout === \"string\" ? unknownRecord.stdout : \"\";\n const merged = [message, stderr, stdout]\n .map((part) => part.trim())\n .filter(Boolean)\n .join(\"\\n\");\n\n return {\n message,\n stderr,\n stdout,\n merged,\n };\n};\n\nconst toClaudeErrorMessage = (error: unknown) => {\n const { message, merged } = extractErrorDetails(error);\n\n if (AUTH_ERROR_PATTERN.test(merged)) {\n return \"Claude Code 로그인이 필요합니다. 터미널에서 `claude /login`을 실행해 주세요.\";\n }\n\n if (/ENOENT/.test(merged)) {\n return \"Claude CLI를 찾을 수 없습니다. Claude Code CLI 설치 상태를 확인해 주세요.\";\n }\n\n return message;\n};\n\nconst findFirstString = (value: unknown): string | null => {\n if (typeof value === \"string\") {\n const text = value.trim();\n return text ? text : null;\n }\n\n if (Array.isArray(value)) {\n for (const item of value) {\n const found = findFirstString(item);\n if (found) {\n return found;\n }\n }\n return null;\n }\n\n if (value && typeof value === \"object\") {\n const record = value as Record<string, unknown>;\n const preferredKeys = [\"result\", \"message\", \"output\", \"text\", \"content\"];\n\n for (const key of preferredKeys) {\n if (key in record) {\n const found = findFirstString(record[key]);\n if (found) {\n return found;\n }\n }\n }\n\n for (const nestedValue of Object.values(record)) {\n const found = findFirstString(nestedValue);\n if (found) {\n return found;\n }\n }\n }\n\n return null;\n};\n\nconst parseClaudeJsonOutput = (raw: string) => {\n const parsed = JSON.parse(raw) as ClaudePrintJsonResponse;\n const text = findFirstString(parsed) ?? \"\";\n\n return {\n parsed,\n text,\n };\n};\n\nconst parseClaudeEditResponse = (raw: string): AgentBridgeResponse => {\n const { text } = parseClaudeJsonOutput(raw);\n const parsed = JSON.parse(text) as AgentBridgeResponse;\n\n return {\n message: parsed.message,\n patchPreview: parsed.patchPreview,\n changes: parsed.changes,\n warnings: parsed.warnings ?? [],\n };\n};\n\nexport const claudeAdapter: AgentAdapter = {\n agent: \"claude\",\n async run(request: AgentBridgeRequest): Promise<AgentBridgeResponse> {\n const prompt = buildAgentPrompt(request);\n const args = [\n \"-p\",\n \"--output-format\",\n \"json\",\n ...(request.mode === \"edit\"\n ? [\n \"--json-schema\",\n '{\"type\":\"object\",\"properties\":{\"message\":{\"type\":\"string\"},\"patchPreview\":{\"type\":\"string\"},\"warnings\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"changes\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"properties\":{\"path\":{\"type\":\"string\"},\"oldText\":{\"type\":\"string\"},\"newText\":{\"type\":\"string\"}},\"required\":[\"path\",\"oldText\",\"newText\"],\"additionalProperties\":false}}},\"required\":[\"message\"],\"additionalProperties\":false}',\n ]\n : []),\n prompt,\n ];\n\n try {\n const { stdout } = await execFileAsync(\"claude\", args, {\n cwd: request.cwd,\n maxBuffer: 1024 * 1024 * 5,\n timeout: Number(process.env.DEV_COPILOT_AGENT_TIMEOUT_MS ?? 120_000),\n env: {\n ...process.env,\n NO_COLOR: \"1\",\n },\n });\n\n if (request.mode === \"answer\") {\n const { text } = parseClaudeJsonOutput(stdout);\n\n return {\n message: text,\n warnings: [],\n };\n }\n\n return parseClaudeEditResponse(stdout);\n } catch (error) {\n throw new Error(toClaudeErrorMessage(error));\n }\n },\n async getStatus(cwd: string): Promise<AgentStatus> {\n try {\n await execFileAsync(\"claude\", [\"-p\", \"--output-format\", \"json\", \"OK\"], {\n cwd,\n timeout: 15_000,\n maxBuffer: 1024 * 512,\n });\n\n return {\n available: true,\n authenticated: true,\n agent: \"claude\",\n message: \"Claude Code CLI에 로그인되어 있습니다.\",\n };\n } catch (error) {\n const { merged, message } = extractErrorDetails(error);\n const unavailable = /ENOENT/.test(merged);\n const authError = AUTH_ERROR_PATTERN.test(merged);\n\n return {\n available: !unavailable,\n authenticated: false,\n agent: \"claude\",\n message: unavailable\n ? \"Claude CLI를 찾을 수 없습니다.\"\n : authError\n ? \"Claude Code 로그인이 필요합니다.\"\n : \"Claude Code 상태 확인에 실패했습니다. 터미널에서 `claude /login` 실행 후 다시 시도해 주세요.\",\n loginCommand: unavailable ? undefined : \"claude /login\",\n };\n }\n },\n};\n\nexport const __internal = {\n findFirstString,\n parseClaudeJsonOutput,\n parseClaudeEditResponse,\n toClaudeErrorMessage,\n};\n","import { execFile } from \"node:child_process\";\nimport { promises as fs } from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { promisify } from \"node:util\";\n\nimport { buildAgentPrompt } from \"../prompts\";\nimport type {\n AgentAdapter,\n AgentBridgeRequest,\n AgentBridgeResponse,\n AgentStatus,\n} from \"./types\";\n\nconst execFileAsync = promisify(execFile);\nconst codexBridgeConfigArgs = [\n \"-c\",\n \"mcp_servers.notion.enabled=false\",\n \"-c\",\n \"mcp_servers.figma.enabled=false\",\n \"-c\",\n \"mcp_servers.linear.enabled=false\",\n \"-c\",\n \"mcp_servers.context7.enabled=false\",\n \"-c\",\n \"mcp_servers.playwright.enabled=false\",\n \"-c\",\n \"mcp_servers.zeplin.enabled=false\",\n] as const;\nconst codexDiffResponseSchema = {\n type: \"object\",\n properties: {\n message: { type: \"string\" },\n warnings: {\n type: \"array\",\n items: { type: \"string\" },\n },\n changes: {\n type: \"array\",\n items: {\n type: \"object\",\n properties: {\n path: { type: \"string\" },\n oldText: { type: \"string\" },\n newText: { type: \"string\" },\n },\n required: [\"path\", \"oldText\", \"newText\"],\n additionalProperties: false,\n },\n },\n },\n required: [\"message\", \"warnings\", \"changes\"],\n additionalProperties: false,\n} as const;\n\nconst parseAnswerResponse = (rawOutput: string): AgentBridgeResponse => {\n return {\n message: rawOutput.trim(),\n warnings: [],\n };\n};\n\nconst parseEditResponse = async (outputPath: string) => {\n const content = await fs.readFile(outputPath, \"utf-8\");\n const parsed = JSON.parse(content) as AgentBridgeResponse;\n\n return {\n message: parsed.message,\n patchPreview: parsed.patchPreview,\n changes: parsed.changes,\n warnings: parsed.warnings ?? [],\n };\n};\n\nconst isCodexAuthenticatedFromStatus = (statusOutput: string) => {\n const normalized = statusOutput.toLowerCase();\n\n if (/not logged in|login required|로그인 필요/.test(normalized)) {\n return false;\n }\n\n return /logged in|로그인됨|로그인되어/.test(normalized);\n};\n\nconst toCodexErrorMessage = (error: unknown) => {\n const message = error instanceof Error ? error.message : String(error);\n\n if (/not logged in|login required|authentication|unauthorized/i.test(message)) {\n return \"Codex CLI 로그인이 필요합니다. 터미널에서 `codex login`을 실행해 주세요.\";\n }\n\n if (/ENOENT/.test(message)) {\n return \"Codex CLI를 찾을 수 없습니다. Codex CLI 설치 상태를 확인해 주세요.\";\n }\n\n return message;\n};\n\nconst getCodexModelName = async (cwd: string) => {\n const outputPath = path.join(\n os.tmpdir(),\n `dev-copilot-codex-status-${Date.now()}-${Math.random().toString(16).slice(2)}.txt`,\n );\n\n try {\n const { stdout, stderr } = await execFileAsync(\n \"codex\",\n [\n ...codexBridgeConfigArgs,\n \"exec\",\n \"--cd\",\n cwd,\n \"--sandbox\",\n \"read-only\",\n \"--skip-git-repo-check\",\n \"--output-last-message\",\n outputPath,\n \"OK만 출력해줘.\",\n ],\n {\n cwd,\n timeout: 30_000,\n maxBuffer: 1024 * 512,\n env: {\n ...process.env,\n NO_COLOR: \"1\",\n },\n },\n );\n const output = `${stdout}\\n${stderr}`;\n const match = output.match(/^model:\\s*(.+)$/m);\n\n return match?.[1]?.trim();\n } catch {\n return undefined;\n } finally {\n await fs.rm(outputPath, { force: true });\n }\n};\n\nexport const codexAdapter: AgentAdapter = {\n agent: \"codex\",\n async run(request: AgentBridgeRequest): Promise<AgentBridgeResponse> {\n const outputPath = path.join(\n os.tmpdir(),\n `dev-copilot-codex-${Date.now()}-${Math.random().toString(16).slice(2)}.json`,\n );\n const schemaPath = path.join(\n os.tmpdir(),\n `dev-copilot-codex-schema-${Date.now()}-${Math.random().toString(16).slice(2)}.json`,\n );\n\n await fs.writeFile(\n schemaPath,\n JSON.stringify(codexDiffResponseSchema),\n \"utf-8\",\n );\n\n const prompt = buildAgentPrompt(request);\n const args = [\n ...codexBridgeConfigArgs,\n \"exec\",\n \"--cd\",\n request.cwd,\n \"--sandbox\",\n \"read-only\",\n \"--skip-git-repo-check\",\n \"--output-last-message\",\n outputPath,\n ...(request.mode === \"edit\" ? [\"--output-schema\", schemaPath] : []),\n prompt,\n ];\n\n try {\n const { stdout } = await execFileAsync(\"codex\", args, {\n cwd: request.cwd,\n maxBuffer: 1024 * 1024 * 5,\n timeout: Number(process.env.DEV_COPILOT_AGENT_TIMEOUT_MS ?? 120_000),\n env: {\n ...process.env,\n NO_COLOR: \"1\",\n },\n });\n\n if (request.mode === \"answer\") {\n try {\n const output = await fs.readFile(outputPath, \"utf-8\");\n return parseAnswerResponse(output);\n } catch {\n return parseAnswerResponse(stdout);\n }\n }\n\n return await parseEditResponse(outputPath);\n } catch (error) {\n throw new Error(toCodexErrorMessage(error));\n } finally {\n await fs.rm(outputPath, { force: true });\n await fs.rm(schemaPath, { force: true });\n }\n },\n async getStatus(cwd: string): Promise<AgentStatus> {\n try {\n const { stdout, stderr } = await execFileAsync(\"codex\", [\"login\", \"status\"], {\n cwd,\n timeout: 10_000,\n maxBuffer: 1024 * 128,\n });\n const output = `${stdout}\\n${stderr}`.trim();\n const authenticated = isCodexAuthenticatedFromStatus(output);\n const model = authenticated ? await getCodexModelName(cwd) : undefined;\n\n return {\n available: true,\n authenticated,\n agent: \"codex\",\n message: authenticated\n ? output || \"Codex CLI에 로그인되어 있습니다.\"\n : output || \"Codex CLI 로그인이 필요합니다.\",\n model,\n loginCommand: authenticated ? undefined : \"codex login\",\n };\n } catch (error) {\n const message =\n error instanceof Error ? error.message : \"Codex CLI 상태 확인에 실패했습니다.\";\n\n return {\n available: !message.includes(\"ENOENT\"),\n authenticated: false,\n agent: \"codex\",\n message: message.includes(\"ENOENT\")\n ? \"Codex CLI를 찾을 수 없습니다.\"\n : message,\n loginCommand: message.includes(\"ENOENT\") ? undefined : \"codex login\",\n };\n }\n },\n};\n\nexport const __internal = {\n toCodexErrorMessage,\n};\n","import type { CopilotAgent } from \"../../types\";\nimport { __internal as claudeInternal, claudeAdapter } from \"./claude-adapter\";\nimport { __internal as codexInternal, codexAdapter } from \"./codex-adapter\";\nimport type { AgentAdapter } from \"./types\";\n\nconst adapters: Record<CopilotAgent, AgentAdapter> = {\n codex: codexAdapter,\n claude: claudeAdapter,\n};\n\nexport const resolveAgentAdapter = (agent: CopilotAgent): AgentAdapter => {\n return adapters[agent];\n};\n\nexport { claudeAdapter, codexAdapter };\nexport const agentTestInternals = {\n claude: claudeInternal,\n codex: codexInternal,\n};\nexport type { AgentAdapter, AgentBridgeRequest, AgentBridgeResponse, AgentStatus } from \"./types\";\n","import { execFile } from \"node:child_process\";\nimport { promises as fs } from \"node:fs\";\nimport path from \"node:path\";\nimport { promisify } from \"node:util\";\n\nconst execFileAsync = promisify(execFile);\n\ninterface ProjectContextConfig {\n rootDir: string;\n allowedDirs: string[];\n ignoredDirs: string[];\n maxReadBytes: number;\n maxSearchResults: number;\n}\n\ninterface CopilotContextParams {\n selectedText?: string;\n route?: string;\n fileHints?: string[];\n}\n\ninterface SearchResult {\n path: string;\n line: number;\n text: string;\n}\n\nconst normalizeRelativePath = (filePath: string) => {\n return filePath.replaceAll(\"\\\\\", \"/\").replace(/^\\.\\/+/, \"\");\n};\n\nconst isIgnoredPath = (relativePath: string, config: ProjectContextConfig) => {\n const segments = normalizeRelativePath(relativePath).split(\"/\");\n return segments.some((segment) => config.ignoredDirs.includes(segment));\n};\n\nconst walk = async (\n relativeDir: string,\n config: ProjectContextConfig,\n results: string[],\n limit: number,\n) => {\n if (results.length >= limit || isIgnoredPath(relativeDir, config)) {\n return;\n }\n\n const absoluteDir = path.join(config.rootDir, relativeDir);\n const entries = await fs.readdir(absoluteDir, { withFileTypes: true });\n\n for (const entry of entries) {\n if (results.length >= limit) {\n return;\n }\n\n const relativePath = normalizeRelativePath(path.join(relativeDir, entry.name));\n\n if (isIgnoredPath(relativePath, config)) {\n continue;\n }\n\n if (entry.isDirectory()) {\n await walk(relativePath, config, results, limit);\n continue;\n }\n\n if (entry.isFile()) {\n results.push(relativePath);\n }\n }\n};\n\nconst listProjectFiles = async (\n config: ProjectContextConfig,\n query?: string,\n limit = 80,\n) => {\n const results: string[] = [];\n\n for (const allowedDir of config.allowedDirs) {\n const absoluteDir = path.join(config.rootDir, allowedDir);\n\n try {\n const stat = await fs.stat(absoluteDir);\n\n if (stat.isDirectory()) {\n await walk(allowedDir, config, results, limit);\n }\n } catch {\n continue;\n }\n }\n\n if (!query) {\n return results;\n }\n\n return results.filter((filePath) => filePath.toLowerCase().includes(query.toLowerCase()));\n};\n\nconst readProjectFile = async (\n config: ProjectContextConfig,\n filePath: string,\n maxBytes = config.maxReadBytes,\n) => {\n const absolutePath = path.join(config.rootDir, normalizeRelativePath(filePath));\n const content = await fs.readFile(absolutePath, \"utf-8\");\n\n return {\n path: filePath,\n content: content.slice(0, maxBytes),\n };\n};\n\nconst searchWithRg = async (\n config: ProjectContextConfig,\n query: string,\n limit: number,\n) => {\n const { stdout } = await execFileAsync(\n \"rg\",\n [\n \"--line-number\",\n \"--fixed-strings\",\n \"--color\",\n \"never\",\n \"--glob\",\n \"!node_modules/**\",\n \"--glob\",\n \"!.next/**\",\n \"--glob\",\n \"!.git/**\",\n query,\n ...config.allowedDirs,\n ],\n {\n cwd: config.rootDir,\n maxBuffer: 1024 * 1024,\n },\n );\n\n return stdout\n .split(\"\\n\")\n .filter(Boolean)\n .slice(0, limit)\n .map((line) => {\n const [filePath, lineNumber, ...rest] = line.split(\":\");\n return {\n path: filePath,\n line: Number(lineNumber),\n text: rest.join(\":\").trim(),\n };\n });\n};\n\nconst searchWithNode = async (\n config: ProjectContextConfig,\n query: string,\n limit: number,\n) => {\n const files = await listProjectFiles(config, undefined, 500);\n const results: SearchResult[] = [];\n\n for (const filePath of files) {\n if (results.length >= limit) {\n break;\n }\n\n try {\n const file = await readProjectFile(config, filePath, 100_000);\n const lines = file.content.split(\"\\n\");\n\n lines.forEach((line, index) => {\n if (results.length < limit && line.includes(query)) {\n results.push({\n path: filePath,\n line: index + 1,\n text: line.trim(),\n });\n }\n });\n } catch {\n continue;\n }\n }\n\n return results;\n};\n\nconst searchProjectText = async (\n config: ProjectContextConfig,\n query: string,\n limit = config.maxSearchResults,\n) => {\n if (!query.trim()) {\n return [];\n }\n\n try {\n return await searchWithRg(config, query, limit);\n } catch {\n return searchWithNode(config, query, limit);\n }\n};\n\nconst findComponentByText = async (\n config: ProjectContextConfig,\n text: string,\n limit = 8,\n) => {\n const normalized = text.replace(/\\s+/g, \" \").trim();\n const candidates = [\n normalized,\n normalized.slice(0, 120),\n ...normalized.split(/[.!?]\\s+/).filter((item) => item.length > 12),\n ];\n\n for (const candidate of candidates) {\n const results = await searchProjectText(config, candidate, limit);\n\n if (results.length) {\n return {\n query: candidate,\n results,\n };\n }\n }\n\n return {\n query: normalized,\n results: [],\n };\n};\n\nconst readJsonFile = async (rootDir: string, filePath: string) => {\n try {\n const content = await fs.readFile(path.join(rootDir, filePath), \"utf-8\");\n return JSON.parse(content) as Record<string, unknown>;\n } catch {\n return null;\n }\n};\n\nconst getProjectContext = async (config: ProjectContextConfig) => {\n const packageJson = await readJsonFile(config.rootDir, \"package.json\");\n const tsconfig = await readJsonFile(config.rootDir, \"tsconfig.json\");\n\n return {\n rootDir: config.rootDir,\n allowedDirs: config.allowedDirs,\n packageName: packageJson?.name,\n scripts: packageJson?.scripts,\n dependencies: packageJson?.dependencies,\n devDependencies: packageJson?.devDependencies,\n tsconfigPaths: (tsconfig?.compilerOptions as { paths?: unknown } | undefined)\n ?.paths,\n };\n};\n\nexport const buildCopilotProjectContext = async (\n rootDir: string,\n allowedDirs: string[],\n params: CopilotContextParams,\n) => {\n const config: ProjectContextConfig = {\n rootDir,\n allowedDirs,\n ignoredDirs: [\".git\", \".next\", \"node_modules\", \"coverage\", \"public\", \"dist\", \"build\"],\n maxReadBytes: 30_000,\n maxSearchResults: 20,\n };\n\n const project = await getProjectContext(config);\n const selectedText = params.selectedText?.trim();\n const routeQuery = params.route?.startsWith(\"/\")\n ? `app${params.route === \"/\" ? \"\" : params.route}/page.tsx`\n : params.route;\n\n const textMatches = selectedText\n ? await findComponentByText(config, selectedText, 8)\n : { query: \"\", results: [] };\n const routeMatches = routeQuery\n ? await searchProjectText(config, routeQuery, 5)\n : [];\n\n return JSON.stringify(\n {\n project,\n requestContext: {\n route: params.route,\n fileHints: params.fileHints,\n },\n selectedTextLookup: textMatches,\n routeLookup: routeMatches,\n guidance:\n \"이 컨텍스트는 로컬 프로젝트에서 수집한 실제 코드 검색 결과입니다. 수정 제안은 이 결과를 우선 근거로 삼고 path/oldText/newText 기반으로 작성하세요.\",\n },\n null,\n 2,\n );\n};\n","import { execFile } from \"node:child_process\";\nimport { promises as fs } from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { promisify } from \"node:util\";\n\nconst execFileAsync = promisify(execFile);\n\nconst getChangedFiles = (patchPreview: string) => {\n const regex = /^\\+\\+\\+ b\\/(.+)$/gm;\n const changedFiles = new Set<string>();\n\n let match = regex.exec(patchPreview);\n while (match) {\n changedFiles.add(match[1]);\n match = regex.exec(patchPreview);\n }\n\n return [...changedFiles];\n};\n\ninterface TextReplacement {\n path: string;\n oldText: string;\n newText: string;\n}\n\nexport const normalizeUnifiedPatch = (patchPreview: string) => {\n const withoutFence = patchPreview\n .replace(/^```(?:diff|patch)?\\s*/i, \"\")\n .replace(/\\s*```$/i, \"\")\n .trim();\n const diffStartIndex = withoutFence.indexOf(\"diff --git \");\n\n return diffStartIndex >= 0\n ? withoutFence.slice(diffStartIndex).trim()\n : withoutFence;\n};\n\nexport const validatePatchPaths = (\n patchPreview: string,\n validatePath: (filePath: string) => string,\n) => {\n const changedFiles = getChangedFiles(patchPreview);\n\n if (!changedFiles.length) {\n throw new Error(\"패치에서 변경 파일을 찾을 수 없습니다.\");\n }\n\n changedFiles.forEach(validatePath);\n\n return changedFiles;\n};\n\nexport const checkUnifiedPatch = async (patchPreview: string, cwd: string) => {\n const tempFilePath = path.join(\n os.tmpdir(),\n `dev-copilot-check-${Date.now()}-${Math.random().toString(16).slice(2)}.patch`,\n );\n\n await fs.writeFile(tempFilePath, patchPreview, \"utf-8\");\n\n try {\n await execFileAsync(\"git\", [\"apply\", \"--check\", tempFilePath], { cwd });\n } catch (error) {\n const detail =\n error instanceof Error && \"stderr\" in error\n ? String((error as Error & { stderr?: unknown }).stderr)\n : error instanceof Error\n ? error.message\n : \"알 수 없는 patch 검증 오류\";\n\n throw new Error(`적용 가능한 diff를 생성하지 못했습니다: ${detail.trim()}`);\n } finally {\n await fs.rm(tempFilePath, { force: true });\n }\n};\n\nconst createGitPatch = async (\n filePath: string,\n oldContent: string,\n newContent: string,\n) => {\n const tempDir = path.join(\n os.tmpdir(),\n `dev-copilot-diff-${Date.now()}-${Math.random().toString(16).slice(2)}`,\n );\n const oldFilePath = path.join(tempDir, \"old\", filePath);\n const newFilePath = path.join(tempDir, \"new\", filePath);\n\n await fs.mkdir(path.dirname(oldFilePath), { recursive: true });\n await fs.mkdir(path.dirname(newFilePath), { recursive: true });\n await fs.writeFile(oldFilePath, oldContent, \"utf-8\");\n await fs.writeFile(newFilePath, newContent, \"utf-8\");\n\n try {\n const { stdout } = await execFileAsync(\n \"git\",\n [\n \"diff\",\n \"--no-index\",\n \"--no-ext-diff\",\n \"--src-prefix=a/\",\n \"--dst-prefix=b/\",\n \"--\",\n path.join(\"old\", filePath),\n path.join(\"new\", filePath),\n ],\n { cwd: tempDir },\n ).catch((error: unknown) => {\n const typedError = error as { stdout?: string; code?: number };\n\n if (typedError.code === 1 && typedError.stdout) {\n return { stdout: typedError.stdout };\n }\n\n throw error;\n });\n\n return stdout\n .replaceAll(`a/old/${filePath}`, `a/${filePath}`)\n .replaceAll(`b/new/${filePath}`, `b/${filePath}`);\n } finally {\n await fs.rm(tempDir, { force: true, recursive: true });\n }\n};\n\nexport const createPatchFromTextReplacements = async (\n replacements: TextReplacement[],\n cwd: string,\n validatePath: (filePath: string) => string,\n) => {\n const byPath = new Map<string, TextReplacement[]>();\n\n for (const replacement of replacements) {\n const normalizedPath = validatePath(replacement.path);\n const current = byPath.get(normalizedPath) ?? [];\n current.push(replacement);\n byPath.set(normalizedPath, current);\n }\n\n const patches: string[] = [];\n\n for (const [filePath, fileReplacements] of byPath.entries()) {\n const absolutePath = path.join(cwd, filePath);\n const oldContent = await fs.readFile(absolutePath, \"utf-8\");\n let newContent = oldContent;\n\n for (const replacement of fileReplacements) {\n if (!newContent.includes(replacement.oldText)) {\n throw new Error(`원문을 파일에서 찾을 수 없습니다: ${filePath}`);\n }\n\n newContent = newContent.replace(replacement.oldText, replacement.newText);\n }\n\n if (newContent === oldContent) {\n continue;\n }\n\n patches.push(await createGitPatch(filePath, oldContent, newContent));\n }\n\n const patchPreview = patches.join(\"\\n\");\n\n if (!patchPreview.trim()) {\n throw new Error(\"변경할 내용이 없습니다.\");\n }\n\n return patchPreview;\n};\n\nexport const applyUnifiedPatch = async (\n patchPreview: string,\n cwd: string,\n actor: string,\n) => {\n const tempFilePath = path.join(\n os.tmpdir(),\n `dev-copilot-${Date.now()}-${Math.random().toString(16).slice(2)}.patch`,\n );\n\n await fs.writeFile(tempFilePath, patchPreview, \"utf-8\");\n\n try {\n await execFileAsync(\"git\", [\"apply\", \"--check\", tempFilePath], { cwd });\n await execFileAsync(\"git\", [\"apply\", tempFilePath], { cwd });\n\n const changedFiles = getChangedFiles(patchPreview);\n\n return {\n actor,\n changedFiles,\n };\n } catch (error) {\n const detail =\n error instanceof Error && \"stderr\" in error\n ? String((error as Error & { stderr?: unknown }).stderr)\n : error instanceof Error\n ? error.message\n : \"알 수 없는 patch 적용 오류\";\n\n throw new Error(`patch 적용에 실패했습니다: ${detail.trim()}`);\n } finally {\n await fs.rm(tempFilePath, { force: true });\n }\n};\n","import { randomUUID } from \"node:crypto\";\n\ninterface ProposedPatch {\n patchId: string;\n approvalToken: string;\n patchPreview: string;\n allowedPaths: string[];\n createdAt: number;\n}\n\nconst patchStore = new Map<string, ProposedPatch>();\nconst TTL_MS = 1000 * 60 * 15;\n\nconst pruneExpired = () => {\n const now = Date.now();\n\n for (const [key, value] of patchStore.entries()) {\n if (now - value.createdAt > TTL_MS) {\n patchStore.delete(key);\n }\n }\n};\n\nexport const createProposedPatch = (patchPreview: string, allowedPaths: string[]) => {\n pruneExpired();\n\n const patchId = randomUUID();\n const approvalToken = `approve:${patchId}`;\n\n patchStore.set(patchId, {\n patchId,\n approvalToken,\n patchPreview,\n allowedPaths,\n createdAt: Date.now(),\n });\n\n return {\n patchId,\n approvalToken,\n };\n};\n\nexport const getProposedPatch = (patchId: string, approvalToken: string) => {\n pruneExpired();\n\n const item = patchStore.get(patchId);\n\n if (!item || item.approvalToken !== approvalToken) {\n return null;\n }\n\n return item;\n};\n\nexport const deleteProposedPatch = (patchId: string) => {\n patchStore.delete(patchId);\n};\n","import { createServer, type IncomingMessage, type ServerResponse } from \"node:http\";\n\nimport type {\n CopilotAgent,\n CopilotApplyRequest,\n CopilotApplyResponse,\n CopilotChatRequest,\n CopilotChatResponse,\n} from \"../types\";\nimport type { DevCopilotBridgeConfig } from \"../lib/config\";\nimport { resolveAndValidatePath } from \"../lib/guards\";\nimport { resolveAgentAdapter } from \"../internal/agents\";\nimport type { AgentAdapter } from \"../internal/agents\";\nimport { buildCopilotProjectContext } from \"../internal/project-context\";\nimport {\n applyUnifiedPatch,\n checkUnifiedPatch,\n createPatchFromTextReplacements,\n validatePatchPaths,\n} from \"../lib/patch\";\nimport {\n createProposedPatch,\n deleteProposedPatch,\n getProposedPatch,\n} from \"../lib/store\";\n\ntype ParsedEditPayload = {\n message?: string;\n patchPreview?: string;\n changes?: Array<{\n path: string;\n oldText: string;\n newText: string;\n }>;\n warnings?: string[];\n};\n\nconst createCorsHeaders = (config: DevCopilotBridgeConfig) => ({\n \"Access-Control-Allow-Origin\": config.corsOrigin,\n \"Access-Control-Allow-Methods\": \"GET,POST,OPTIONS\",\n \"Access-Control-Allow-Headers\": \"Content-Type\",\n \"Content-Type\": \"application/json; charset=utf-8\",\n});\n\nconst sendJson = (\n response: ServerResponse,\n config: DevCopilotBridgeConfig,\n statusCode: number,\n payload: unknown,\n) => {\n response.writeHead(statusCode, createCorsHeaders(config));\n response.end(JSON.stringify(payload));\n};\n\nconst readJsonBody = async <T>(request: IncomingMessage) => {\n const chunks: Buffer[] = [];\n\n for await (const chunk of request) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n }\n\n const raw = Buffer.concat(chunks).toString(\"utf-8\");\n return JSON.parse(raw) as T;\n};\n\nconst createProjectContext = async (\n config: DevCopilotBridgeConfig,\n payload: CopilotChatRequest,\n allowedPaths: string[],\n) => {\n return buildCopilotProjectContext(\n config.rootDir,\n allowedPaths,\n {\n selectedText: payload.selectedText,\n route: payload.context?.route,\n fileHints: payload.context?.fileHints,\n },\n );\n};\n\nconst sanitizeAllowedPaths = (fileHints?: string[]) => {\n if (!fileHints?.length) {\n return null;\n }\n\n const sanitized = fileHints\n .map((value) => value.trim())\n .filter(Boolean)\n .filter((value) => value === \".\" || value === \"*\" || /^[A-Za-z0-9._-]+$/.test(value));\n\n return sanitized.length ? Array.from(new Set(sanitized)) : null;\n};\n\nconst toPatchSummary = (changedFiles: string[]) => {\n return changedFiles.length === 1\n ? \"1개 파일에 수정이 반영되었습니다.\"\n : `${changedFiles.length}개 파일에 수정이 반영되었습니다.`;\n};\n\nconst toEditPayload = (payload: ParsedEditPayload): ParsedEditPayload => {\n return payload;\n};\n\nconst isCopilotAgent = (value: string | null): value is CopilotAgent => {\n return value === \"codex\" || value === \"claude\";\n};\n\nconst resolveRequestedAgent = (\n config: DevCopilotBridgeConfig,\n requestAgent?: CopilotAgent,\n queryAgent?: string | null,\n): CopilotAgent => {\n if (requestAgent) {\n return requestAgent;\n }\n\n if (isCopilotAgent(queryAgent)) {\n return queryAgent;\n }\n\n return config.agent;\n};\n\nexport const createDevCopilotBridgeServer = (config: DevCopilotBridgeConfig) => {\n return createDevCopilotBridgeServerWithDependencies(config, { resolveAdapter: resolveAgentAdapter });\n};\n\nexport const createDevCopilotBridgeServerWithDependencies = (\n config: DevCopilotBridgeConfig,\n dependencies: {\n resolveAdapter: (agent: CopilotAgent) => AgentAdapter;\n },\n) => {\n const server = createServer(async (request, response) => {\n const method = request.method ?? \"GET\";\n const url = new URL(request.url ?? \"/\", `http://${config.host}:${config.port}`);\n\n if (method === \"OPTIONS\") {\n response.writeHead(204, createCorsHeaders(config));\n response.end();\n return;\n }\n\n try {\n if (method === \"GET\" && url.pathname === \"/status\") {\n const agent = resolveRequestedAgent(config, undefined, url.searchParams.get(\"agent\"));\n const adapter = dependencies.resolveAdapter(agent);\n\n sendJson(response, config, 200, await adapter.getStatus(config.rootDir));\n return;\n }\n\n if (method === \"POST\" && url.pathname === \"/chat\") {\n const payload = await readJsonBody<CopilotChatRequest>(request);\n const effectiveAllowedPaths =\n sanitizeAllowedPaths(payload.context?.fileHints) ?? config.allowedPaths;\n const agent = resolveRequestedAgent(config, payload.context?.agent);\n const adapter = dependencies.resolveAdapter(agent);\n\n if (!payload.prompt?.trim()) {\n sendJson(response, config, 400, { error: \"프롬프트를 입력해 주세요.\" });\n return;\n }\n\n const agentResponse = await adapter.run({\n selectedText: payload.selectedText ?? \"\",\n prompt: payload.prompt,\n mode: payload.mode,\n route: payload.context?.route,\n fileHints: payload.context?.fileHints,\n previousResponse: payload.context?.previousResponse,\n projectContext: await createProjectContext(config, payload, effectiveAllowedPaths),\n cwd: config.rootDir,\n });\n\n if (payload.mode === \"answer\") {\n const answerResponse: CopilotChatResponse = {\n message: agentResponse.message,\n warnings: agentResponse.warnings,\n };\n\n sendJson(response, config, 200, answerResponse);\n return;\n }\n\n const parsed = toEditPayload(agentResponse);\n let patchPreview = \"\";\n\n try {\n if (parsed.changes?.length) {\n patchPreview = await createPatchFromTextReplacements(\n parsed.changes,\n config.rootDir,\n (filePath) =>\n resolveAndValidatePath(filePath, effectiveAllowedPaths, config.rootDir),\n );\n }\n } catch (error) {\n const failedResponse: CopilotChatResponse = {\n message:\n parsed.message ??\n \"에이전트가 수정안을 만들었지만 실제 파일 내용과 매칭하지 못했습니다.\",\n warnings: [\n ...(parsed.warnings ?? []),\n error instanceof Error ? error.message : \"수정안 생성에 실패했습니다.\",\n ],\n };\n\n sendJson(response, config, 200, failedResponse);\n return;\n }\n\n if (!patchPreview) {\n const emptyPatchResponse: CopilotChatResponse = {\n message: parsed.message ?? \"패치 제안을 생성하지 못했습니다.\",\n warnings: [\n ...(parsed.warnings ?? []),\n \"적용 가능한 변경 목록이 없어 패치 미리보기와 적용 버튼을 만들 수 없습니다.\",\n ],\n };\n\n sendJson(response, config, 200, emptyPatchResponse);\n return;\n }\n\n try {\n validatePatchPaths(patchPreview, (filePath) =>\n resolveAndValidatePath(filePath, effectiveAllowedPaths, config.rootDir),\n );\n await checkUnifiedPatch(patchPreview, config.rootDir);\n } catch (error) {\n const invalidPatchResponse: CopilotChatResponse = {\n message:\n parsed.message ??\n \"에이전트가 수정안을 만들었지만 적용 가능한 diff 형식이 아닙니다.\",\n patchPreview,\n warnings: [\n ...(parsed.warnings ?? []),\n error instanceof Error ? error.message : \"patch 검증에 실패했습니다.\",\n ],\n };\n\n sendJson(response, config, 200, invalidPatchResponse);\n return;\n }\n\n const patch = createProposedPatch(patchPreview, effectiveAllowedPaths);\n const chatResponse: CopilotChatResponse = {\n message: parsed.message ?? \"에이전트가 패치 미리보기를 생성했습니다.\",\n patchPreview,\n patchId: patch.patchId,\n warnings: parsed.warnings ?? [],\n };\n\n sendJson(response, config, 200, chatResponse);\n return;\n }\n\n if (method === \"POST\" && url.pathname === \"/apply\") {\n const payload = await readJsonBody<CopilotApplyRequest>(request);\n\n if (!payload.patchId || !payload.approvalToken) {\n sendJson(response, config, 400, {\n error: \"patchId와 approvalToken이 필요합니다.\",\n });\n return;\n }\n\n const proposedPatch = getProposedPatch(payload.patchId, payload.approvalToken);\n\n if (!proposedPatch) {\n sendJson(response, config, 400, {\n error: \"유효하지 않거나 만료된 patchId입니다.\",\n });\n return;\n }\n\n validatePatchPaths(proposedPatch.patchPreview, (filePath) =>\n resolveAndValidatePath(\n filePath,\n proposedPatch.allowedPaths?.length\n ? proposedPatch.allowedPaths\n : config.allowedPaths,\n config.rootDir,\n ),\n );\n\n const result = await applyUnifiedPatch(\n proposedPatch.patchPreview,\n config.rootDir,\n \"local-codex-bridge\",\n );\n deleteProposedPatch(payload.patchId);\n\n const applyResponse: CopilotApplyResponse = {\n applied: true,\n changedFiles: result.changedFiles,\n summary: toPatchSummary(result.changedFiles),\n };\n\n sendJson(response, config, 200, applyResponse);\n return;\n }\n\n sendJson(response, config, 404, { error: \"지원하지 않는 경로입니다.\" });\n } catch (error) {\n sendJson(response, config, 500, {\n error:\n error instanceof Error\n ? error.message\n : \"브리지 서버 처리 중 오류가 발생했습니다.\",\n });\n }\n });\n\n return server;\n};\n","import { createDevCopilotBridgeConfig } from \"../lib/config\";\nimport { createDevCopilotBridgeServer } from \"../server/http-server\";\nimport type { CopilotAgent } from \"../types\";\n\nconst resolveAgent = (value: string | undefined): CopilotAgent => {\n if (value === \"claude\") {\n return \"claude\";\n }\n\n return \"codex\";\n};\n\nexport const runDevCopilotBridgeCli = async (argv: string[]) => {\n const portFlagIndex = argv.findIndex((value) => value === \"-p\");\n const portFlagValue =\n portFlagIndex >= 0 ? argv[portFlagIndex + 1] : undefined;\n const positionalPort = argv.find((value) => /^\\d+$/.test(value));\n const resolvedPort = portFlagValue\n ? Number(portFlagValue)\n : positionalPort\n ? Number(positionalPort)\n : Number(process.env.DEV_COPILOT_BRIDGE_PORT ?? 3339);\n const positionalAgent = argv.find((value) => value === \"codex\" || value === \"claude\");\n\n const config = createDevCopilotBridgeConfig({\n rootDir: process.cwd(),\n host: process.env.DEV_COPILOT_BRIDGE_HOST,\n port: Number.isFinite(resolvedPort) ? resolvedPort : 3339,\n corsOrigin: process.env.DEV_COPILOT_BRIDGE_CORS_ORIGIN ?? \"*\",\n agent: resolveAgent(positionalAgent),\n allowedPaths: (process.env.DEV_COPILOT_ALLOWED_PATHS ??\n \"app,src,widgets,features,entities,shared,components\")\n .split(\",\")\n .map((value) => value.trim())\n .filter(Boolean),\n });\n\n const server = createDevCopilotBridgeServer(config);\n\n await new Promise<void>((resolve) => {\n server.listen(config.port, config.host, () => {\n process.stdout.write(\n `[dev-copilot-bridge] listening on http://${config.host}:${config.port}\\n`,\n );\n resolve();\n });\n });\n};\n","#!/usr/bin/env node\n\nimport { runDevCopilotBridgeCli } from \"../bridge/cli/run-http\";\n\nrunDevCopilotBridgeCli(process.argv.slice(2)).catch((error) => {\n const message = error instanceof Error ? error.message : String(error);\n process.stderr.write(`[dev-copilot-bridge] ${message}\\n`);\n process.exit(1);\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"bridge.mjs","names":[],"sources":["../../src/bin/bridge.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { runDevCopilotBridgeCli } from \"../bridge/app/run-bridge-cli\";\n\nrunDevCopilotBridgeCli(process.argv.slice(2)).catch((error) => {\n const code =\n error && typeof error === \"object\" && \"code\" in error\n ? String((error as { code?: unknown }).code)\n : \"\";\n const message = error instanceof Error ? error.message : String(error);\n const normalized =\n code === \"EADDRINUSE\"\n ? \"요청한 브리지 포트가 이미 사용 중입니다. 포트를 변경해서 다시 실행해 주세요.\"\n : message;\n process.stderr.write(`[dev-copilot-bridge] ${normalized}\\n`);\n process.exit(1);\n});\n"],"mappings":";;;;AAIA,uBAAuB,QAAQ,KAAK,MAAM,EAAE,CAAC,CAAC,OAAO,UAAU;CAC7D,MAAM,OACJ,SAAS,OAAO,UAAU,YAAY,UAAU,QAC5C,OAAQ,MAA6B,KAAK,GAC1C;CACN,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;CACtE,MAAM,aACJ,SAAS,eACL,iDACA;AACN,SAAQ,OAAO,MAAM,wBAAwB,WAAW,IAAI;AAC5D,SAAQ,KAAK,EAAE;EACf"}
|
package/dist/bin/dev-copilot.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { spawnSync } from "node:child_process";
|
|
2
3
|
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
4
|
import { join } from "node:path";
|
|
4
5
|
import { fileURLToPath } from "node:url";
|
|
5
|
-
import { spawnSync } from "node:child_process";
|
|
6
6
|
|
|
7
7
|
//#region src/bin/init.ts
|
|
8
8
|
const PACKAGE_NAME = "@yr-kits/dev-copilot";
|
|
@@ -41,6 +41,14 @@ const getInstallCommand = (manager, spec) => {
|
|
|
41
41
|
};
|
|
42
42
|
}
|
|
43
43
|
};
|
|
44
|
+
const getRunScriptCommand = (manager, scriptName) => {
|
|
45
|
+
switch (manager) {
|
|
46
|
+
case "yarn": return `yarn ${scriptName}`;
|
|
47
|
+
case "bun": return `bun run ${scriptName}`;
|
|
48
|
+
case "pnpm": return `pnpm run ${scriptName}`;
|
|
49
|
+
default: return `npm run ${scriptName}`;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
44
52
|
const ensurePackageInstalled = (cwd, packageJson) => {
|
|
45
53
|
if (packageJson.dependencies?.[PACKAGE_NAME] || packageJson.devDependencies?.[PACKAGE_NAME]) {
|
|
46
54
|
process.stdout.write(`[dev-copilot:init] ${PACKAGE_NAME} 이미 설치되어 있습니다.\n`);
|
|
@@ -76,11 +84,13 @@ const runInitCommand = async (options = {}) => {
|
|
|
76
84
|
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
77
85
|
if (!options.skipInstall) ensurePackageInstalled(cwd, packageJson);
|
|
78
86
|
else process.stdout.write("[dev-copilot:init] --skip-install 옵션으로 설치 단계를 건너뜁니다.\n");
|
|
79
|
-
|
|
87
|
+
const refreshedPackageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
88
|
+
ensureBridgeScript(cwd, packageJsonPath, refreshedPackageJson);
|
|
89
|
+
const runBridgeCommand = getRunScriptCommand(detectPackageManager(cwd, refreshedPackageJson), SCRIPT_NAME);
|
|
80
90
|
process.stdout.write([
|
|
81
91
|
"",
|
|
82
92
|
"다음 단계",
|
|
83
|
-
`1.
|
|
93
|
+
`1. ${runBridgeCommand}`,
|
|
84
94
|
"2. React 트리에 DevCopilotProvider와 DevCopilotOverlay를 연결합니다.",
|
|
85
95
|
"3. 자세한 문서는 https://yr-kits.vercel.app/docs/dev-copilot/overview 를 확인합니다."
|
|
86
96
|
].join("\n") + "\n");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev-copilot.mjs","names":[],"sources":["../../src/bin/init.ts","../../src/bin/dev-copilot.ts"],"sourcesContent":["import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { spawnSync } from \"node:child_process\";\n\ninterface PackageJsonShape {\n name?: string;\n packageManager?: string;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n scripts?: Record<string, string>;\n}\n\ntype PackageManager = \"pnpm\" | \"npm\" | \"yarn\" | \"bun\";\n\ninterface InitCommandOptions {\n skipInstall?: boolean;\n}\n\nconst PACKAGE_NAME = \"@yr-kits/dev-copilot\";\nconst SCRIPT_NAME = \"dev-copilot-bridge\";\nconst SCRIPT_VALUE = \"dev-copilot-bridge\";\n\nconst readOwnVersion = () => {\n const packageJsonPath = fileURLToPath(\n new URL(\"../../package.json\", import.meta.url),\n );\n const content = readFileSync(packageJsonPath, \"utf-8\");\n const parsed = JSON.parse(content) as { version?: string };\n return parsed.version && parsed.version !== \"0.0.0\"\n ? parsed.version\n : \"latest\";\n};\n\nconst detectPackageManager = (cwd: string, packageJson: PackageJsonShape): PackageManager => {\n const declared = packageJson.packageManager?.split(\"@\")[0];\n\n if (declared === \"pnpm\" || declared === \"npm\" || declared === \"yarn\" || declared === \"bun\") {\n return declared;\n }\n\n if (existsSync(join(cwd, \"pnpm-lock.yaml\"))) {\n return \"pnpm\";\n }\n\n if (existsSync(join(cwd, \"yarn.lock\"))) {\n return \"yarn\";\n }\n\n if (existsSync(join(cwd, \"bun.lockb\")) || existsSync(join(cwd, \"bun.lock\"))) {\n return \"bun\";\n }\n\n return \"npm\";\n};\n\nconst getInstallCommand = (manager: PackageManager, spec: string) => {\n switch (manager) {\n case \"pnpm\":\n return { command: \"pnpm\", args: [\"add\", spec] };\n case \"yarn\":\n return { command: \"yarn\", args: [\"add\", spec] };\n case \"bun\":\n return { command: \"bun\", args: [\"add\", spec] };\n case \"npm\":\n default:\n return { command: \"npm\", args: [\"install\", spec] };\n }\n};\n\nconst ensurePackageInstalled = (cwd: string, packageJson: PackageJsonShape) => {\n const installed =\n packageJson.dependencies?.[PACKAGE_NAME] ||\n packageJson.devDependencies?.[PACKAGE_NAME];\n\n if (installed) {\n process.stdout.write(`[dev-copilot:init] ${PACKAGE_NAME} 이미 설치되어 있습니다.\\n`);\n return;\n }\n\n const manager = detectPackageManager(cwd, packageJson);\n const version = readOwnVersion();\n const spec = `${PACKAGE_NAME}@${version}`;\n const install = getInstallCommand(manager, spec);\n\n process.stdout.write(\n `[dev-copilot:init] ${manager}로 ${spec} 설치를 시작합니다.\\n`,\n );\n\n const result = spawnSync(install.command, install.args, {\n cwd,\n stdio: \"inherit\",\n shell: process.platform === \"win32\",\n });\n\n if (result.status !== 0) {\n throw new Error(`${PACKAGE_NAME} 설치에 실패했습니다.`);\n }\n};\n\nconst ensureBridgeScript = (cwd: string, packageJsonPath: string, packageJson: PackageJsonShape) => {\n const nextPackageJson: PackageJsonShape = {\n ...packageJson,\n scripts: {\n ...(packageJson.scripts ?? {}),\n },\n };\n\n if (!nextPackageJson.scripts?.[SCRIPT_NAME]) {\n nextPackageJson.scripts![SCRIPT_NAME] = SCRIPT_VALUE;\n writeFileSync(packageJsonPath, `${JSON.stringify(nextPackageJson, null, 2)}\\n`, \"utf-8\");\n process.stdout.write(\n `[dev-copilot:init] package.json scripts에 \\\"${SCRIPT_NAME}\\\"를 추가했습니다.\\n`,\n );\n return;\n }\n\n process.stdout.write(\n `[dev-copilot:init] package.json scripts에 이미 \\\"${SCRIPT_NAME}\\\"가 있습니다.\\n`,\n );\n};\n\nexport const runInitCommand = async (options: InitCommandOptions = {}) => {\n const cwd = process.cwd();\n const packageJsonPath = join(cwd, \"package.json\");\n\n if (!existsSync(packageJsonPath)) {\n throw new Error(\"현재 디렉터리에 package.json이 없습니다.\");\n }\n\n const packageJson = JSON.parse(\n readFileSync(packageJsonPath, \"utf-8\"),\n ) as PackageJsonShape;\n\n if (!options.skipInstall) {\n ensurePackageInstalled(cwd, packageJson);\n } else {\n process.stdout.write(\"[dev-copilot:init] --skip-install 옵션으로 설치 단계를 건너뜁니다.\\n\");\n }\n\n const refreshedPackageJson = JSON.parse(\n readFileSync(packageJsonPath, \"utf-8\"),\n ) as PackageJsonShape;\n\n ensureBridgeScript(cwd, packageJsonPath, refreshedPackageJson);\n\n process.stdout.write(\n [\n \"\",\n \"다음 단계\",\n `1.
|
|
1
|
+
{"version":3,"file":"dev-copilot.mjs","names":[],"sources":["../../src/bin/init.ts","../../src/bin/dev-copilot.ts"],"sourcesContent":["import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { spawnSync } from \"node:child_process\";\n\ninterface PackageJsonShape {\n name?: string;\n packageManager?: string;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n scripts?: Record<string, string>;\n}\n\ntype PackageManager = \"pnpm\" | \"npm\" | \"yarn\" | \"bun\";\n\ninterface InitCommandOptions {\n skipInstall?: boolean;\n}\n\nconst PACKAGE_NAME = \"@yr-kits/dev-copilot\";\nconst SCRIPT_NAME = \"dev-copilot-bridge\";\nconst SCRIPT_VALUE = \"dev-copilot-bridge\";\n\nconst readOwnVersion = () => {\n const packageJsonPath = fileURLToPath(\n new URL(\"../../package.json\", import.meta.url),\n );\n const content = readFileSync(packageJsonPath, \"utf-8\");\n const parsed = JSON.parse(content) as { version?: string };\n return parsed.version && parsed.version !== \"0.0.0\"\n ? parsed.version\n : \"latest\";\n};\n\nconst detectPackageManager = (cwd: string, packageJson: PackageJsonShape): PackageManager => {\n const declared = packageJson.packageManager?.split(\"@\")[0];\n\n if (declared === \"pnpm\" || declared === \"npm\" || declared === \"yarn\" || declared === \"bun\") {\n return declared;\n }\n\n if (existsSync(join(cwd, \"pnpm-lock.yaml\"))) {\n return \"pnpm\";\n }\n\n if (existsSync(join(cwd, \"yarn.lock\"))) {\n return \"yarn\";\n }\n\n if (existsSync(join(cwd, \"bun.lockb\")) || existsSync(join(cwd, \"bun.lock\"))) {\n return \"bun\";\n }\n\n return \"npm\";\n};\n\nconst getInstallCommand = (manager: PackageManager, spec: string) => {\n switch (manager) {\n case \"pnpm\":\n return { command: \"pnpm\", args: [\"add\", spec] };\n case \"yarn\":\n return { command: \"yarn\", args: [\"add\", spec] };\n case \"bun\":\n return { command: \"bun\", args: [\"add\", spec] };\n case \"npm\":\n default:\n return { command: \"npm\", args: [\"install\", spec] };\n }\n};\n\nconst getRunScriptCommand = (manager: PackageManager, scriptName: string) => {\n switch (manager) {\n case \"yarn\":\n return `yarn ${scriptName}`;\n case \"bun\":\n return `bun run ${scriptName}`;\n case \"pnpm\":\n return `pnpm run ${scriptName}`;\n case \"npm\":\n default:\n return `npm run ${scriptName}`;\n }\n};\n\nconst ensurePackageInstalled = (cwd: string, packageJson: PackageJsonShape) => {\n const installed =\n packageJson.dependencies?.[PACKAGE_NAME] ||\n packageJson.devDependencies?.[PACKAGE_NAME];\n\n if (installed) {\n process.stdout.write(`[dev-copilot:init] ${PACKAGE_NAME} 이미 설치되어 있습니다.\\n`);\n return;\n }\n\n const manager = detectPackageManager(cwd, packageJson);\n const version = readOwnVersion();\n const spec = `${PACKAGE_NAME}@${version}`;\n const install = getInstallCommand(manager, spec);\n\n process.stdout.write(\n `[dev-copilot:init] ${manager}로 ${spec} 설치를 시작합니다.\\n`,\n );\n\n const result = spawnSync(install.command, install.args, {\n cwd,\n stdio: \"inherit\",\n shell: process.platform === \"win32\",\n });\n\n if (result.status !== 0) {\n throw new Error(`${PACKAGE_NAME} 설치에 실패했습니다.`);\n }\n};\n\nconst ensureBridgeScript = (cwd: string, packageJsonPath: string, packageJson: PackageJsonShape) => {\n const nextPackageJson: PackageJsonShape = {\n ...packageJson,\n scripts: {\n ...(packageJson.scripts ?? {}),\n },\n };\n\n if (!nextPackageJson.scripts?.[SCRIPT_NAME]) {\n nextPackageJson.scripts![SCRIPT_NAME] = SCRIPT_VALUE;\n writeFileSync(packageJsonPath, `${JSON.stringify(nextPackageJson, null, 2)}\\n`, \"utf-8\");\n process.stdout.write(\n `[dev-copilot:init] package.json scripts에 \\\"${SCRIPT_NAME}\\\"를 추가했습니다.\\n`,\n );\n return;\n }\n\n process.stdout.write(\n `[dev-copilot:init] package.json scripts에 이미 \\\"${SCRIPT_NAME}\\\"가 있습니다.\\n`,\n );\n};\n\nexport const runInitCommand = async (options: InitCommandOptions = {}) => {\n const cwd = process.cwd();\n const packageJsonPath = join(cwd, \"package.json\");\n\n if (!existsSync(packageJsonPath)) {\n throw new Error(\"현재 디렉터리에 package.json이 없습니다.\");\n }\n\n const packageJson = JSON.parse(\n readFileSync(packageJsonPath, \"utf-8\"),\n ) as PackageJsonShape;\n\n if (!options.skipInstall) {\n ensurePackageInstalled(cwd, packageJson);\n } else {\n process.stdout.write(\"[dev-copilot:init] --skip-install 옵션으로 설치 단계를 건너뜁니다.\\n\");\n }\n\n const refreshedPackageJson = JSON.parse(\n readFileSync(packageJsonPath, \"utf-8\"),\n ) as PackageJsonShape;\n\n ensureBridgeScript(cwd, packageJsonPath, refreshedPackageJson);\n const manager = detectPackageManager(cwd, refreshedPackageJson);\n const runBridgeCommand = getRunScriptCommand(manager, SCRIPT_NAME);\n\n process.stdout.write(\n [\n \"\",\n \"다음 단계\",\n `1. ${runBridgeCommand}`,\n \"2. React 트리에 DevCopilotProvider와 DevCopilotOverlay를 연결합니다.\",\n \"3. 자세한 문서는 https://yr-kits.vercel.app/docs/dev-copilot/overview 를 확인합니다.\",\n ].join(\"\\n\") + \"\\n\",\n );\n};\n","#!/usr/bin/env node\n\nimport { runInitCommand } from \"./init\";\n\nconst printHelp = () => {\n process.stdout.write(\n [\n \"@yr-kits/dev-copilot\",\n \"\",\n \"사용법:\",\n \" npx @yr-kits/dev-copilot init [--skip-install]\",\n \"\",\n \"명령:\",\n \" init 현재 프로젝트에 패키지를 설치하고 bridge 스크립트를 추가합니다.\",\n \"\",\n \"옵션:\",\n \" --skip-install 패키지 설치 단계를 건너뛰고 scripts만 추가합니다.\",\n ].join(\"\\n\") + \"\\n\",\n );\n};\n\nconst [command, ...restArgs] = process.argv.slice(2);\n\nif (!command || command === \"--help\" || command === \"-h\") {\n printHelp();\n process.exit(0);\n}\n\nif (command === \"init\") {\n runInitCommand({\n skipInstall: restArgs.includes(\"--skip-install\"),\n }).catch((error) => {\n const message = error instanceof Error ? error.message : String(error);\n process.stderr.write(`[dev-copilot:init] ${message}\\n`);\n process.exit(1);\n });\n} else {\n printHelp();\n process.exit(1);\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { t as CopilotAgent } from "../../copilot-D8--qKgC.mjs";
|
|
2
|
+
import * as http from "http";
|
|
3
|
+
|
|
4
|
+
//#region src/bridge/shared/config/bridge-config.d.ts
|
|
5
|
+
interface DevCopilotBridgeConfig {
|
|
6
|
+
rootDir: string;
|
|
7
|
+
host: string;
|
|
8
|
+
port: number;
|
|
9
|
+
corsOrigin: string;
|
|
10
|
+
agent: CopilotAgent;
|
|
11
|
+
allowedPaths: string[];
|
|
12
|
+
}
|
|
13
|
+
declare const createDevCopilotBridgeConfig: (config: Partial<DevCopilotBridgeConfig> & {
|
|
14
|
+
rootDir: string;
|
|
15
|
+
}) => DevCopilotBridgeConfig;
|
|
16
|
+
//#endregion
|
|
17
|
+
//#region src/bridge/app/create-bridge-server.d.ts
|
|
18
|
+
declare const createDevCopilotBridgeServer: (config: DevCopilotBridgeConfig) => http.Server<typeof http.IncomingMessage, typeof http.ServerResponse>;
|
|
19
|
+
//#endregion
|
|
20
|
+
//#region src/bridge/app/run-bridge-cli.d.ts
|
|
21
|
+
declare const runDevCopilotBridgeCli: (argv: string[]) => Promise<void>;
|
|
22
|
+
//#endregion
|
|
23
|
+
export { type DevCopilotBridgeConfig, createDevCopilotBridgeConfig, createDevCopilotBridgeServer, runDevCopilotBridgeCli };
|
|
24
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../../src/bridge/shared/config/bridge-config.ts","../../../src/bridge/app/create-bridge-server.ts","../../../src/bridge/app/run-bridge-cli.ts"],"mappings":";;;;UAEiB,sBAAA;EACf,OAAA;EACA,IAAA;EACA,IAAA;EACA,UAAA;EACA,KAAA,EAAO,YAAA;EACP,YAAA;AAAA;AAAA,cAaW,4BAAA,GACX,MAAA,EAAQ,OAAA,CAAQ,sBAAA;EAA4B,OAAA;AAAA,MAC3C,sBAAA;;;cCdU,4BAAA,GAAgC,MAAA,EAAQ,sBAAA,KAAsB,IAAA,CAAA,MAAA,QAAA,IAAA,CAAA,eAAA,SAAA,IAAA,CAAA,cAAA;;;cCI9D,sBAAA,GAAgC,IAAA,eAAc,OAAA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//#region src/
|
|
1
|
+
//#region src/shared/contracts/copilot.d.ts
|
|
2
2
|
type CopilotMode = "answer" | "edit";
|
|
3
3
|
type CopilotAgent = "codex" | "claude";
|
|
4
4
|
interface CopilotChatRequest {
|
|
@@ -39,5 +39,5 @@ interface CopilotErrorResponse {
|
|
|
39
39
|
error: string;
|
|
40
40
|
}
|
|
41
41
|
//#endregion
|
|
42
|
-
export {
|
|
43
|
-
//# sourceMappingURL=
|
|
42
|
+
export { CopilotChatRequest as a, CopilotMode as c, CopilotApplyResponse as i, CopilotAgentStatusResponse as n, CopilotChatResponse as o, CopilotApplyRequest as r, CopilotErrorResponse as s, CopilotAgent as t };
|
|
43
|
+
//# sourceMappingURL=copilot-D8--qKgC.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"copilot-D8--qKgC.d.mts","names":[],"sources":["../src/shared/contracts/copilot.ts"],"mappings":";KAAY,WAAA;AAAA,KACA,YAAA;AAAA,UAEK,kBAAA;EACf,YAAA;EACA,MAAA;EACA,IAAA,EAAM,WAAA;EACN,OAAA;IACE,KAAA;IACA,SAAA;IACA,gBAAA;IACA,KAAA,GAAQ,YAAA;EAAA;AAAA;AAAA,UAIK,mBAAA;EACf,OAAA;EACA,aAAA;AAAA;AAAA,UAGe,mBAAA;EACf,OAAA;EACA,YAAA;EACA,OAAA;EACA,QAAA;AAAA;AAAA,UAGe,oBAAA;EACf,OAAA;EACA,YAAA;EACA,OAAA;AAAA;AAAA,UAGe,0BAAA;EACf,SAAA;EACA,aAAA;EACA,KAAA,EAAO,YAAA;EACP,OAAA;EACA,KAAA;EACA,YAAA;AAAA;AAAA,UAGe,oBAAA;EACf,KAAA;AAAA"}
|