cc-viewer 1.7.23 → 1.8.0

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 (237) hide show
  1. package/README.md +19 -0
  2. package/cli.js +92 -11
  3. package/concepts/ar/GlobalSettings.md +2 -2
  4. package/concepts/da/GlobalSettings.md +2 -2
  5. package/concepts/de/GlobalSettings.md +2 -2
  6. package/concepts/en/GlobalSettings.md +2 -2
  7. package/concepts/es/GlobalSettings.md +2 -2
  8. package/concepts/fr/GlobalSettings.md +2 -2
  9. package/concepts/it/GlobalSettings.md +2 -2
  10. package/concepts/ja/GlobalSettings.md +2 -2
  11. package/concepts/ko/GlobalSettings.md +2 -2
  12. package/concepts/no/GlobalSettings.md +2 -2
  13. package/concepts/pl/GlobalSettings.md +2 -2
  14. package/concepts/pt-BR/GlobalSettings.md +2 -2
  15. package/concepts/ru/GlobalSettings.md +2 -2
  16. package/concepts/th/GlobalSettings.md +2 -2
  17. package/concepts/tr/GlobalSettings.md +2 -2
  18. package/concepts/uk/GlobalSettings.md +2 -2
  19. package/concepts/zh/GlobalSettings.md +2 -2
  20. package/concepts/zh-TW/GlobalSettings.md +2 -2
  21. package/dist/assets/{App-CusqoEAB.js → App-CCu0y2Cq.js} +2 -2
  22. package/dist/assets/{MdxEditorPanel-e5DlfcqJ.js → MdxEditorPanel-BBhgTmDk.js} +1 -1
  23. package/dist/assets/{Mobile-B8xwCLgr.js → Mobile-vN4lyiaz.js} +1 -1
  24. package/dist/assets/{ProxyStatsModal-_w677xPM.js → ProxyStatsModal-BOflqr0R.js} +1 -1
  25. package/dist/assets/index-C3BRHDVF.js +2 -0
  26. package/dist/assets/seqResourceLoaders-DI0G5nu1.css +41 -0
  27. package/dist/assets/seqResourceLoaders-DpYqp6SP.js +2 -0
  28. package/dist/index.html +1 -1
  29. package/findcc.js +17 -8
  30. package/node_modules/@ccv/core/package.json +13 -0
  31. package/{server/lib → node_modules/@ccv/core/src}/approval-modal-prefs.js +1 -1
  32. package/node_modules/@ccv/core/src/clearCheckpoint.js +7 -0
  33. package/{src/utils → node_modules/@ccv/core/src}/contentFilter.js +207 -141
  34. package/{server/lib → node_modules/@ccv/core/src}/context-rules.js +2 -2
  35. package/{server/lib → node_modules/@ccv/core/src}/delta-reconstructor.js +60 -4
  36. package/{server/lib → node_modules/@ccv/core/src}/error-report.js +5 -4
  37. package/{server/lib → node_modules/@ccv/core/src}/session-boundary.js +3 -3
  38. package/{src/utils → node_modules/@ccv/core/src}/teammateDetector.js +9 -0
  39. package/{server/lib → node_modules/@ccv/core/src}/tools-xml-formatter.js +3 -3
  40. package/{server/lib → node_modules/@ccv/core/src}/v2-transcript-normalizer.js +1 -1
  41. package/{server/lib → node_modules/@ccv/core/src}/voice-pack-events.js +2 -2
  42. package/package.json +11 -97
  43. package/server/_paths.js +28 -7
  44. package/server/i18n.js +60 -0
  45. package/server/interceptor.js +36 -11
  46. package/server/lib/adapters/dingtalk-adapter.js +2 -2
  47. package/server/lib/adapters/discord-adapter.js +2 -2
  48. package/server/lib/adapters/feishu-adapter.js +2 -2
  49. package/server/lib/adapters/wecom-adapter.js +2 -2
  50. package/server/lib/approval-policy.js +29 -0
  51. package/server/lib/{ask-store.js → ask/ask-store.js} +3 -3
  52. package/server/lib/{perm-bridge.js → ask/perm-bridge.js} +5 -5
  53. package/server/lib/chat-queue.js +341 -0
  54. package/server/lib/cli-inject.js +1 -1
  55. package/server/lib/context-watcher.js +3 -3
  56. package/server/lib/create_system_prompt.js +0 -9
  57. package/server/lib/enrich-plan-input.js +1 -1
  58. package/server/lib/ensure-hooks.js +2 -2
  59. package/server/lib/file-access-policy.js +6 -1
  60. package/server/lib/file-api.js +17 -1
  61. package/server/lib/{dingtalk-bridge.js → im/dingtalk-bridge.js} +1 -1
  62. package/server/lib/{im-append-system.js → im/im-append-system.js} +5 -13
  63. package/server/lib/{im-bridge-core.js → im/im-bridge-core.js} +12 -6
  64. package/server/lib/{im-config.js → im/im-config.js} +1 -1
  65. package/server/lib/im/im-deny.js +4 -0
  66. package/server/lib/{im-lang.js → im/im-lang.js} +1 -1
  67. package/server/lib/{im-lock.js → im/im-lock.js} +2 -2
  68. package/server/lib/{im-process-manager.js → im/im-process-manager.js} +1 -1
  69. package/server/lib/{im-senders.js → im/im-senders.js} +1 -1
  70. package/server/lib/{im-skills.js → im/im-skills.js} +2 -2
  71. package/server/lib/interceptor-core.js +8 -5
  72. package/server/lib/kv-cache-analyzer.js +6 -5
  73. package/server/lib/launch-config.js +321 -0
  74. package/server/lib/log-file-utils.js +21 -0
  75. package/server/lib/log-management.js +6 -17
  76. package/server/lib/log-stream.js +1 -1
  77. package/server/lib/log-watcher.js +1 -1
  78. package/server/lib/model-system-prompts.js +1 -1
  79. package/server/lib/prefs-store.js +2 -2
  80. package/server/lib/project-prefs.js +6 -6
  81. package/server/lib/project-state.js +15 -0
  82. package/server/lib/{proxy-retry.js → proxy/proxy-retry.js} +2 -2
  83. package/server/lib/{proxy-stats.js → proxy/proxy-stats.js} +3 -3
  84. package/server/lib/sdk-adapter.js +6 -74
  85. package/server/lib/sdk-manager.js +383 -278
  86. package/server/lib/skills-api.js +1 -1
  87. package/server/lib/spawn-model-resolver.js +21 -6
  88. package/server/lib/stats-worker.js +2 -2
  89. package/server/lib/system-prompt-files.js +11 -10
  90. package/server/lib/system-prompt-render.js +23 -7
  91. package/server/lib/system-prompt-snapshots.js +452 -0
  92. package/server/lib/updater.js +63 -3
  93. package/server/lib/user-prompt-extract.js +5 -5
  94. package/server/lib/v2/adapter.js +3 -3
  95. package/server/lib/v2/conversation-store.js +1 -1
  96. package/server/lib/v2/convert.js +3 -3
  97. package/server/lib/v2/jsonl-read.js +1 -1
  98. package/server/lib/v2/live-feed.js +3 -3
  99. package/server/lib/v2/meta-rows.js +3 -3
  100. package/server/lib/v2/replay.js +1 -1
  101. package/server/lib/v2/session-list.js +1 -1
  102. package/server/lib/v2/session-owner.js +1 -1
  103. package/server/lib/v2/v2-writer.js +26 -1
  104. package/server/lib/v2/verify.js +1 -1
  105. package/server/lib/voice-pack-manager.js +4 -5
  106. package/server/lib/wire-compress.js +1 -1
  107. package/server/proxy.js +5 -5
  108. package/server/pty-manager.js +282 -184
  109. package/server/routes/ask-perm.js +1 -1
  110. package/server/routes/dingtalk.js +3 -3
  111. package/server/routes/events.js +2 -2
  112. package/server/routes/im.js +5 -5
  113. package/server/routes/preferences.js +3 -3
  114. package/server/routes/workspaces.js +1 -1
  115. package/server/server.js +207 -58
  116. package/server/system-prompt-templates/systemPromptModel.md +0 -8
  117. package/server/system-prompt-templates/systemPromptVariables.ar.md +0 -7
  118. package/server/system-prompt-templates/systemPromptVariables.da.md +0 -7
  119. package/server/system-prompt-templates/systemPromptVariables.de.md +0 -7
  120. package/server/system-prompt-templates/systemPromptVariables.es.md +0 -7
  121. package/server/system-prompt-templates/systemPromptVariables.fr.md +0 -7
  122. package/server/system-prompt-templates/systemPromptVariables.it.md +0 -7
  123. package/server/system-prompt-templates/systemPromptVariables.ja.md +0 -7
  124. package/server/system-prompt-templates/systemPromptVariables.ko.md +0 -7
  125. package/server/system-prompt-templates/systemPromptVariables.md +0 -7
  126. package/server/system-prompt-templates/systemPromptVariables.no.md +0 -7
  127. package/server/system-prompt-templates/systemPromptVariables.pl.md +0 -7
  128. package/server/system-prompt-templates/systemPromptVariables.pt-BR.md +0 -7
  129. package/server/system-prompt-templates/systemPromptVariables.ru.md +0 -7
  130. package/server/system-prompt-templates/systemPromptVariables.th.md +0 -7
  131. package/server/system-prompt-templates/systemPromptVariables.tr.md +0 -7
  132. package/server/system-prompt-templates/systemPromptVariables.uk.md +0 -7
  133. package/server/system-prompt-templates/systemPromptVariables.zh-TW.md +0 -7
  134. package/server/system-prompt-templates/systemPromptVariables.zh.md +0 -7
  135. package/dist/assets/index-D6FmFsIz.js +0 -2
  136. package/dist/assets/seqResourceLoaders-3K77Znll.js +0 -2
  137. package/dist/assets/seqResourceLoaders-BgD_Rwvc.css +0 -41
  138. package/src/utils/apiUrl.js +0 -26
  139. package/src/utils/askFallback.js +0 -21
  140. package/src/utils/askOptionDesc.js +0 -55
  141. package/src/utils/askPortalMatcher.js +0 -54
  142. package/src/utils/autoApproveOptions.js +0 -27
  143. package/src/utils/avatarAnimationPostPass.js +0 -49
  144. package/src/utils/builtinPresets.js +0 -18
  145. package/src/utils/clearCheckpoint.js +0 -7
  146. package/src/utils/commandValidator.js +0 -45
  147. package/src/utils/contextRaw.js +0 -18
  148. package/src/utils/contextSidebarNavigation.js +0 -16
  149. package/src/utils/contextTurns.js +0 -117
  150. package/src/utils/displayScaleHelper.js +0 -47
  151. package/src/utils/effectiveModel.js +0 -17
  152. package/src/utils/entry-slim.js +0 -563
  153. package/src/utils/entryCache.js +0 -144
  154. package/src/utils/errorReport.js +0 -6
  155. package/src/utils/fileExpandedPathsStorage.js +0 -70
  156. package/src/utils/fileIcons.jsx +0 -36
  157. package/src/utils/fileOpen.js +0 -37
  158. package/src/utils/formatters.js +0 -48
  159. package/src/utils/gitApi.js +0 -50
  160. package/src/utils/gitTreeBuilder.js +0 -19
  161. package/src/utils/helpers.js +0 -854
  162. package/src/utils/identityHeal.js +0 -108
  163. package/src/utils/imConnState.js +0 -59
  164. package/src/utils/imOrigin.js +0 -24
  165. package/src/utils/imTr.js +0 -7
  166. package/src/utils/imageCompress.js +0 -83
  167. package/src/utils/imageDownscale.js +0 -28
  168. package/src/utils/imageResize.js +0 -112
  169. package/src/utils/ingestPipeline.js +0 -47
  170. package/src/utils/isProxyMode.js +0 -11
  171. package/src/utils/lazyWithReload.js +0 -53
  172. package/src/utils/markdown.js +0 -30
  173. package/src/utils/markdownIncremental.js +0 -39
  174. package/src/utils/markdownProfiler.js +0 -113
  175. package/src/utils/mdExtensionDetect.js +0 -64
  176. package/src/utils/memoryLinkParser.js +0 -44
  177. package/src/utils/modalMask.js +0 -15
  178. package/src/utils/modelSuggestions.js +0 -48
  179. package/src/utils/monotime.js +0 -6
  180. package/src/utils/pinnedMenu.js +0 -55
  181. package/src/utils/presetShortcuts.js +0 -14
  182. package/src/utils/projectAlias.js +0 -135
  183. package/src/utils/promptClassifier.js +0 -112
  184. package/src/utils/promptDetect.js +0 -196
  185. package/src/utils/promptNav.js +0 -60
  186. package/src/utils/ptyChunkBuilder.js +0 -251
  187. package/src/utils/quickMenuHoverIntent.js +0 -35
  188. package/src/utils/rateLimitParser.js +0 -119
  189. package/src/utils/readResultPool.js +0 -106
  190. package/src/utils/refreshCachedItemProp.js +0 -30
  191. package/src/utils/resizeCalc.js +0 -21
  192. package/src/utils/resolveLocalized.js +0 -17
  193. package/src/utils/searchApi.js +0 -47
  194. package/src/utils/searchReplace.js +0 -51
  195. package/src/utils/seqResourceLoaders.js +0 -79
  196. package/src/utils/sessionManager.js +0 -482
  197. package/src/utils/sessionMerge.js +0 -239
  198. package/src/utils/skillModalController.js +0 -111
  199. package/src/utils/skillsParser.js +0 -116
  200. package/src/utils/slashCommandLabels.js +0 -80
  201. package/src/utils/splitDragCalc.js +0 -73
  202. package/src/utils/stickyBottomController.js +0 -643
  203. package/src/utils/svgSanitize.js +0 -48
  204. package/src/utils/systemTags.js +0 -47
  205. package/src/utils/tClaude.js +0 -20
  206. package/src/utils/teamModalBuilder.js +0 -351
  207. package/src/utils/teamSessionParser.js +0 -190
  208. package/src/utils/teammateAvatars.js +0 -194
  209. package/src/utils/termDiag.js +0 -114
  210. package/src/utils/terminalClipboard.js +0 -117
  211. package/src/utils/terminalWriteQueue.js +0 -398
  212. package/src/utils/thinkingMerge.js +0 -49
  213. package/src/utils/toolCatalog.js +0 -30
  214. package/src/utils/toolResultBuilder.js +0 -411
  215. package/src/utils/toolResultClassifier.js +0 -16
  216. package/src/utils/toolResultCore.js +0 -194
  217. package/src/utils/toolsDiff.js +0 -44
  218. package/src/utils/toolsXmlFormatter.js +0 -3
  219. package/src/utils/ultraplanController.js +0 -109
  220. package/src/utils/ultraplanExperts.js +0 -86
  221. package/src/utils/ultraplanTemplates.js +0 -154
  222. package/src/utils/userImageRefs.js +0 -49
  223. package/src/utils/v3Assembler.js +0 -125
  224. package/src/utils/v3Rows.js +0 -49
  225. package/src/utils/voicePackPlayer.js +0 -233
  226. package/src/utils/webSearchGrouping.js +0 -111
  227. package/src/utils/workflowFormat.js +0 -52
  228. package/src/utils/workflowRuns.js +0 -118
  229. package/src/utils/workflowStore.js +0 -94
  230. /package/{src/utils → node_modules/@ccv/core/src}/requestType.js +0 -0
  231. /package/server/lib/{ask-bridge.js → ask/ask-bridge.js} +0 -0
  232. /package/server/lib/{ask-constants.js → ask/ask-constants.js} +0 -0
  233. /package/server/lib/{ask-reaper.js → ask/ask-reaper.js} +0 -0
  234. /package/server/lib/{dingtalk-config.js → im/dingtalk-config.js} +0 -0
  235. /package/server/lib/{im-log-watcher.js → im/im-log-watcher.js} +0 -0
  236. /package/server/lib/{proxy-env.js → proxy/proxy-env.js} +0 -0
  237. /package/server/lib/{proxy-errors.js → proxy/proxy-errors.js} +0 -0
