@adhdev/daemon-core 0.6.53 → 0.6.56

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.
Files changed (164) hide show
  1. package/dist/index.d.ts +84 -34
  2. package/dist/index.js +631 -305
  3. package/dist/index.js.map +1 -1
  4. package/package.json +2 -1
  5. package/providers/_builtin/_helpers/index.js +26 -26
  6. package/providers/_builtin/cli/aider-cli/provider.json +37 -0
  7. package/providers/_builtin/cli/aider-cli/scripts/1.0/detect_status.js +20 -0
  8. package/providers/_builtin/cli/aider-cli/scripts/1.0/parse_approval.js +10 -0
  9. package/providers/_builtin/cli/aider-cli/scripts/1.0/parse_output.js +49 -0
  10. package/providers/_builtin/cli/aider-cli/scripts/1.0/scripts.js +7 -0
  11. package/providers/_builtin/cli/claude-cli/provider.json +9 -2
  12. package/providers/_builtin/cli/claude-cli/scripts/1.0/detect_status.js +31 -0
  13. package/providers/_builtin/cli/claude-cli/scripts/1.0/parse_approval.js +38 -0
  14. package/providers/_builtin/cli/claude-cli/scripts/1.0/parse_output.js +164 -0
  15. package/providers/_builtin/cli/claude-cli/scripts/1.0/scripts.js +42 -0
  16. package/providers/_builtin/cli/codex-cli/provider.json +9 -2
  17. package/providers/_builtin/cli/codex-cli/scripts/1.0/detect_status.js +20 -0
  18. package/providers/_builtin/cli/codex-cli/scripts/1.0/parse_approval.js +15 -0
  19. package/providers/_builtin/cli/codex-cli/scripts/1.0/parse_output.js +68 -0
  20. package/providers/_builtin/cli/codex-cli/scripts/1.0/scripts.js +11 -0
  21. package/providers/_builtin/cli/cursor-cli/provider.json +37 -0
  22. package/providers/_builtin/cli/cursor-cli/scripts/1.0/detect_status.js +19 -0
  23. package/providers/_builtin/cli/cursor-cli/scripts/1.0/parse_approval.js +10 -0
  24. package/providers/_builtin/cli/cursor-cli/scripts/1.0/parse_output.js +48 -0
  25. package/providers/_builtin/cli/cursor-cli/scripts/1.0/scripts.js +7 -0
  26. package/providers/_builtin/cli/gemini-cli/provider.json +9 -2
  27. package/providers/_builtin/cli/gemini-cli/scripts/1.0/detect_status.js +26 -0
  28. package/providers/_builtin/cli/gemini-cli/scripts/1.0/parse_approval.js +22 -0
  29. package/providers/_builtin/cli/gemini-cli/scripts/1.0/parse_output.js +71 -0
  30. package/providers/_builtin/cli/gemini-cli/scripts/1.0/scripts.js +12 -0
  31. package/providers/_builtin/cli/github-copilot-cli/provider.json +37 -0
  32. package/providers/_builtin/cli/github-copilot-cli/scripts/1.0/detect_status.js +19 -0
  33. package/providers/_builtin/cli/github-copilot-cli/scripts/1.0/parse_approval.js +9 -0
  34. package/providers/_builtin/cli/github-copilot-cli/scripts/1.0/parse_output.js +48 -0
  35. package/providers/_builtin/cli/github-copilot-cli/scripts/1.0/scripts.js +7 -0
  36. package/providers/_builtin/cli/goose-cli/provider.json +37 -0
  37. package/providers/_builtin/cli/goose-cli/scripts/1.0/detect_status.js +20 -0
  38. package/providers/_builtin/cli/goose-cli/scripts/1.0/parse_approval.js +10 -0
  39. package/providers/_builtin/cli/goose-cli/scripts/1.0/parse_output.js +48 -0
  40. package/providers/_builtin/cli/goose-cli/scripts/1.0/scripts.js +7 -0
  41. package/providers/_builtin/cli/opencode-cli/provider.json +37 -0
  42. package/providers/_builtin/cli/opencode-cli/scripts/1.0/detect_status.js +15 -0
  43. package/providers/_builtin/cli/opencode-cli/scripts/1.0/parse_approval.js +9 -0
  44. package/providers/_builtin/cli/opencode-cli/scripts/1.0/parse_output.js +48 -0
  45. package/providers/_builtin/cli/opencode-cli/scripts/1.0/scripts.js +7 -0
  46. package/providers/_builtin/extension/cline/scripts/1.0/focus_editor.js +5 -5
  47. package/providers/_builtin/extension/cline/scripts/1.0/list_chats.js +11 -11
  48. package/providers/_builtin/extension/cline/scripts/1.0/list_models.js +6 -6
  49. package/providers/_builtin/extension/cline/scripts/1.0/list_modes.js +5 -5
  50. package/providers/_builtin/extension/cline/scripts/1.0/new_session.js +12 -12
  51. package/providers/_builtin/extension/cline/scripts/1.0/open_panel.js +7 -7
  52. package/providers/_builtin/extension/cline/scripts/1.0/read_chat.js +29 -29
  53. package/providers/_builtin/extension/cline/scripts/1.0/resolve_action.js +19 -19
  54. package/providers/_builtin/extension/cline/scripts/1.0/send_message.js +15 -15
  55. package/providers/_builtin/extension/cline/scripts/1.0/set_mode.js +4 -4
  56. package/providers/_builtin/extension/cline/scripts/1.0/set_model.js +4 -4
  57. package/providers/_builtin/extension/cline/scripts/1.0/switch_session.js +21 -21
  58. package/providers/_builtin/extension/codex/scripts/1.0/explore_controls_webview.js +2 -2
  59. package/providers/_builtin/extension/codex/scripts/1.0/list_models.js +1 -1
  60. package/providers/_builtin/extension/codex/scripts/1.0/list_modes.js +1 -1
  61. package/providers/_builtin/extension/codex/scripts/1.0/new_session.js +2 -2
  62. package/providers/_builtin/extension/codex/scripts/1.0/read_chat.js +6 -6
  63. package/providers/_builtin/extension/codex/scripts/1.0/resolve_action.js +3 -3
  64. package/providers/_builtin/extension/codex/scripts/1.0/set_model.js +1 -1
  65. package/providers/_builtin/ide/antigravity/scripts/1.0/focus_editor.js +2 -2
  66. package/providers/_builtin/ide/antigravity/scripts/1.0/list_chats.js +19 -19
  67. package/providers/_builtin/ide/antigravity/scripts/1.0/list_models.js +1 -1
  68. package/providers/_builtin/ide/antigravity/scripts/1.0/list_modes.js +1 -1
  69. package/providers/_builtin/ide/antigravity/scripts/1.0/new_session.js +17 -17
  70. package/providers/_builtin/ide/antigravity/scripts/1.0/read_chat.js +41 -41
  71. package/providers/_builtin/ide/antigravity/scripts/1.0/resolve_action.js +6 -6
  72. package/providers/_builtin/ide/antigravity/scripts/1.0/send_message.js +13 -13
  73. package/providers/_builtin/ide/antigravity/scripts/1.0/set_model.js +1 -1
  74. package/providers/_builtin/ide/antigravity/scripts/1.0/switch_session.js +13 -13
  75. package/providers/_builtin/ide/cursor/scripts/1.0/dismiss_notification.js +3 -3
  76. package/providers/_builtin/ide/cursor/scripts/1.0/focus_editor.js +1 -1
  77. package/providers/_builtin/ide/cursor/scripts/1.0/list_models.js +12 -12
  78. package/providers/_builtin/ide/cursor/scripts/1.0/list_modes.js +5 -5
  79. package/providers/_builtin/ide/cursor/scripts/1.0/list_notifications.js +2 -2
  80. package/providers/_builtin/ide/cursor/scripts/1.0/list_sessions.js +5 -5
  81. package/providers/_builtin/ide/cursor/scripts/1.0/new_session.js +1 -1
  82. package/providers/_builtin/ide/cursor/scripts/1.0/open_panel.js +3 -3
  83. package/providers/_builtin/ide/cursor/scripts/1.0/read_chat.js +9 -9
  84. package/providers/_builtin/ide/cursor/scripts/1.0/resolve_action.js +4 -4
  85. package/providers/_builtin/ide/cursor/scripts/1.0/send_message.js +5 -5
  86. package/providers/_builtin/ide/cursor/scripts/1.0/set_mode.js +4 -4
  87. package/providers/_builtin/ide/cursor/scripts/1.0/set_model.js +12 -12
  88. package/providers/_builtin/ide/cursor/scripts/1.0/switch_session.js +2 -2
  89. package/providers/_builtin/ide/kiro/scripts/1.0/focus_editor.js +2 -2
  90. package/providers/_builtin/ide/kiro/scripts/1.0/open_panel.js +7 -7
  91. package/providers/_builtin/ide/kiro/scripts/1.0/resolve_action.js +3 -3
  92. package/providers/_builtin/ide/kiro/scripts/1.0/send_message.js +4 -4
  93. package/providers/_builtin/ide/kiro/scripts/1.0/webview_list_sessions.js +2 -2
  94. package/providers/_builtin/ide/kiro/scripts/1.0/webview_new_session.js +5 -5
  95. package/providers/_builtin/ide/kiro/scripts/1.0/webview_read_chat.js +13 -13
  96. package/providers/_builtin/ide/kiro/scripts/1.0/webview_resolve_action.js +1 -1
  97. package/providers/_builtin/ide/kiro/scripts/1.0/webview_send_message.js +8 -8
  98. package/providers/_builtin/ide/kiro/scripts/1.0/webview_set_mode.js +1 -1
  99. package/providers/_builtin/ide/kiro/scripts/1.0/webview_set_model.js +1 -1
  100. package/providers/_builtin/ide/kiro/scripts/1.0/webview_switch_session.js +3 -3
  101. package/providers/_builtin/ide/pearai/.tmp/after_rich.json +157 -0
  102. package/providers/_builtin/ide/pearai/.tmp/after_rich_raw.json +161 -0
  103. package/providers/_builtin/ide/pearai/.tmp/after_switch.json +592 -0
  104. package/providers/_builtin/ide/pearai/.tmp/after_switch_raw.json +596 -0
  105. package/providers/_builtin/ide/pearai/.tmp/home_dump_raw.json +176 -0
  106. package/providers/_builtin/ide/pearai/.tmp/items_raw.json +778 -0
  107. package/providers/_builtin/ide/pearai/.tmp/webview_dump.json +157 -0
  108. package/providers/_builtin/ide/pearai/.tmp/webview_dump_raw.json +161 -0
  109. package/providers/_builtin/ide/pearai/provider.json +1 -3
  110. package/providers/_builtin/ide/pearai/scripts/1.0/focus_editor.js +12 -16
  111. package/providers/_builtin/ide/pearai/scripts/1.0/list_models.js +45 -0
  112. package/providers/_builtin/ide/pearai/scripts/1.0/list_modes.js +44 -0
  113. package/providers/_builtin/ide/pearai/scripts/1.0/list_sessions.js +82 -27
  114. package/providers/_builtin/ide/pearai/scripts/1.0/new_session.js +26 -43
  115. package/providers/_builtin/ide/pearai/scripts/1.0/open_panel.js +10 -33
  116. package/providers/_builtin/ide/pearai/scripts/1.0/read_chat.js +169 -0
  117. package/providers/_builtin/ide/pearai/scripts/1.0/resolve_action.js +47 -41
  118. package/providers/_builtin/ide/pearai/scripts/1.0/scripts.js +36 -7
  119. package/providers/_builtin/ide/pearai/scripts/1.0/send_message.js +97 -22
  120. package/providers/_builtin/ide/pearai/scripts/1.0/set_mode.js +51 -0
  121. package/providers/_builtin/ide/pearai/scripts/1.0/set_model.js +54 -0
  122. package/providers/_builtin/ide/pearai/scripts/1.0/switch_session.js +81 -0
  123. package/providers/_builtin/ide/trae/scripts/1.0/focus_editor.js +2 -2
  124. package/providers/_builtin/ide/trae/scripts/1.0/list_chats.js +2 -2
  125. package/providers/_builtin/ide/trae/scripts/1.0/new_session.js +4 -4
  126. package/providers/_builtin/ide/trae/scripts/1.0/open_panel.js +6 -6
  127. package/providers/_builtin/ide/trae/scripts/1.0/read_chat.js +13 -13
  128. package/providers/_builtin/ide/trae/scripts/1.0/resolve_action.js +3 -3
  129. package/providers/_builtin/ide/trae/scripts/1.0/send_message.js +11 -11
  130. package/providers/_builtin/ide/trae/scripts/1.0/switch_session.js +2 -2
  131. package/providers/_builtin/ide/windsurf/scripts/1.0/focus_editor.js +6 -6
  132. package/providers/_builtin/ide/windsurf/scripts/1.0/list_chats.js +4 -4
  133. package/providers/_builtin/ide/windsurf/scripts/1.0/list_sessions.js +6 -6
  134. package/providers/_builtin/ide/windsurf/scripts/1.0/new_session.js +9 -9
  135. package/providers/_builtin/ide/windsurf/scripts/1.0/open_panel.js +6 -6
  136. package/providers/_builtin/ide/windsurf/scripts/1.0/resolve_action.js +8 -8
  137. package/providers/_builtin/ide/windsurf/scripts/1.0/switch_session.js +8 -8
  138. package/providers/_builtin/ide/windsurf/scripts/1.0.bak/focus_editor.js +6 -6
  139. package/providers/_builtin/ide/windsurf/scripts/1.0.bak/list_chats.js +12 -12
  140. package/providers/_builtin/ide/windsurf/scripts/1.0.bak/new_session.js +15 -15
  141. package/providers/_builtin/ide/windsurf/scripts/1.0.bak/open_panel.js +10 -10
  142. package/providers/_builtin/ide/windsurf/scripts/1.0.bak/read_chat.js +33 -33
  143. package/providers/_builtin/ide/windsurf/scripts/1.0.bak/resolve_action.js +6 -6
  144. package/providers/_builtin/ide/windsurf/scripts/1.0.bak/send_message.js +16 -16
  145. package/providers/_builtin/ide/windsurf/scripts/1.0.bak/switch_session.js +7 -7
  146. package/providers/_builtin/registry.json +76 -3
  147. package/src/cli-adapters/provider-cli-adapter.ts +312 -258
  148. package/src/cli-adapters/terminal-screen.ts +95 -0
  149. package/src/commands/chat-commands.ts +41 -15
  150. package/src/commands/cli-manager.ts +4 -2
  151. package/src/daemon/dev-server.ts +306 -62
  152. package/src/providers/acp-provider-instance.ts +1 -1
  153. package/src/providers/cli-provider-instance.ts +23 -9
  154. package/src/providers/provider-loader.ts +3 -2
  155. package/providers/_builtin/ide/pearai/scripts/1.0/webview_list_models.js +0 -43
  156. package/providers/_builtin/ide/pearai/scripts/1.0/webview_list_modes.js +0 -35
  157. package/providers/_builtin/ide/pearai/scripts/1.0/webview_list_sessions.js +0 -62
  158. package/providers/_builtin/ide/pearai/scripts/1.0/webview_new_session.js +0 -49
  159. package/providers/_builtin/ide/pearai/scripts/1.0/webview_read_chat.js +0 -92
  160. package/providers/_builtin/ide/pearai/scripts/1.0/webview_resolve_action.js +0 -59
  161. package/providers/_builtin/ide/pearai/scripts/1.0/webview_send_message.js +0 -72
  162. package/providers/_builtin/ide/pearai/scripts/1.0/webview_set_mode.js +0 -36
  163. package/providers/_builtin/ide/pearai/scripts/1.0/webview_set_model.js +0 -36
  164. package/providers/_builtin/ide/pearai/scripts/1.0/webview_switch_session.js +0 -34