package/README.md CHANGED
@@ -35,6 +35,13 @@ brew install cc-viewer
35
35
  brew upgrade cc-viewer # use this to upgrade; do NOT use npm install -g to upgrade a brew-installed ccv
36
36
  ```
37
37
 
38
+ #### Install via pnpm (global)
39
+
40
+ ```bash
41
+ pnpm add -g cc-viewer
42
+ pnpm add -g cc-viewer@latest # use this to upgrade; do NOT use npm install -g to upgrade a pnpm-installed ccv
43
+ ```
44
+
38
45
  ### How to start
39
46
 
40
47
  ccv is a drop-in replacement for claude — all arguments are passed through to claude while the Web Viewer is launched alongside it.
@@ -54,6 +61,18 @@ Once started in programming mode, the web page opens automatically.
54
61
 
55
62
  cc-viewer also ships as a native desktop app: [download page](https://github.com/weiesky/cc-viewer/releases)
56
63
 
64
+ ### SDK mode (headless, `ccv -SDK`)
65
+
66
+ `ccv -SDK` runs the session through the Agent SDK instead of an interactive terminal — no terminal panel, messages are sent from the web UI, and everything else (session logs, streaming typewriter, usage stats) works the same as in terminal mode.
67
+
68
+ ```bash
69
+ ccv -SDK # headless session; chat from the browser
70
+ ccv -SDK -c # continue the most recent session
71
+ ccv -SDK --model sonnet # pick a model
72
+ ```
73
+
74
+ Approvals (Bash/Edit/Write/WebFetch/…) pop up in the browser with allow / deny / allow-for-session, and `AskUserQuestion` / plan prompts appear as modals. `npm publish` always requires an explicit approval — even with `--d`. Requires the `@anthropic-ai/claude-agent-sdk` package (bundled with cc-viewer); falls back to terminal mode if unavailable.
75
+
57
76
  ### Choose the Claude executable
58
77
 
59
78
  On the local CCV page, open **Global Settings → Claude executable** to choose the
package/cli.js CHANGED
@@ -16,6 +16,7 @@ import { ensureHooks, removeAllManagedHooks } from './server/lib/ensure-hooks.js
16
16
  import { injectCliJsAt, removeCliJsInjectionAt, INJECT_START as _INJECT_START, INJECT_END as _INJECT_END, buildInjectBlock as _buildInjectBlock } from './server/lib/cli-inject.js';
17
17
  import { normalizeBasePath } from './server/lib/base-path.js';
18
18
  import { mergeSettingsIntoArgs } from './server/lib/settings-merge.js';
19
+ import { splitSdkLaunchArgs } from './server/lib/launch-config.js';
19
20
  import { createHardenedCleanup, installWinKeypressFallback } from './server/lib/term-signals.js';
20
21
 
21
22
  const __dirname = fileURLToPath(new URL('.', import.meta.url));
@@ -486,7 +487,7 @@ async function runCliMode(extraClaudeArgs = [], cwd, noOpen = false) {
486
487
  // IM worker:服务器监听成功后把真实端口回填进 im.lock(manager 据此做 HTTP 身份探测)
487
488
  if (process.env.CCV_IM_PLATFORM) {
488
489
  try {
489
- const { updateImLockPort } = await import('./server/lib/im-lock.js');
490
+ const { updateImLockPort } = await import('./server/lib/im/im-lock.js');
490
491
  updateImLockPort(process.env.CCV_IM_PLATFORM, port);
491
492
  } catch (e) {
492
493
  console.error('[CC Viewer] updateImLockPort failed:', e.message);
@@ -587,15 +588,15 @@ async function runCliMode(extraClaudeArgs = [], cwd, noOpen = false) {
587
588
  // 外加:全局唯一锁、CC_APPEND_SYSTEM.md 人格预置/迁移、IM 专属 env。由 im-process-manager 以 detached 子进程拉起,
588
589
  // 也可手动 `ccv --im <id>` 启动。
589
590
  async function runImMode(platformId) {
590
- const { getDescriptor } = await import('./server/lib/im-config.js');
591
+ const { getDescriptor } = await import('./server/lib/im/im-config.js');
591
592
  if (!getDescriptor(platformId)) {
592
593
  console.error(t('cli.imUnknownPlatform', { id: platformId }));
593
594
  process.exit(1);
594
595
  }
595
596
 
596
- const { acquireImLock, releaseImLock, imDir } = await import('./server/lib/im-lock.js');
597
- const { ensureImAppendSystem, migrateImClaudeMd } = await import('./server/lib/im-append-system.js');
598
- const { ensureImBuiltinSkills } = await import('./server/lib/im-skills.js');
597
+ const { acquireImLock, releaseImLock, imDir } = await import('./server/lib/im/im-lock.js');
598
+ const { ensureImAppendSystem, migrateImClaudeMd } = await import('./server/lib/im/im-append-system.js');
599
+ const { ensureImBuiltinSkills } = await import('./server/lib/im/im-skills.js');
599
600
 
600
601
  const dir = imDir(platformId);
601
602
  mkdirSync(dir, { recursive: true });
@@ -653,14 +654,21 @@ async function runSdkMode(extraClaudeArgs = [], cwd, noOpen = false) {
653
654
  const { registerWorkspace } = await import('./server/workspace-registry.js');
654
655
  await registerWorkspace(workingDir);
655
656
 
656
- // 不需要 ensureHooks — SDK canUseTool 处理 AskUserQuestion + 权限
657
- // 不需要 proxy SDK 直接管理 API 通信
657
+ // 不需要 ensureHooks — SDK canUseTool 处理 AskUserQuestion + 权限;
658
+ // 也不向子进程注入 CCVIEWER_PORT,让 CCV settings bridges 保持休眠,避免双通道审批。
658
659
 
659
- // 设置环境标记(必须在 import server.js 之前)
660
+ // 设置环境标记(必须在 import proxy.js / server.js 之前 — proxy.js → interceptor.js
661
+ // 可能触发 server.js 加载,而 server.js 的 isCliMode/isSdkMode 在模块顶层求值且只执行一次)
660
662
  process.env.CCV_CLI_MODE = '1';
661
663
  process.env.CCV_SDK_MODE = '1';
662
664
  process.env.CCV_PROJECT_DIR = workingDir;
663
- process.env.CCV_PROXY_MODE = '1'; // 使 interceptor.js 惰性
665
+ process.env.CCV_PROXY_MODE = '1';
666
+
667
+ // 启动本地回环代理 — SDK 子进程的 API 流量经 ANTHROPIC_BASE_URL 指向这里,
668
+ // 报文捕获/落盘/流式推送与 PTY 模式走同一条 wire 通路
669
+ const { startProxy } = await import('./server/proxy.js');
670
+ const proxyPort = await startProxy();
671
+ process.env.CCV_PROXY_PORT = String(proxyPort);
664
672
 
665
673
  // 启动 HTTP 服务器
666
674
  const serverMod = await import('./server/server.js');
@@ -685,12 +693,75 @@ async function runSdkMode(extraClaudeArgs = [], cwd, noOpen = false) {
685
693
  permissionMode = 'bypassPermissions';
686
694
  }
687
695
 
696
+ // 合并用户 --settings 与注入的 env.ANTHROPIC_BASE_URL(与 PTY 的 --settings 注入
697
+ // 等价、同一 helper,注入键优先);SDK 模式下经 options.settings 传给 query()。
698
+ // settingsMerge.args 已剥离 --settings;其余参数(--model/-c/-r 等)的映射后续接入。
699
+ const proxyBaseUrl = `http://127.0.0.1:${proxyPort}`;
700
+ const settingsMerge = mergeSettingsIntoArgs(extraClaudeArgs, { env: { ANTHROPIC_BASE_URL: proxyBaseUrl } }, { cwd: workingDir });
701
+ if (settingsMerge.warningDetail) {
702
+ console.warn(`[CC Viewer] --settings merge failed (${settingsMerge.warningDetail.reason}): ${settingsMerge.warningDetail.value}`);
703
+ }
704
+
705
+ // 子进程 env:代理指向 + 禁自动更新 + EDITOR 劫持(对齐 pty-manager 的注入面;
706
+ // 刻意不注入 CCVIEWER_PORT/PROTOCOL/INTERNAL_TOKEN — settings bridges 在 SDK 模式休眠)
707
+ const editorScript = resolve(__dirname, 'server', 'lib', 'ccv-editor.js');
708
+ const childEnv = {
709
+ ...process.env,
710
+ ANTHROPIC_BASE_URL: proxyBaseUrl,
711
+ // 与 PTY 子进程同款(pty-manager.js:247):SDK 子进程的 cli.js 若已被 -logger/PTY 注入
712
+ // interceptor,CCV_PROXY_MODE=1 让它只装 fetch hook 而不再自起 server;wire 捕获本来
713
+ // 就发生在主进程 proxy 的出站 fetch(ANTHROPIC_BASE_URL 指过来),此键保证子进程不双起。
714
+ CCV_PROXY_MODE: '1',
715
+ CCV_LOG_DIR: process.env.CCV_LOG_DIR || LOG_DIR,
716
+ DISABLE_AUTOUPDATER: '1',
717
+ EDITOR: `${process.execPath} ${editorScript}`,
718
+ VISUAL: `${process.execPath} ${editorScript}`,
719
+ CCV_EDITOR_PORT: String(port),
720
+ };
721
+ // 与 PTY 同款剥离(pty-manager.js:250-256):内部短路开关与 server 专属模式标记不外泄。
722
+ delete childEnv.CCV_SKIP_THINKING_DISPLAY;
723
+ delete childEnv.CCV_WORKSPACE_MODE;
724
+ delete childEnv.CCV_ELECTRON_MULTITAB;
725
+
726
+ // 用户参数映射到 SDK options:--model/-c/-r/--fork-session 提升为 SDK 原生 option
727
+ // (resume-pin 语义也需要它们),其余参数经 extraArgs 原样透传给 CLI 子进程。
728
+ // 不再静默丢弃任何参数。
729
+ const sdkArgs = splitSdkLaunchArgs(settingsMerge.args);
730
+ if (sdkArgs.pickerResume) {
731
+ console.warn('[CC Viewer] SDK mode: bare -r (interactive session picker) is not supported headless — starting a fresh session. Use -r <sessionId> to resume a specific session.');
732
+ }
733
+
688
734
  // 初始化 SDK 会话
735
+ // claudeExecutable 走与 PTY 相同的解析优先级(configured → codefuse → native → PATH → npm)。
736
+ // 缺了它 SDK 会从 PATH 解析 claude,在装有 agent-security headless guard 的机器上
737
+ // 会挑到一个 spawn 即被 SIGKILL 的二进制(PTY 交互式终端不在其拦截范围,headless 正中)。
738
+ let sdkClaudeSelection = null;
739
+ try {
740
+ sdkClaudeSelection = assertUsableClaudeSelection(resolvePreferredClaudeSelection());
741
+ } catch (err) {
742
+ console.error(`[CC Viewer] ${err.message}`);
743
+ process.exit(1);
744
+ }
745
+ const sdkClaudePath = sdkClaudeSelection?.path || null;
746
+ if (sdkClaudePath) {
747
+ process.env.CCV_CLAUDE_EXECUTABLE = sdkClaudePath;
748
+ console.log(`[CC Viewer] SDK mode: claude executable → ${sdkClaudePath} (${sdkClaudeSelection.source})`);
749
+ } else {
750
+ console.warn('[CC Viewer] SDK mode: no claude executable resolved — SDK will fall back to PATH/builtin discovery.');
751
+ }
752
+ // 观测面走与 PTY 相同的 wire 通路(SDK 子进程流量经 ANTHROPIC_BASE_URL 到 ccv proxy →
753
+ // fetch hook → v2 transcript → SSE),sdk-manager 不再另接 v2/streaming 注入。
689
754
  sdkManager.initSdkSession(workingDir, basename(workingDir), {
690
- onEntry: (entry) => serverMod.pushSdkEntry(entry),
691
- onStreamingStatus: (data) => serverMod.setSdkStreamingState(data),
692
755
  broadcastWs: (msg) => serverMod.broadcastWsMessage(msg),
693
756
  permissionMode,
757
+ env: childEnv,
758
+ settings: JSON.parse(settingsMerge.settingsJson),
759
+ model: sdkArgs.model,
760
+ claudeExecutable: sdkClaudePath,
761
+ launchResume: (sdkArgs.continue || sdkArgs.resume || sdkArgs.forkSession)
762
+ ? { continue: sdkArgs.continue, resumeId: sdkArgs.resume, forkSession: sdkArgs.forkSession }
763
+ : null,
764
+ userArgs: sdkArgs.rest,
694
765
  runWaterfallHook: (await import('./server/lib/plugin-loader.js')).runWaterfallHook,
695
766
  // Round-3 P0: SDK mode has no Stop hook (ensureHooks() skipped above), so
696
767
  // the only place we learn a turn ended is the SDK 'result' message. Forward
@@ -707,6 +778,9 @@ async function runSdkMode(extraClaudeArgs = [], cwd, noOpen = false) {
707
778
  try { serverMod.broadcastTurnEnd(sessionId, ts); }
708
779
  catch (err) { console.warn('[sdk] broadcastTurnEnd threw:', err?.message); }
709
780
  },
781
+ // query 级失败(spawn/protocol/iterator)推到 Web UI toast —— 此前只有 console.error,
782
+ // 死掉的 query 在 UI 上看与挂起无异。
783
+ onQueryError: (message) => serverMod.broadcastWsMessage({ type: 'sdk-error', message }),
710
784
  });