@@ -1866,6 +1866,51 @@ export class DevServer {
1866
1866
 
1867
1867
  // ─── Phase 2: Auto-Implement Backend ───
1868
1868
 
1869
+ private getDefaultAutoImplReference(category: string, type: string): string {
1870
+ if (category === 'cli') {
1871
+ return type === 'codex-cli' ? 'claude-cli' : 'codex-cli';
1872
+ }
1873
+ return 'antigravity';
1874
+ }
1875
+
1876
+ private resolveAutoImplReference(category: string, requestedReference: string | undefined, targetType: string): string | null {
1877
+ const desired = requestedReference || this.getDefaultAutoImplReference(category, targetType);
1878
+ const ref = this.providerLoader.resolve(desired) || this.providerLoader.getMeta(desired);
1879
+ if (ref?.category === category) return desired;
1880
+
1881
+ const all = this.providerLoader.getAll();
1882
+ const fallback = all.find((p: any) => p.category === category && p.type !== targetType);
1883
+ return fallback?.type || null;
1884
+ }
1885
+
1886
+ private loadAutoImplReferenceScripts(category: string, referenceType: string | null): Record<string, string> {
1887
+ if (!referenceType) return {};
1888
+
1889
+ const builtinDir = this.providerLoader.getPrimaryBuiltinDir();
1890
+ const refDir = path.join(builtinDir, category, referenceType);
1891
+ if (!fs.existsSync(refDir)) return {};
1892
+
1893
+ const referenceScripts: Record<string, string> = {};
1894
+ const scriptsDir = path.join(refDir, 'scripts');
1895
+ if (!fs.existsSync(scriptsDir)) return referenceScripts;
1896
+
1897
+ const versions = fs.readdirSync(scriptsDir).filter((d: string) => {
1898
+ try { return fs.statSync(path.join(scriptsDir, d)).isDirectory(); } catch { return false; }
1899
+ }).sort().reverse();
1900
+ if (versions.length === 0) return referenceScripts;
1901
+
1902
+ const latestDir = path.join(scriptsDir, versions[0]);
1903
+ for (const file of fs.readdirSync(latestDir)) {
1904
+ if (!file.endsWith('.js')) continue;
1905
+ try {
1906
+ referenceScripts[file] = fs.readFileSync(path.join(latestDir, file), 'utf-8');
1907
+ } catch {
1908
+ // ignore broken reference files
1909
+ }
1910
+ }
1911
+ return referenceScripts;
1912
+ }
1913
+
1869
1914
  private async handleAutoImplement(type: string, req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {
1870
1915
  const body = await this.readBody(req);
1871
1916
  const { agent = 'claude-cli', functions, reference = 'antigravity', model, comment } = body;
@@ -1888,37 +1933,33 @@ export class DevServer {
1888
1933
  try {
1889
1934
  // 1. Collect DOM context
1890
1935
  // 1. Skip heavy DOM pre-parsing (Agent will use cURL to explore via CDP!)
1891
- this.sendAutoImplSSE({ event: 'progress', data: { function: '_init', status: 'analyzing', message: '에이전트 초기화 (DOM 탐색 권한 부여)...' } });
1936
+ const resolvedReference = this.resolveAutoImplReference(provider.category, reference, type);
1937
+ this.sendAutoImplSSE({
1938
+ event: 'progress',
1939
+ data: {
1940
+ function: '_init',
1941
+ status: 'analyzing',
1942
+ message: provider.category === 'cli'
1943
+ ? 'Initializing agent (granting CLI PTY debug access)...'
1944
+ : 'Initializing agent (granting DOM access)...'
1945
+ }
1946
+ });
1892
1947
  const domContext = null;
1893
1948
 
1894
1949
  // 2. Load reference scripts
1895
- this.sendAutoImplSSE({ event: 'progress', data: { function: '_init', status: 'loading_reference', message: `레퍼런스 스크립트 로드 중 (${reference})...` } });
1896
-
1897
- let referenceScripts: Record<string, string> = {};
1898
- const builtinDir = this.providerLoader.getPrimaryBuiltinDir();
1899
- const refDir = path.join(builtinDir, 'ide', reference);
1900
- if (fs.existsSync(refDir)) {
1901
- // Find latest versioned scripts dir
1902
- const scriptsDir = path.join(refDir, 'scripts');
1903
- if (fs.existsSync(scriptsDir)) {
1904
- const versions = fs.readdirSync(scriptsDir).filter((d: string) => {
1905
- try { return fs.statSync(path.join(scriptsDir, d)).isDirectory(); } catch { return false; }
1906
- }).sort().reverse();
1907
- if (versions.length > 0) {
1908
- const latestDir = path.join(scriptsDir, versions[0]);
1909
- for (const file of fs.readdirSync(latestDir)) {
1910
- if (file.endsWith('.js')) {
1911
- try {
1912
- referenceScripts[file] = fs.readFileSync(path.join(latestDir, file), 'utf-8');
1913
- } catch { /* skip */ }
1914
- }
1915
- }
1916
- }
1950
+ this.sendAutoImplSSE({
1951
+ event: 'progress',
1952
+ data: {
1953
+ function: '_init',
1954
+ status: 'loading_reference',
1955
+ message: `Loading reference script (${resolvedReference || 'none'})...`
1917
1956
  }
1918
- }
1957
+ });
1958
+
1959
+ const referenceScripts = this.loadAutoImplReferenceScripts(provider.category, resolvedReference);
1919
1960
 
1920
1961
  // 3. Build the prompt
1921
- const prompt = this.buildAutoImplPrompt(type, provider, providerDir, functions, domContext, referenceScripts, comment);
1962
+ const prompt = this.buildAutoImplPrompt(type, provider, providerDir, functions, domContext, referenceScripts, comment, resolvedReference);
1922
1963
 
1923
1964
  // 4. Write prompt to temp file (avoids shell escaping issues with special chars)
1924
1965
  const tmpDir = path.join(os.tmpdir(), 'adhdev-autoimpl');
@@ -1940,7 +1981,7 @@ export class DevServer {
1940
1981
 
1941
1982
  // ─── ACP Agent: use ACP SDK (JSON-RPC protocol) ───
1942
1983
  if (agentCategory === 'acp') {
1943
- this.sendAutoImplSSE({ event: 'progress', data: { function: '_init', status: 'spawning', message: `ACP 에이전트 실행 중: ${spawn.command} ${(spawn.args || []).join(' ')}` } });
1984
+ this.sendAutoImplSSE({ event: 'progress', data: { function: '_init', status: 'spawning', message: `Spawning ACP agent: ${spawn.command} ${(spawn.args || []).join(' ')}` } });
1944
1985
  this.autoImplStatus = { running: true, type, progress: [] };
1945
1986
 
1946
1987
  // Dynamic import ACP SDK
@@ -2022,7 +2063,7 @@ export class DevServer {
2022
2063
  this.autoImplProcess = null;
2023
2064
  this.autoImplStatus.running = false;
2024
2065
  const success = code === 0;
2025
- this.sendAutoImplSSE({ event: 'complete', data: { success, exitCode: code, functions, message: success ? '✅ ACP Auto-implement 완료' : `❌ ACP 에이전트 종료 (code: ${code})` } });
2066
+ this.sendAutoImplSSE({ event: 'complete', data: { success, exitCode: code, functions, message: success ? '✅ ACP Auto-implement complete' : `❌ ACP agent exited (code: ${code})` } });
2026
2067
  try { this.providerLoader.reload(); } catch { /* ignore */ }
2027
2068
  try { fs.unlinkSync(promptFile); } catch { /* ignore */ }
2028
2069
  this.log(`Auto-implement (ACP) ${success ? 'completed' : 'failed'}: ${type} (exit: ${code})`);
@@ -2034,18 +2075,18 @@ export class DevServer {
2034
2075
  this.sendAutoImplSSE({ event: 'progress', data: { function: '_init', status: 'initializing', message: 'ACP initialize...' } });
2035
2076
  await connection.initialize({ protocolVersion: PROTOCOL_VERSION, clientCapabilities: {} });
2036
2077
 
2037
- this.sendAutoImplSSE({ event: 'progress', data: { function: '_init', status: 'session', message: 'ACP session 생성 중...' } });
2078
+ this.sendAutoImplSSE({ event: 'progress', data: { function: '_init', status: 'session', message: 'Creating ACP session...' } });
2038
2079
  const session = await connection.newSession({ cwd: providerDir, mcpServers: [] });
2039
2080
  const sessionId = session?.sessionId;
2040
2081
  if (!sessionId) throw new Error('No sessionId returned from session/new');
2041
2082
 
2042
- this.sendAutoImplSSE({ event: 'progress', data: { function: '_init', status: 'prompting', message: `프롬프트 전송 (${prompt.length} chars)...` } });
2083
+ this.sendAutoImplSSE({ event: 'progress', data: { function: '_init', status: 'prompting', message: `Sending prompt (${prompt.length} chars)...` } });
2043
2084
  await connection.prompt({
2044
2085
  sessionId,
2045
2086
  prompt: [{ type: 'text', text: prompt }],
2046
2087
  });
2047
2088
 
2048
- this.sendAutoImplSSE({ event: 'progress', data: { function: '_done', status: 'complete', message: '✅ ACP 프롬프트 처리 완료' } });
2089
+ this.sendAutoImplSSE({ event: 'progress', data: { function: '_done', status: 'complete', message: '✅ ACP prompt processing complete' } });
2049
2090
  } catch (e: any) {
2050
2091
  this.sendAutoImplSSE({ event: 'output', data: { chunk: `[ACP Error] ${e.message}\n`, stream: 'stderr' } });
2051
2092
  this.log(`Auto-implement ACP error: ${e.message}`);
@@ -2105,7 +2146,7 @@ export class DevServer {
2105
2146
  shellCmd = `cat '${promptFile}' | ${command} ${escapedArgs}`;
2106
2147
  }
2107
2148
 
2108
- this.sendAutoImplSSE({ event: 'progress', data: { function: '_init', status: 'spawning', message: `에이전트 실행 중: ${shellCmd.substring(0, 200)}... (prompt: ${prompt.length} chars)` } });
2149
+ this.sendAutoImplSSE({ event: 'progress', data: { function: '_init', status: 'spawning', message: `Spawning agent: ${shellCmd.substring(0, 200)}... (prompt: ${prompt.length} chars)` } });
2109
2150
 
2110
2151
  this.autoImplStatus = { running: true, type, progress: [] };
2111
2152
  const spawnedAt = Date.now();
@@ -2218,7 +2259,7 @@ export class DevServer {
2218
2259
  const success = code === 0;
2219
2260
  this.sendAutoImplSSE({
2220
2261
  event: 'complete',
2221
- data: { success, exitCode: code, functions, message: success ? '✅ Auto-implement 완료' : `❌ 에이전트 종료 (code: ${code})` },
2262
+ data: { success, exitCode: code, functions, message: success ? '✅ Auto-implement complete' : `❌ Agent exited (code: ${code})` },
2222
2263
  });
2223
2264
  try { this.providerLoader.reload(); } catch { /* ignore */ }
2224
2265
  try { fs.unlinkSync(promptFile); } catch { /* ignore */ }
@@ -2247,7 +2288,7 @@ export class DevServer {
2247
2288
  success,
2248
2289
  exitCode: code,
2249
2290
  functions,
2250
- message: success ? '✅ Auto-implement 완료' : `❌ 에이전트 종료 (code: ${code})`,
2291
+ message: success ? '✅ Auto-implement complete' : `❌ Agent exited (code: ${code})`,
2251
2292
  },
2252
2293
  });
2253
2294
  try { this.providerLoader.reload(); } catch { /* ignore */ }
@@ -2278,7 +2319,12 @@ export class DevServer {
2278
2319
  domContext: any,
2279
2320
  referenceScripts: Record<string, string>,
2280
2321
  userComment?: string,
2322
+ referenceType?: string | null,
2281
2323
  ): string {
2324
+ if (provider.category === 'cli') {
2325
+ return this.buildCliAutoImplPrompt(type, provider, providerDir, functions, referenceScripts, userComment, referenceType);
2326
+ }
2327
+
2282
2328
  const lines: string[] = [];
2283
2329
 
2284
2330
  // ── System instructions ──
@@ -2341,7 +2387,7 @@ export class DevServer {
2341
2387
  };
2342
2388
 
2343
2389
  if (Object.keys(referenceScripts).length > 0) {
2344
- lines.push('## Reference Implementation (from Antigravity provider)');
2390
+ lines.push(`## Reference Implementation (from ${referenceType || 'antigravity'} provider)`);
2345
2391
  lines.push('These are WORKING scripts from another IDE. Adapt the PATTERNS (not selectors) for the target IDE.');
2346
2392
  lines.push('');
2347
2393
  for (const fn of functions) {
@@ -2507,6 +2553,186 @@ export class DevServer {
2507
2553
  return lines.join('\n');
2508
2554
  }
2509
2555
 
2556
+ private buildCliAutoImplPrompt(
2557
+ type: string,
2558
+ provider: any,
2559
+ providerDir: string,
2560
+ functions: string[],
2561
+ referenceScripts: Record<string, string>,
2562
+ userComment?: string,
2563
+ referenceType?: string | null,
2564
+ ): string {
2565
+ const lines: string[] = [];
2566
+
2567
+ lines.push('You are implementing PTY parsing scripts for a CLI provider.');
2568
+ lines.push('Be concise. Do NOT explain your reasoning. Edit files directly and verify with the local DevServer.');
2569
+ lines.push('');
2570
+
2571
+ lines.push(`# Target: ${provider.name || type} (${type})`);
2572
+ lines.push(`Provider directory: \`${providerDir}\``);
2573
+ lines.push('Provider category: `cli`');
2574
+ lines.push('');
2575
+
2576
+ lines.push('## Current Target Files');
2577
+ lines.push('These are the files you need to edit. Replace TODO or heuristic-only logic with working PTY-aware implementations.');
2578
+ lines.push('');
2579
+
2580
+ const scriptsDir = path.join(providerDir, 'scripts');
2581
+ if (fs.existsSync(scriptsDir)) {
2582
+ const versions = fs.readdirSync(scriptsDir).filter((d: string) => {
2583
+ try { return fs.statSync(path.join(scriptsDir, d)).isDirectory(); } catch { return false; }
2584
+ }).sort().reverse();
2585
+ if (versions.length > 0) {
2586
+ const vDir = path.join(scriptsDir, versions[0]);
2587
+ lines.push(`Scripts version directory: \`${vDir}\``);
2588
+ lines.push('');
2589
+ for (const file of fs.readdirSync(vDir)) {
2590
+ if (!file.endsWith('.js')) continue;
2591
+ try {
2592
+ const content = fs.readFileSync(path.join(vDir, file), 'utf-8');
2593
+ lines.push(`### \`${file}\``);
2594
+ lines.push('```javascript');
2595
+ lines.push(content);
2596
+ lines.push('```');
2597
+ lines.push('');
2598
+ } catch {
2599
+ // ignore
2600
+ }
2601
+ }
2602
+ }
2603
+ }
2604
+
2605
+ const funcToFile: Record<string, string> = {
2606
+ parseOutput: 'parse_output.js',
2607
+ detectStatus: 'detect_status.js',
2608
+ parseApproval: 'parse_approval.js',
2609
+ };
2610
+
2611
+ if (Object.keys(referenceScripts).length > 0) {
2612
+ lines.push(`## Reference Implementation (from ${referenceType || 'another CLI'} provider)`);
2613
+ lines.push('These are working CLI PTY parser scripts. Reuse the parsing shape and runtime contract, but adapt to the target CLI screen.');
2614
+ lines.push('');
2615
+ for (const fn of functions) {
2616
+ const fileName = funcToFile[fn];
2617
+ if (fileName && referenceScripts[fileName]) {
2618
+ lines.push(`### ${fn} → \`${fileName}\``);
2619
+ lines.push('```javascript');
2620
+ lines.push(referenceScripts[fileName]);
2621
+ lines.push('```');
2622
+ lines.push('');
2623
+ }
2624
+ }
2625
+ if (referenceScripts['scripts.js']) {
2626
+ lines.push('### Router → `scripts.js`');
2627
+ lines.push('```javascript');
2628
+ lines.push(referenceScripts['scripts.js']);
2629
+ lines.push('```');
2630
+ lines.push('');
2631
+ }
2632
+ }
2633
+
2634
+ lines.push('## Runtime Contract');
2635
+ lines.push('The daemon runtime is already implemented in `packages/daemon-core/src/cli-adapters/provider-cli-adapter.ts`.');
2636
+ lines.push('Your scripts receive PTY-derived input and must return plain JS objects.');
2637
+ lines.push('');
2638
+ lines.push('| Function | Input | Return |');
2639
+ lines.push('|---|---|---|');
2640
+ lines.push('| `parseOutput` | `{ buffer, rawBuffer, recentBuffer, screenText, messages, partialResponse }` | `{ id, status, title, messages, activeModal }` |');
2641
+ lines.push('| `detectStatus` | `{ tail, screenText, rawBuffer }` | `idle`, `generating`, `waiting_approval`, or `error` |');
2642
+ lines.push('| `parseApproval` | `{ buffer, rawBuffer, tail }` | `{ message, buttons }` or `null` |');
2643
+ lines.push('');
2644
+
2645
+ lines.push('## Rules');
2646
+ lines.push('1. These scripts run in Node.js CommonJS, not in the browser. Do NOT use DOM APIs.');
2647
+ lines.push('2. Prefer `screenText` for current visible UI state. That is the PTY equivalent of parsing the current IDE DOM.');
2648
+ lines.push('3. Use `messages` as prior transcript state so redraws do not duplicate old turns on every parse.');
2649
+ lines.push('4. Use `partialResponse` for the actively streaming assistant text when status is `generating`.');
2650
+ lines.push('5. `detectStatus` must stay lightweight and tail-based. Do not scan the entire history there.');
2651
+ lines.push('6. `parseApproval` should understand the live approval area and return clean button labels.');
2652
+ lines.push('7. Use `rawBuffer` only when ANSI/control-sequence artifacts matter. Do not depend on raw escape noise unless necessary.');
2653
+ lines.push('8. Keep exports compatible with the existing `scripts.js` router (`module.exports = function ...`).');
2654
+ lines.push('9. Do not rewrite unrelated provider config. Only touch the scripts needed for this task unless a tiny supporting change is required.');
2655
+ lines.push('10. When the verification API returns `instanceId`, keep using that exact instance for follow-up `send`, `resolve`, `raw`, and `stop` calls. Do not assume type-only routing is safe if multiple sessions exist.');
2656
+ lines.push('');
2657
+
2658
+ lines.push('## Task');
2659
+ lines.push(`Edit files in \`${providerDir}\` to implement: **${functions.join(', ')}**`);
2660
+ lines.push('');
2661
+
2662
+ lines.push('## Verification API');
2663
+ lines.push('Use the DevServer CLI debug endpoints, not DOM/CDP routes.');
2664
+ lines.push('');
2665
+ lines.push('### 1. Launch the target CLI');
2666
+ lines.push('```bash');
2667
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/launch \\`);
2668
+ lines.push(' -H "Content-Type: application/json" \\');
2669
+ lines.push(` -d '{"type":"${type}","workingDir":"${providerDir.replace(/\\/g, '\\\\')}"}'`);
2670
+ lines.push('```');
2671
+ lines.push('');
2672
+ lines.push('### 2. Inspect parsed + raw adapter state');
2673
+ lines.push('```bash');
2674
+ lines.push(`curl -sS http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/debug/${type}`);
2675
+ lines.push(`curl -sS http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/status`);
2676
+ lines.push('```');
2677
+ lines.push('');
2678
+ lines.push('Extract the current `instanceId` from the launch or status response and keep using it below.');
2679
+ lines.push('');
2680
+ lines.push('### 3. Send a realistic approval-triggering prompt');
2681
+ lines.push('```bash');
2682
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/send \\`);
2683
+ lines.push(' -H "Content-Type: application/json" \\');
2684
+ lines.push(` -d '{"type":"${type}","instanceId":"<INSTANCE_ID>","text":"Create a file at tmp/adhdev_provider_fix_test.py that prints the current working directory and the squares of 1 through 5, then run python3 tmp/adhdev_provider_fix_test.py and tell me the exact output."}'`);
2685
+ lines.push('```');
2686
+ lines.push('');
2687
+ lines.push('### 4. If approval appears, resolve it until the CLI reaches idle');
2688
+ lines.push('```bash');
2689
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/resolve \\`);
2690
+ lines.push(' -H "Content-Type: application/json" \\');
2691
+ lines.push(` -d '{"type":"${type}","instanceId":"<INSTANCE_ID>","buttonIndex":0}'`);
2692
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/raw \\`);
2693
+ lines.push(' -H "Content-Type: application/json" \\');
2694
+ lines.push(` -d '{"type":"${type}","instanceId":"<INSTANCE_ID>","keys":"1"}'`);
2695
+ lines.push('```');
2696
+ lines.push('');
2697
+ lines.push('Use `resolve` when the parsed modal buttons are correct. Use `raw` when the CLI expects a literal keystroke like `1`, `y`, or Enter. Repeat until idle.');
2698
+ lines.push('');
2699
+ lines.push('### 5. Verify the side effects outside the CLI');
2700
+ lines.push('```bash');
2701
+ lines.push('test -f tmp/adhdev_provider_fix_test.py');
2702
+ lines.push('python3 tmp/adhdev_provider_fix_test.py');
2703
+ lines.push('```');
2704
+ lines.push('');
2705
+ lines.push('### 6. Stop the CLI when finished');
2706
+ lines.push('```bash');
2707
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/stop \\`);
2708
+ lines.push(' -H "Content-Type: application/json" \\');
2709
+ lines.push(` -d '{"type":"${type}","instanceId":"<INSTANCE_ID>"}'`);
2710
+ lines.push('```');
2711
+ lines.push('');
2712
+
2713
+ lines.push('## Required Validation');
2714
+ lines.push('1. Confirm `detectStatus` changes sensibly between startup, generating, approval, and idle.');
2715
+ lines.push('2. Confirm `parseOutput` produces a stable transcript without duplicating past turns when the PTY redraws.');
2716
+ lines.push('3. Confirm the latest assistant message streams through `partialResponse` while generation is in progress.');
2717
+ lines.push('4. Confirm approval parsing returns meaningful button labels when the CLI requests permission.');
2718
+ lines.push('5. Confirm the Python file was actually created and executed, not just described in chat text.');
2719
+ lines.push('6. Confirm the final assistant transcript includes the exact Python output, including the working directory line and the five square numbers.');
2720
+ lines.push('7. Re-run the debug endpoints after edits. Do NOT finish until the parsed result looks correct.');
2721
+ lines.push('');
2722
+
2723
+ if (userComment) {
2724
+ lines.push('## ⚠️ User Instructions (HIGH PRIORITY)');
2725
+ lines.push('The user has provided the following additional instructions. Follow them strictly:');
2726
+ lines.push('');
2727
+ lines.push(userComment);
2728
+ lines.push('');
2729
+ }
2730
+
2731
+ lines.push('Start NOW. Launch the CLI, inspect PTY state, edit the scripts, and verify via the CLI debug endpoints.');
2732
+
2733
+ return lines.join('\n');
2734
+ }
2735
+
2510
2736
  private handleAutoImplSSE(type: string, req: http.IncomingMessage, res: http.ServerResponse): void {
2511
2737
  res.writeHead(200, {
2512
2738
  'Content-Type': 'text/event-stream',
@@ -2531,7 +2757,7 @@ export class DevServer {
2531
2757
  if (this.autoImplProcess) {
2532
2758
  this.autoImplProcess.kill('SIGTERM');
2533
2759
  setTimeout(() => { if (this.autoImplProcess) this.autoImplProcess.kill('SIGKILL'); }, 3000);
2534
- this.sendAutoImplSSE({ event: 'complete', data: { success: false, exitCode: -1, message: '⛔ 사용자에 의해 중단됨' } });
2760
+ this.sendAutoImplSSE({ event: 'complete', data: { success: false, exitCode: -1, message: '⛔ Aborted by user' } });
2535
2761
  this.autoImplProcess = null;
2536
2762
  this.autoImplStatus.running = false;
2537
2763
  this.json(res, 200, { cancelled: true });
@@ -2617,6 +2843,17 @@ export class DevServer {
2617
2843
  this.json(res, 200, { instances: result, count: result.length });
2618
2844
  }
2619
2845
 
2846
+ private findCliTarget(type?: string, instanceId?: string): any | null {
2847
+ if (!this.instanceManager) return null;
2848
+ const cliStates = this.instanceManager
2849
+ .collectAllStates()
2850
+ .filter(s => s.category === 'cli' || s.category === 'acp');
2851
+ if (instanceId) return cliStates.find(s => s.instanceId === instanceId) || null;
2852
+ if (!type) return cliStates[cliStates.length - 1] || null;
2853
+ const matches = cliStates.filter(s => s.type === type);
2854
+ return matches[matches.length - 1] || null;
2855
+ }
2856
+
2620
2857
  /** POST /api/cli/launch — launch a CLI agent { type, workingDir?, args? } */
2621
2858
  private async handleCliLaunch(req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {
2622
2859
  if (!this.cliManager) {
@@ -2650,12 +2887,7 @@ export class DevServer {
2650
2887
  return;
2651
2888
  }
2652
2889
 
2653
- // Find the CLI instance by type or instanceId
2654
- const allStates = this.instanceManager.collectAllStates();
2655
- const target = allStates.find(s =>
2656
- (s.category === 'cli' || s.category === 'acp') &&
2657
- (instanceId ? s.instanceId === instanceId : s.type === type)
2658
- );
2890
+ const target = this.findCliTarget(type, instanceId);
2659
2891
  if (!target) {
2660
2892
  this.json(res, 404, { error: `No running instance found for: ${type || instanceId}` });
2661
2893
  return;
@@ -2678,11 +2910,7 @@ export class DevServer {
2678
2910
  const body = await this.readBody(req);
2679
2911
  const { type, instanceId } = body;
2680
2912
 
2681
- const allStates = this.instanceManager.collectAllStates();
2682
- const target = allStates.find(s =>
2683
- (s.category === 'cli' || s.category === 'acp') &&
2684
- (instanceId ? s.instanceId === instanceId : s.type === type)
2685
- );
2913
+ const target = this.findCliTarget(type, instanceId);
2686
2914
  if (!target) {
2687
2915
  this.json(res, 404, { error: `No running instance found for: ${type || instanceId}` });
2688
2916
  return;
@@ -2742,12 +2970,9 @@ export class DevServer {
2742
2970
  return;
2743
2971
  }
2744
2972
 
2745
- // Find the matching CLI instance
2746
- const allStates = this.instanceManager.collectAllStates();
2747
- const target = allStates.find(s =>
2748
- (s.category === 'cli' || s.category === 'acp') && s.type === type
2749
- );
2973
+ const target = this.findCliTarget(type);
2750
2974
  if (!target) {
2975
+ const allStates = this.instanceManager.collectAllStates();
2751
2976
  this.json(res, 404, { error: `No running instance for: ${type}`, available: allStates.filter(s => s.category === 'cli' || s.category === 'acp').map(s => s.type) });
2752
2977
  return;
2753
2978
  }
@@ -2800,19 +3025,28 @@ export class DevServer {
2800
3025
  this.json(res, 503, { error: 'CliManager not available' });
2801
3026
  return;
2802
3027
  }
2803
- // Find adapter from cliManager.adapters map
2804
- let adapter: any = null;
2805
- for (const [, a] of this.cliManager.adapters) {
2806
- if (type && (a as any).cliType === type) { adapter = a; break; }
3028
+ if (!this.instanceManager) {
3029
+ this.json(res, 503, { error: 'InstanceManager not available' });
3030
+ return;
2807
3031
  }
2808
- if (!adapter) {
3032
+
3033
+ const target = this.findCliTarget(type, instanceId);
3034
+ if (!target) {
2809
3035
  this.json(res, 404, { error: `No running adapter for: ${type || instanceId}` });
2810
3036
  return;
2811
3037
  }
3038
+
3039
+ const instance = this.instanceManager.getInstance(target.instanceId) as any;
3040
+ const adapter = instance?.getAdapter?.() || instance?.adapter;
3041
+ if (!adapter) {
3042
+ this.json(res, 404, { error: `Adapter not found for instance: ${target.instanceId}` });
3043
+ return;
3044
+ }
3045
+
2812
3046
  try {
2813
3047
  if (typeof adapter.resolveModal === 'function') {
2814
3048
  adapter.resolveModal(buttonIndex);
2815
- this.json(res, 200, { resolved: true, type, buttonIndex });
3049
+ this.json(res, 200, { resolved: true, type: target.type, instanceId: target.instanceId, buttonIndex });
2816
3050
  } else {
2817
3051
  this.json(res, 400, { error: 'resolveModal not available on this adapter' });
2818
3052
  }
@@ -2834,18 +3068,28 @@ export class DevServer {
2834
3068
  this.json(res, 503, { error: 'CliManager not available' });
2835
3069
  return;
2836
3070
  }
2837
- let adapter: any = null;
2838
- for (const [, a] of this.cliManager.adapters) {
2839
- if (type && (a as any).cliType === type) { adapter = a; break; }
3071
+ if (!this.instanceManager) {
3072
+ this.json(res, 503, { error: 'InstanceManager not available' });
3073
+ return;
3074
+ }
3075
+
3076
+ const target = this.findCliTarget(type, instanceId);
3077
+ if (!target) {
3078
+ this.json(res, 404, { error: `No running adapter for: ${type || instanceId}` });
3079
+ return;
2840
3080
  }
3081
+
3082
+ const instance = this.instanceManager.getInstance(target.instanceId) as any;
3083
+ const adapter = instance?.getAdapter?.() || instance?.adapter;
2841
3084
  if (!adapter) {
2842
- this.json(res, 404, { error: `No running adapter for: ${type || instanceId}` });
3085
+ this.json(res, 404, { error: `Adapter not found for instance: ${target.instanceId}` });
2843
3086
  return;
2844
3087
  }
3088
+
2845
3089
  try {
2846
3090
  if (typeof adapter.writeRaw === 'function') {
2847
3091
  adapter.writeRaw(keys);
2848
- this.json(res, 200, { sent: true, type, keysLength: keys.length });
3092
+ this.json(res, 200, { sent: true, type: target.type, instanceId: target.instanceId, keysLength: keys.length });
2849
3093
  } else {
2850
3094
  this.json(res, 400, { error: 'writeRaw not available on this adapter' });
2851
3095
  }
@@ -51,7 +51,7 @@ import type { ProviderInstance, ProviderState, AcpProviderState, ProviderErrorRe
51
51
  import { StatusMonitor } from './status-monitor.js';
52
52
  import { LOG } from '../logging/logger.js';
53
53
 
54
- // ─── Internal Display Types (dashboard) ────────────────────────────
54
+ // ─── Internal Display Types (for dashboard) ────────────────────────────
55
55
 
56
56
  interface AcpMessage {
57
57
  role: 'user' | 'assistant' | 'system';
@@ -81,25 +81,37 @@ export class CliProviderInstance implements ProviderInstance {
81
81
  }
82
82
 
83
83
  getState(): ProviderState {
84
- const adapterStatus = this.adapter.getStatus();
84
+ const rawStatus = this.adapter.getStatus();
85
+ const parsedStatus = this.adapter.getScriptParsedStatus();
86
+
87
+ // Prefer rich script parsed status if available
88
+ const adapterStatus = parsedStatus ? {
89
+ ...rawStatus,
90
+ messages: parsedStatus.messages || rawStatus.messages,
91
+ activeModal: parsedStatus.activeModal || rawStatus.activeModal,
92
+ } : rawStatus;
93
+
85
94
  const dirName = this.workingDir.split('/').filter(Boolean).pop() || 'session';
86
95
 
87
- // Message truncate (recent 50, 2000 char limit)
88
- const recentMessages = adapterStatus.messages.slice(-50).map(m => ({
89
- role: m.role,
90
- content: m.content.length > 2000 ? m.content.slice(0, 2000) + '\n... (truncated)' : m.content,
91
- timestamp: m.timestamp,
92
- }));
96
+ // Preserve rich message objects, just truncate extremely long text strings
97
+ const recentMessages = adapterStatus.messages.slice(-50).map((m: any) => {
98
+ const content = typeof m.content === 'string' && m.content.length > 8000
99
+ ? m.content.slice(0, 8000) + '\n... (truncated)'
100
+ : m.content;
101
+ return { ...m, content };
102
+ });
93
103
 
94
104
  // generating during partial response add
95
105
  const partial = this.adapter.getPartialResponse();
96
- if (adapterStatus.status === 'generating' && partial) {
106
+ const shouldAppendRawPartial = !parsedStatus;
107
+ if (shouldAppendRawPartial && adapterStatus.status === 'generating' && partial) {
97
108
  const cleaned = partial.trim();
98
109
  if (cleaned && cleaned !== '(generating...)') {
99
110
  recentMessages.push({
100
111
  role: 'assistant',
101
- content: (cleaned.length > 2000 ? cleaned.slice(0, 2000) + '...' : cleaned) + '...',
112
+ content: (cleaned.length > 8000 ? cleaned.slice(0, 8000) + '...' : cleaned) + '...',
102
113
  timestamp: Date.now(),
114
+ meta: { streaming: true },
103
115
  });
104
116
  }
105
117
  }
@@ -142,6 +154,8 @@ export class CliProviderInstance implements ProviderInstance {
142
154
  this.adapter.sendMessage(data.text);
143
155
  } else if (event === 'server_connected' && data?.serverConn) {
144
156
  this.adapter.setServerConn(data.serverConn);
157
+ } else if (event === 'resolve_action' && data) {
158
+ this.adapter.resolveAction(data);
145
159
  }
146
160
  }
147
161
 
@@ -1141,8 +1141,9 @@ export class ProviderLoader {
1141
1141
  }
1142
1142
 
1143
1143
  private compareVersions(a: string, b: string): number {
1144
- const pa = a.split('.').map(Number);
1145
- const pb = b.split('.').map(Number);
1144
+ const normalize = (v: string) => v.split(/[-_+]/)[0].split('.').map(x => parseInt(x, 10) || 0);
1145
+ const pa = normalize(a);
1146
+ const pb = normalize(b);
1146
1147
  for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
1147
1148
  const va = pa[i] || 0;
1148
1149
  const vb = pb[i] || 0;
@@ -1,43 +0,0 @@
1
- /**
2
- * Cline — list_models
3
- * 드롭다운에서 사용 가능한 모델 목록 + 현재 선택된 모델 반환
4
- * → { models: string[], current: string }
5
- */
6
- (async () => {
7
- try {
8
- const inner = document.querySelector('iframe');
9
- const doc = inner?.contentDocument || inner?.contentWindow?.document;
10
- if (!doc) return JSON.stringify({ models: [], current: '', error: 'no doc' });
11
-
12
- // 현재 모델: mode-switch 또는 model selector에서 읽기
13
- let current = '';
14
- const modeSwitch = doc.querySelector('[data-testid="mode-switch"]');
15
- if (modeSwitch) current = (modeSwitch.textContent || '').trim();
16
- if (!current) {
17
- const modelSel = doc.querySelector('[data-testid*="model"], [aria-label*="model" i]');
18
- if (modelSel) current = (modelSel.textContent || '').trim();
19
- }
20
-
21
- // 드롭다운 트리거 찾기
22
- const trigger = doc.querySelector('[data-testid="model-selector"], [data-testid*="model-dropdown"], [data-testid="dropdown-trigger"]');
23
- if (!trigger) return JSON.stringify({ models: [], current, error: 'no model trigger' });
24
-
25
- // 드롭다운 열기
26
- trigger.click();
27
- await new Promise(r => setTimeout(r, 300));
28
-
29
- // 옵션 수집
30
- const options = doc.querySelectorAll('[data-testid*="dropdown-option"], [role="option"], [class*="dropdown"] [class*="item"], [class*="listbox"] [class*="option"]');
31
- const models = [];
32
- for (const opt of options) {
33
- const text = (opt.textContent || '').trim();
34
- if (text && text.length > 1 && text.length < 100) models.push(text);
35
- }
36
-
37
- // 닫기
38
- doc.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
39
- if (trigger.click) trigger.click(); // fallback close
40
-
41
- return JSON.stringify({ models: [...new Set(models)], current });
42
- } catch (e) { return JSON.stringify({ models: [], current: '', error: e.message }); }
43
- })()