711
785
 
712
786
  // 注册 SDK 回调到 server.js(WS 消息路由用)
@@ -714,6 +788,13 @@ async function runSdkMode(extraClaudeArgs = [], cwd, noOpen = false) {
714
788
  serverMod.setSdkCancelApproval(sdkManager.cancelApproval);
715
789
  serverMod.setSdkSendUserMessage(sdkManager.sendUserMessage);
716
790
  serverMod.setSdkInterruptTurn(sdkManager.interruptTurn);
791
+ serverMod.setSdkGetPendingApprovals(sdkManager.getPendingApprovals);
792
+ serverMod.setSdkGetInitSnapshot(sdkManager.getSdkInitSnapshot);
793
+ // Busy-queue bubble actions (queue-send-now / queue-remove / queue-clear / replay).
794
+ serverMod.setSdkSendQueuedNow(sdkManager.sendQueuedNow);
795
+ serverMod.setSdkRemoveQueued(sdkManager.removeQueued);
796
+ serverMod.setSdkClearQueued(sdkManager.clearQueued);
797
+ serverMod.setSdkGetQueueSnapshot(sdkManager.getQueueSnapshot);
717
798
 
718
799
  // 自动打开浏览器
719
800
  const protocol = serverMod.getProtocol();
@@ -122,12 +122,12 @@ CC-Viewer 自动注册到 `~/.claude/settings.json` 的 `hooks.PreToolUse` 中
122
122
 
123
123
  ### 1. AskUserQuestion 桥接
124
124
  - **匹配器**: `"AskUserQuestion"`
125
- - **命令**: `node <安装目录>/server/lib/ask-bridge.js`
125
+ - **命令**: `node <安装目录>/server/lib/ask/ask-bridge.js`
126
126
  - **作用**: 将 Claude 的问题转发到 Web UI,等待用户回答
127
127
 
128
128
  ### 2. 权限审批桥接
129
129
  - **匹配器**: `""` (空 = 匹配所有工具)
130
- - **命令**: `node <安装目录>/server/lib/perm-bridge.js`
130
+ - **命令**: `node <安装目录>/server/lib/ask/perm-bridge.js`
131
131
  - **作用**: 仅 `Bash`/`Edit`/`Write`/`NotebookEdit` 需要 Web UI 审批,其余自动放行
132
132
 
133
133
  ## 七、Shell 集成
@@ -122,12 +122,12 @@ CC-Viewer 自动注册到 `~/.claude/settings.json` 的 `hooks.PreToolUse` 中
122
122
 
123
123
  ### 1. AskUserQuestion 桥接
124
124
  - **匹配器**: `"AskUserQuestion"`
125
- - **命令**: `node <安装目录>/server/lib/ask-bridge.js`
125
+ - **命令**: `node <安装目录>/server/lib/ask/ask-bridge.js`
126
126
  - **作用**: 将 Claude 的问题转发到 Web UI,等待用户回答
127
127
 
128
128
  ### 2. 权限审批桥接
129
129
  - **匹配器**: `""` (空 = 匹配所有工具)
130
- - **命令**: `node <安装目录>/server/lib/perm-bridge.js`
130
+ - **命令**: `node <安装目录>/server/lib/ask/perm-bridge.js`
131
131
  - **作用**: 仅 `Bash`/`Edit`/`Write`/`NotebookEdit` 需要 Web UI 审批,其余自动放行
132
132
 
133
133
  ## 七、Shell 集成
@@ -122,12 +122,12 @@ CC-Viewer 自动注册到 `~/.claude/settings.json` 的 `hooks.PreToolUse` 中
122
122
 
123
123
  ### 1. AskUserQuestion 桥接
124
124
  - **匹配器**: `"AskUserQuestion"`
125
- - **命令**: `node <安装目录>/server/lib/ask-bridge.js`
125
+ - **命令**: `node <安装目录>/server/lib/ask/ask-bridge.js`
126
126
  - **作用**: 将 Claude 的问题转发到 Web UI,等待用户回答
127
127
 
128
128
  ### 2. 权限审批桥接
129
129
  - **匹配器**: `""` (空 = 匹配所有工具)
130
- - **命令**: `node <安装目录>/server/lib/perm-bridge.js`
130
+ - **命令**: `node <安装目录>/server/lib/ask/perm-bridge.js`
131
131
  - **作用**: 仅 `Bash`/`Edit`/`Write`/`NotebookEdit` 需要 Web UI 审批,其余自动放行
132
132
 
133
133
  ## 七、Shell 集成
@@ -125,12 +125,12 @@ CC-Viewer auto-registers hooks in `~/.claude/settings.json` under `hooks.PreTool
125
125
 
126
126
  ### 1. AskUserQuestion Bridge
127
127
  - **Matcher**: `"AskUserQuestion"`
128
- - **Command**: `node <install_dir>/server/lib/ask-bridge.js`
128
+ - **Command**: `node <install_dir>/server/lib/ask/ask-bridge.js`
129
129
  - **Purpose**: Forward Claude's questions to Web UI, wait for user answers
130
130
 
131
131
  ### 2. Permission Approval Bridge
132
132
  - **Matcher**: `""` (empty = match all tools)
133
- - **Command**: `node <install_dir>/server/lib/perm-bridge.js`
133
+ - **Command**: `node <install_dir>/server/lib/ask/perm-bridge.js`
134
134
  - **Purpose**: Only `Bash`/`Edit`/`Write`/`NotebookEdit` require Web UI approval; others pass through
135
135
 
136
136
  ## 7. Shell Integration
@@ -122,12 +122,12 @@ CC-Viewer 自动注册到 `~/.claude/settings.json` 的 `hooks.PreToolUse` 中
122
122
 
123
123
  ### 1. AskUserQuestion 桥接
124
124
  - **匹配器**: `"AskUserQuestion"`
125
- - **命令**: `node <安装目录>/server/lib/ask-bridge.js`
125
+ - **命令**: `node <安装目录>/server/lib/ask/ask-bridge.js`
126
126
  - **作用**: 将 Claude 的问题转发到 Web UI,等待用户回答
127
127
 
128
128
  ### 2. 权限审批桥接
129
129
  - **匹配器**: `""` (空 = 匹配所有工具)
130
- - **命令**: `node <安装目录>/server/lib/perm-bridge.js`
130
+ - **命令**: `node <安装目录>/server/lib/ask/perm-bridge.js`
131
131
  - **作用**: 仅 `Bash`/`Edit`/`Write`/`NotebookEdit` 需要 Web UI 审批,其余自动放行
132
132
 
133
133
  ## 七、Shell 集成
@@ -122,12 +122,12 @@ CC-Viewer 自动注册到 `~/.claude/settings.json` 的 `hooks.PreToolUse` 中
122
122
 
123
123
  ### 1. AskUserQuestion 桥接
124
124
  - **匹配器**: `"AskUserQuestion"`
125
- - **命令**: `node <安装目录>/server/lib/ask-bridge.js`
125
+ - **命令**: `node <安装目录>/server/lib/ask/ask-bridge.js`
126
126
  - **作用**: 将 Claude 的问题转发到 Web UI,等待用户回答
127
127
 
128
128
  ### 2. 权限审批桥接
129
129
  - **匹配器**: `""` (空 = 匹配所有工具)
130
- - **命令**: `node <安装目录>/server/lib/perm-bridge.js`
130
+ - **命令**: `node <安装目录>/server/lib/ask/perm-bridge.js`
131
131
  - **作用**: 仅 `Bash`/`Edit`/`Write`/`NotebookEdit` 需要 Web UI 审批,其余自动放行
132
132
 
133
133
  ## 七、Shell 集成
@@ -122,12 +122,12 @@ CC-Viewer 自动注册到 `~/.claude/settings.json` 的 `hooks.PreToolUse` 中
122
122
 
123
123
  ### 1. AskUserQuestion 桥接
124
124
  - **匹配器**: `"AskUserQuestion"`
125
- - **命令**: `node <安装目录>/server/lib/ask-bridge.js`
125
+ - **命令**: `node <安装目录>/server/lib/ask/ask-bridge.js`
126
126
  - **作用**: 将 Claude 的问题转发到 Web UI,等待用户回答
127
127
 
128
128
  ### 2. 权限审批桥接
129
129
  - **匹配器**: `""` (空 = 匹配所有工具)
130
- - **命令**: `node <安装目录>/server/lib/perm-bridge.js`
130
+ - **命令**: `node <安装目录>/server/lib/ask/perm-bridge.js`
131
131
  - **作用**: 仅 `Bash`/`Edit`/`Write`/`NotebookEdit` 需要 Web UI 审批,其余自动放行
132
132
 
133
133
  ## 七、Shell 集成
@@ -122,12 +122,12 @@ CC-Viewer 自动注册到 `~/.claude/settings.json` 的 `hooks.PreToolUse` 中
122
122
 
123
123
  ### 1. AskUserQuestion 桥接
124
124
  - **匹配器**: `"AskUserQuestion"`
125
- - **命令**: `node <安装目录>/server/lib/ask-bridge.js`
125
+ - **命令**: `node <安装目录>/server/lib/ask/ask-bridge.js`
126
126
  - **作用**: 将 Claude 的问题转发到 Web UI,等待用户回答
127
127
 
128
128
  ### 2. 权限审批桥接
129
129
  - **匹配器**: `""` (空 = 匹配所有工具)
130
- - **命令**: `node <安装目录>/server/lib/perm-bridge.js`
130
+ - **命令**: `node <安装目录>/server/lib/ask/perm-bridge.js`
131
131
  - **作用**: 仅 `Bash`/`Edit`/`Write`/`NotebookEdit` 需要 Web UI 审批,其余自动放行
132
132
 
133
133
  ## 七、Shell 集成
@@ -122,12 +122,12 @@ CC-Viewer 自动注册到 `~/.claude/settings.json` 的 `hooks.PreToolUse` 中
122
122
 
123
123
  ### 1. AskUserQuestion 桥接
124
124
  - **匹配器**: `"AskUserQuestion"`
125
- - **命令**: `node <安装目录>/server/lib/ask-bridge.js`
125
+ - **命令**: `node <安装目录>/server/lib/ask/ask-bridge.js`
126
126
  - **作用**: 将 Claude 的问题转发到 Web UI,等待用户回答
127
127
 
128
128
  ### 2. 权限审批桥接
129
129
  - **匹配器**: `""` (空 = 匹配所有工具)
130
- - **命令**: `node <安装目录>/server/lib/perm-bridge.js`
130
+ - **命令**: `node <安装目录>/server/lib/ask/perm-bridge.js`
131
131
  - **作用**: 仅 `Bash`/`Edit`/`Write`/`NotebookEdit` 需要 Web UI 审批,其余自动放行
132
132
 
133
133
  ## 七、Shell 集成
@@ -122,12 +122,12 @@ CC-Viewer 自动注册到 `~/.claude/settings.json` 的 `hooks.PreToolUse` 中
122
122
 
123
123
  ### 1. AskUserQuestion 桥接
124
124
  - **匹配器**: `"AskUserQuestion"`
125
- - **命令**: `node <安装目录>/server/lib/ask-bridge.js`
125
+ - **命令**: `node <安装目录>/server/lib/ask/ask-bridge.js`
126
126
  - **作用**: 将 Claude 的问题转发到 Web UI,等待用户回答
127
127
 
128
128
  ### 2. 权限审批桥接
129
129
  - **匹配器**: `""` (空 = 匹配所有工具)
130
- - **命令**: `node <安装目录>/server/lib/perm-bridge.js`
130
+ - **命令**: `node <安装目录>/server/lib/ask/perm-bridge.js`
131
131
  - **作用**: 仅 `Bash`/`Edit`/`Write`/`NotebookEdit` 需要 Web UI 审批,其余自动放行
132
132
 
133
133
  ## 七、Shell 集成
@@ -122,12 +122,12 @@ CC-Viewer 自动注册到 `~/.claude/settings.json` 的 `hooks.PreToolUse` 中
122
122
 
123
123
  ### 1. AskUserQuestion 桥接
124
124
  - **匹配器**: `"AskUserQuestion"`
125
- - **命令**: `node <安装目录>/server/lib/ask-bridge.js`
125
+ - **命令**: `node <安装目录>/server/lib/ask/ask-bridge.js`
126
126
  - **作用**: 将 Claude 的问题转发到 Web UI,等待用户回答
127
127
 
128
128
  ### 2. 权限审批桥接
129
129
  - **匹配器**: `""` (空 = 匹配所有工具)
130
- - **命令**: `node <安装目录>/server/lib/perm-bridge.js`
130
+ - **命令**: `node <安装目录>/server/lib/ask/perm-bridge.js`
131
131
  - **作用**: 仅 `Bash`/`Edit`/`Write`/`NotebookEdit` 需要 Web UI 审批,其余自动放行
132
132
 
133
133
  ## 七、Shell 集成
@@ -122,12 +122,12 @@ CC-Viewer 自动注册到 `~/.claude/settings.json` 的 `hooks.PreToolUse` 中
122
122
 
123
123
  ### 1. AskUserQuestion 桥接
124
124
  - **匹配器**: `"AskUserQuestion"`
125
- - **命令**: `node <安装目录>/server/lib/ask-bridge.js`
125
+ - **命令**: `node <安装目录>/server/lib/ask/ask-bridge.js`
126
126
  - **作用**: 将 Claude 的问题转发到 Web UI,等待用户回答
127
127
 
128
128
  ### 2. 权限审批桥接
129
129
  - **匹配器**: `""` (空 = 匹配所有工具)
130
- - **命令**: `node <安装目录>/server/lib/perm-bridge.js`
130
+ - **命令**: `node <安装目录>/server/lib/ask/perm-bridge.js`
131
131
  - **作用**: 仅 `Bash`/`Edit`/`Write`/`NotebookEdit` 需要 Web UI 审批,其余自动放行
132
132
 
133
133
  ## 七、Shell 集成
@@ -122,12 +122,12 @@ CC-Viewer 自动注册到 `~/.claude/settings.json` 的 `hooks.PreToolUse` 中
122
122
 
123
123
  ### 1. AskUserQuestion 桥接
124
124
  - **匹配器**: `"AskUserQuestion"`
125
- - **命令**: `node <安装目录>/server/lib/ask-bridge.js`
125
+ - **命令**: `node <安装目录>/server/lib/ask/ask-bridge.js`
126
126
  - **作用**: 将 Claude 的问题转发到 Web UI,等待用户回答
127
127
 
128
128
  ### 2. 权限审批桥接
129
129
  - **匹配器**: `""` (空 = 匹配所有工具)
130
- - **命令**: `node <安装目录>/server/lib/perm-bridge.js`
130
+ - **命令**: `node <安装目录>/server/lib/ask/perm-bridge.js`
131
131
  - **作用**: 仅 `Bash`/`Edit`/`Write`/`NotebookEdit` 需要 Web UI 审批,其余自动放行
132
132
 
133
133
  ## 七、Shell 集成
@@ -122,12 +122,12 @@ CC-Viewer 自动注册到 `~/.claude/settings.json` 的 `hooks.PreToolUse` 中
122
122
 
123
123
  ### 1. AskUserQuestion 桥接
124
124
  - **匹配器**: `"AskUserQuestion"`
125
- - **命令**: `node <安装目录>/server/lib/ask-bridge.js`
125
+ - **命令**: `node <安装目录>/server/lib/ask/ask-bridge.js`
126
126
  - **作用**: 将 Claude 的问题转发到 Web UI,等待用户回答
127
127
 
128
128
  ### 2. 权限审批桥接
129
129
  - **匹配器**: `""` (空 = 匹配所有工具)
130
- - **命令**: `node <安装目录>/server/lib/perm-bridge.js`
130
+ - **命令**: `node <安装目录>/server/lib/ask/perm-bridge.js`
131
131
  - **作用**: 仅 `Bash`/`Edit`/`Write`/`NotebookEdit` 需要 Web UI 审批,其余自动放行
132
132
 
133
133
  ## 七、Shell 集成
@@ -122,12 +122,12 @@ CC-Viewer 自动注册到 `~/.claude/settings.json` 的 `hooks.PreToolUse` 中
122
122
 
123
123
  ### 1. AskUserQuestion 桥接
124
124
  - **匹配器**: `"AskUserQuestion"`
125
- - **命令**: `node <安装目录>/server/lib/ask-bridge.js`
125
+ - **命令**: `node <安装目录>/server/lib/ask/ask-bridge.js`
126
126
  - **作用**: 将 Claude 的问题转发到 Web UI,等待用户回答
127
127
 
128
128
  ### 2. 权限审批桥接
129
129
  - **匹配器**: `""` (空 = 匹配所有工具)
130
- - **命令**: `node <安装目录>/server/lib/perm-bridge.js`
130
+ - **命令**: `node <安装目录>/server/lib/ask/perm-bridge.js`
131
131
  - **作用**: 仅 `Bash`/`Edit`/`Write`/`NotebookEdit` 需要 Web UI 审批,其余自动放行
132
132
 
133
133
  ## 七、Shell 集成
@@ -122,12 +122,12 @@ CC-Viewer 自动注册到 `~/.claude/settings.json` 的 `hooks.PreToolUse` 中
122
122
 
123
123
  ### 1. AskUserQuestion 桥接
124
124
  - **匹配器**: `"AskUserQuestion"`
125
- - **命令**: `node <安装目录>/server/lib/ask-bridge.js`
125
+ - **命令**: `node <安装目录>/server/lib/ask/ask-bridge.js`
126
126
  - **作用**: 将 Claude 的问题转发到 Web UI,等待用户回答
127
127
 
128
128
  ### 2. 权限审批桥接
129
129
  - **匹配器**: `""` (空 = 匹配所有工具)
130
- - **命令**: `node <安装目录>/server/lib/perm-bridge.js`
130
+ - **命令**: `node <安装目录>/server/lib/ask/perm-bridge.js`
131
131
  - **作用**: 仅 `Bash`/`Edit`/`Write`/`NotebookEdit` 需要 Web UI 审批,其余自动放行
132
132
 
133
133
  ## 七、Shell 集成
@@ -123,12 +123,12 @@ CC-Viewer 自动注册到 `~/.claude/settings.json` 的 `hooks.PreToolUse` 中
123
123
 
124
124
  ### 1. AskUserQuestion 桥接
125
125
  - **匹配器**: `"AskUserQuestion"`
126
- - **命令**: `node <安装目录>/server/lib/ask-bridge.js`
126
+ - **命令**: `node <安装目录>/server/lib/ask/ask-bridge.js`
127
127
  - **作用**: 将 Claude 的问题转发到 Web UI,等待用户回答
128
128
 
129
129
  ### 2. 权限审批桥接
130
130
  - **匹配器**: `""` (空 = 匹配所有工具)
131
- - **命令**: `node <安装目录>/server/lib/perm-bridge.js`
131
+ - **命令**: `node <安装目录>/server/lib/ask/perm-bridge.js`
132
132
  - **作用**: 仅 `Bash`/`Edit`/`Write`/`NotebookEdit` 需要 Web UI 审批,其余自动放行
133
133
 
134
134
  ## 七、Shell 集成
@@ -122,12 +122,12 @@ CC-Viewer 自动注册到 `~/.claude/settings.json` 的 `hooks.PreToolUse` 中
122
122
 
123
123
  ### 1. AskUserQuestion 桥接
124
124
  - **匹配器**: `"AskUserQuestion"`
125
- - **命令**: `node <安装目录>/server/lib/ask-bridge.js`
125
+ - **命令**: `node <安装目录>/server/lib/ask/ask-bridge.js`
126
126
  - **作用**: 将 Claude 的问题转发到 Web UI,等待用户回答
127
127
 
128
128
  ### 2. 权限审批桥接
129
129
  - **匹配器**: `""` (空 = 匹配所有工具)
130
- - **命令**: `node <安装目录>/server/lib/perm-bridge.js`
130
+ - **命令**: `node <安装目录>/server/lib/ask/perm-bridge.js`
131
131
  - **作用**: 仅 `Bash`/`Edit`/`Write`/`NotebookEdit` 需要 Web UI 审批,其余自动放行
132
132
 
133
133
  ## 七、Shell 集成