cc-viewer 1.8.19 → 1.8.21

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 (130) hide show
  1. package/README.md +3 -1
  2. package/cli.js +33 -4
  3. package/dist/assets/App-BmZyzd9Q.js +2 -0
  4. package/dist/assets/App-DOZI5HME.css +1 -0
  5. package/dist/assets/{MdxEditorPanel-DU_5CRtW.js → MdxEditorPanel-BHvoYOF-.js} +1 -1
  6. package/dist/assets/{MdxEditorPanel-Dpn-4ydO.css → MdxEditorPanel-DTfdj6GS.css} +1 -1
  7. package/dist/assets/Mobile-C10tOIQo.js +1 -0
  8. package/dist/assets/ProxyStatsModal-Do4qrHT7.js +1 -0
  9. package/dist/assets/{_baseUniq-B3e4JaL0.js → _baseUniq-CwQykUuc.js} +1 -1
  10. package/dist/assets/{arc-DnoPn_qY.js → arc-EdUdBxtG.js} +1 -1
  11. package/dist/assets/{architectureDiagram-Q4EWVU46-DrPKTbxH.js → architectureDiagram-Q4EWVU46-DtBIdElY.js} +1 -1
  12. package/dist/assets/{blockDiagram-DXYQGD6D-CEaO0Vcw.js → blockDiagram-DXYQGD6D-guNZIKkZ.js} +1 -1
  13. package/dist/assets/{c4Diagram-AHTNJAMY-BLaawFeg.js → c4Diagram-AHTNJAMY-xV5vB-Z9.js} +1 -1
  14. package/dist/assets/{channel-DnYR1fF4.js → channel-DYEktNap.js} +1 -1
  15. package/dist/assets/{chunk-4BX2VUAB-Bfd4edKZ.js → chunk-4BX2VUAB-ZTkItpvj.js} +1 -1
  16. package/dist/assets/{chunk-4TB4RGXK-t2nMQmY7.js → chunk-4TB4RGXK-dYIewyyR.js} +1 -1
  17. package/dist/assets/{chunk-55IACEB6-C6tLOjGX.js → chunk-55IACEB6-CSsPNgPX.js} +1 -1
  18. package/dist/assets/{chunk-EDXVE4YY-dWCvxbCb.js → chunk-EDXVE4YY-CnMiuqzQ.js} +1 -1
  19. package/dist/assets/{chunk-FMBD7UC4-BHELZLPK.js → chunk-FMBD7UC4-CVpATPZ3.js} +1 -1
  20. package/dist/assets/{chunk-OYMX7WX6-C8XTkH1S.js → chunk-OYMX7WX6-Dpq4s8dW.js} +1 -1
  21. package/dist/assets/{chunk-QZHKN3VN-CD0j6SAs.js → chunk-QZHKN3VN-Bnojh6X6.js} +1 -1
  22. package/dist/assets/{chunk-YZCP3GAM-D4dKfXJJ.js → chunk-YZCP3GAM-BYqK4Dsa.js} +1 -1
  23. package/dist/assets/classDiagram-6PBFFD2Q-ClGF33bF.js +1 -0
  24. package/dist/assets/classDiagram-v2-HSJHXN6E-ClGF33bF.js +1 -0
  25. package/dist/assets/clone-CFj55h49.js +1 -0
  26. package/dist/assets/{cose-bilkent-S5V4N54A-BF2HsiSD.js → cose-bilkent-S5V4N54A-OJ7mmWyV.js} +1 -1
  27. package/dist/assets/{dagre-KV5264BT-f3h967yx.js → dagre-KV5264BT-B1Kwd_Rk.js} +1 -1
  28. package/dist/assets/{diagram-5BDNPKRD-B9PzHQfh.js → diagram-5BDNPKRD-D8qrw8sp.js} +1 -1
  29. package/dist/assets/{diagram-G4DWMVQ6-kR953Bqm.js → diagram-G4DWMVQ6-ip-N4ho8.js} +1 -1
  30. package/dist/assets/{diagram-MMDJMWI5-DAewa2eg.js → diagram-MMDJMWI5-2PZaskUF.js} +1 -1
  31. package/dist/assets/{diagram-TYMM5635-C8HNTH6I.js → diagram-TYMM5635-CeAOQUZP.js} +1 -1
  32. package/dist/assets/{erDiagram-SMLLAGMA-BQ5P8wWK.js → erDiagram-SMLLAGMA-BCBaEYEb.js} +1 -1
  33. package/dist/assets/{flowDiagram-DWJPFMVM-BIpEkrMR.js → flowDiagram-DWJPFMVM-CsGyIqcX.js} +1 -1
  34. package/dist/assets/{ganttDiagram-T4ZO3ILL-CWqSfB5v.js → ganttDiagram-T4ZO3ILL-COsj3FZ-.js} +1 -1
  35. package/dist/assets/{gitGraphDiagram-UUTBAWPF-Ba-9yEbQ.js → gitGraphDiagram-UUTBAWPF-DvQVQGJG.js} +1 -1
  36. package/dist/assets/{graph-D3zXKQ6P.js → graph-BSB9fDSP.js} +1 -1
  37. package/dist/assets/{index-G3xd-gLo.js → index-BRw4Iz2O.js} +1 -1
  38. package/dist/assets/{index-DClD_EkN.js → index-Bo-12bug.js} +1 -1
  39. package/dist/assets/{index-DSd5P3WQ.js → index-BuVComcY.js} +1 -1
  40. package/dist/assets/{index-HLrnYsI1.js → index-CNNAYjkF.js} +1 -1
  41. package/dist/assets/{index-Bm3A5VLb.js → index-DKufsAzx.js} +1 -1
  42. package/dist/assets/{index-C9N0rZ7Z.js → index-DXBfwPYD.js} +1 -1
  43. package/dist/assets/index-DyVKoGOX.js +2 -0
  44. package/dist/assets/{index-Nvk8r3tO.css → index-Dz36p_bA.css} +1 -1
  45. package/dist/assets/{index-Q8wp4Nof.js → index-eM2ih5n7.js} +1 -1
  46. package/dist/assets/{infoDiagram-42DDH7IO-Cxm79ZJR.js → infoDiagram-42DDH7IO-eNucS4iW.js} +1 -1
  47. package/dist/assets/{ishikawaDiagram-UXIWVN3A-Cd0vZP1B.js → ishikawaDiagram-UXIWVN3A-Dxxj-gUX.js} +1 -1
  48. package/dist/assets/{journeyDiagram-VCZTEJTY-B2b57HXk.js → journeyDiagram-VCZTEJTY-yJJzVEBb.js} +1 -1
  49. package/dist/assets/{jszip.min-Bj5uiEb2.js → jszip.min-ByI0ds5u.js} +1 -1
  50. package/dist/assets/{kanban-definition-6JOO6SKY-YCERiUCO.js → kanban-definition-6JOO6SKY-2rfTi2zw.js} +1 -1
  51. package/dist/assets/{layout-Do5TlO2U.js → layout-DTmHj0Wm.js} +1 -1
  52. package/dist/assets/{linear-BiJNTDgN.js → linear-BOA3a9FE.js} +1 -1
  53. package/dist/assets/{mermaid.core-Dg0McRZt.js → mermaid.core-5H-NR79H.js} +3 -3
  54. package/dist/assets/{min-T51iefht.js → min-CpjFTEec.js} +1 -1
  55. package/dist/assets/{mindmap-definition-QFDTVHPH-Cu_GJxY3.js → mindmap-definition-QFDTVHPH-B8KCjFgB.js} +1 -1
  56. package/dist/assets/{pieDiagram-DEJITSTG-DldHHZXi.js → pieDiagram-DEJITSTG-BARy96g5.js} +1 -1
  57. package/dist/assets/{quadrantDiagram-34T5L4WZ-BzyTPNAJ.js → quadrantDiagram-34T5L4WZ-DYoTapuI.js} +1 -1
  58. package/dist/assets/{requirementDiagram-MS252O5E-C5xxFkvG.js → requirementDiagram-MS252O5E-EeANLLK2.js} +1 -1
  59. package/dist/assets/{sankeyDiagram-XADWPNL6-OxdjoaE1.js → sankeyDiagram-XADWPNL6-DmQ-YVPj.js} +1 -1
  60. package/dist/assets/seqResourceLoaders-B-wmkeam.js +2 -0
  61. package/dist/assets/seqResourceLoaders-BdWMUSrC.css +41 -0
  62. package/dist/assets/{sequenceDiagram-FGHM5R23-C7c89uIS.js → sequenceDiagram-FGHM5R23-SZtW0rYC.js} +1 -1
  63. package/dist/assets/{stateDiagram-FHFEXIEX-ssdJnDrO.js → stateDiagram-FHFEXIEX-CEygsIld.js} +1 -1
  64. package/dist/assets/{stateDiagram-v2-QKLJ7IA2-BP-0WClK.js → stateDiagram-v2-QKLJ7IA2-BU1XPhBe.js} +1 -1
  65. package/dist/assets/{timeline-definition-GMOUNBTQ-sWScEpSM.js → timeline-definition-GMOUNBTQ-DhPBaQBt.js} +1 -1
  66. package/dist/assets/{vendor-antd-DKIytXho.js → vendor-antd-CS_S2mBN.js} +1 -1
  67. package/dist/assets/{vendor-codemirror-4qgXq03k.js → vendor-codemirror-B5l-VbBO.js} +1 -1
  68. package/dist/assets/{vendor-mdxeditor-D5Z5D9fq.js → vendor-mdxeditor-Cz09a1_I.js} +2 -2
  69. package/dist/assets/{vendor-qrcode-B7lb5qk1.js → vendor-qrcode-qbbntD6-.js} +1 -1
  70. package/dist/assets/{vendor-virtuoso-BqoXlbhH.js → vendor-virtuoso-Sk8fQ4Hx.js} +1 -1
  71. package/dist/assets/{vennDiagram-DHZGUBPP-DNfXR0ge.js → vennDiagram-DHZGUBPP-NniTHxDw.js} +1 -1
  72. package/dist/assets/{wardley-RL74JXVD-JXd--CRD.js → wardley-RL74JXVD-D9SNOrDw.js} +1 -1
  73. package/dist/assets/{wardleyDiagram-NUSXRM2D-DHmNyVPM.js → wardleyDiagram-NUSXRM2D-DvHXKNza.js} +1 -1
  74. package/dist/assets/{xychartDiagram-5P7HB3ND-CTb0gltZ.js → xychartDiagram-5P7HB3ND-CaiwPTQB.js} +1 -1
  75. package/dist/index.html +5 -5
  76. package/package.json +1 -1
  77. package/server/interceptor.js +192 -24
  78. package/server/lib/ask/ask-store.js +7 -3
  79. package/server/lib/async-file-lock.js +29 -5
  80. package/server/lib/auth.js +71 -54
  81. package/server/lib/chat-queue.js +67 -4
  82. package/server/lib/config-backup.js +8 -5
  83. package/server/lib/credential-access.js +233 -0
  84. package/server/lib/credential-migrate.js +147 -0
  85. package/server/lib/credential-store.js +120 -0
  86. package/server/lib/credential-vault.js +112 -0
  87. package/server/lib/file-access-policy.js +16 -0
  88. package/server/lib/im/im-config.js +81 -31
  89. package/server/lib/im-deny.js +22 -8
  90. package/server/lib/json-store.js +264 -0
  91. package/server/lib/prefs-store.js +8 -33
  92. package/server/lib/same-origin.js +22 -0
  93. package/server/lib/session-pin-store.js +7 -14
  94. package/server/lib/v2/convert.js +1 -1
  95. package/server/lib/v2/layout.js +28 -3
  96. package/server/lib/v2/live-feed.js +41 -4
  97. package/server/lib/v2/resume-list.js +150 -0
  98. package/server/lib/v2/session-select.js +63 -14
  99. package/server/lib/v2/v2-writer.js +172 -34
  100. package/server/lib/v2/view-router.js +83 -0
  101. package/server/lib/view-root.js +209 -0
  102. package/server/pty-manager.js +800 -163
  103. package/server/routes/ask-perm.js +21 -1
  104. package/server/routes/auth.js +21 -1
  105. package/server/routes/events.js +123 -7
  106. package/server/routes/expert.js +46 -14
  107. package/server/routes/files-content.js +72 -7
  108. package/server/routes/files-fs.js +28 -3
  109. package/server/routes/git.js +31 -5
  110. package/server/routes/preferences.js +59 -46
  111. package/server/routes/project-meta.js +32 -3
  112. package/server/routes/proxy-stats.js +33 -5
  113. package/server/routes/resume.js +302 -0
  114. package/server/routes/search.js +23 -1
  115. package/server/routes/skills.js +18 -2
  116. package/server/routes/v2.js +6 -1
  117. package/server/routes/workspaces.js +10 -3
  118. package/server/server.js +199 -25
  119. package/server/system-prompt-templates/presets/kimi-k3.md +1 -1
  120. package/server/workspace-registry.js +41 -35
  121. package/dist/assets/App-C9Tx6Iqw.js +0 -2
  122. package/dist/assets/App-M61pqQEx.css +0 -1
  123. package/dist/assets/Mobile--EECC49-.js +0 -1
  124. package/dist/assets/ProxyStatsModal-DJu0xq3Z.js +0 -1
  125. package/dist/assets/classDiagram-6PBFFD2Q-BecPAAuk.js +0 -1
  126. package/dist/assets/classDiagram-v2-HSJHXN6E-BecPAAuk.js +0 -1
  127. package/dist/assets/clone-B0_ghF3F.js +0 -1
  128. package/dist/assets/index-CJdRSHTP.js +0 -2
  129. package/dist/assets/seqResourceLoaders-BumAjQDW.css +0 -41
  130. package/dist/assets/seqResourceLoaders-C5UX6ecI.js +0 -2
package/README.md CHANGED
@@ -191,7 +191,7 @@ By default, remote (LAN) access requires the `?token=` query that ccv prints at
191
191
  * Remote devices opening the LAN URL (without a token) are shown a minimal password page; entering the correct password sets an `HttpOnly` cookie and the page refreshes into the app. The existing `?token=` URL keeps working in parallel.
192
192
  * An **empty password means no protection at all** — it is allowed, but the admin UI shows a clear security warning.
193
193
  * **Global default + per-project override:** by default one password covers every project. From the QR popover the admin can switch between **This project** and **Global** — set a project-specific password that overrides the global default for that project only, or remove the override to inherit the global setting again. (A disabled project override means "no protection for this project", which is different from removing it.)
194
- * The on/off state and password(s) are persisted alongside your other settings in cc-viewer's `preferences.json` — a global `auth` key plus an optional `authByProject` map (the password is base64-obfuscated, not stored as raw plaintext; file mode `0600`). The login cookie is tied to the per-launch token, so restarting ccv requires remote devices to log in again.
194
+ * The on/off state is persisted alongside your other settings in cc-viewer's `preferences.json` — a global `auth` key plus an optional `authByProject` map (file mode `0600`). The password itself is **not** kept there: it is encrypted at rest (AES-256-GCM) in `credentials.json` under the same data root, with the machine-local key in `master.key` (both mode `0600`). The login cookie is tied to the per-launch token, so restarting ccv requires remote devices to log in again.
195
195
 
196
196
  ### Container / cloud deployment (remote admin)
197
197
 
@@ -205,6 +205,8 @@ cc-viewer works in a single container or on a cloud host where you reach the UI
205
205
  * **Security recommendations for a public/cloud deployment:** enable password login (or keep the random `?token=` URL secret), and put the instance behind a reverse proxy that terminates HTTPS. Persist the log/settings directory by mounting a volume at the path pointed to by `CCV_LOG_DIR` (default `~/.claude/cc-viewer`) so your preferences, auth password, and IM credentials survive container restarts.
206
206
  * **Reverse-proxy note:** access control is based on the socket peer address (`X-Forwarded-For` is deliberately not trusted, to prevent spoofing). This does not affect remote admins — they authenticate by token/password, not by IP. It only means "same-container" detection relies on a real loopback connection.
207
207
 
208
+ * **Design doc:** how local config maps to a cloud database and the cloud-sync model (cloud-authoritative, local read-only fallback) is described in [Config Convergence & Cloud-Sync Advisory](./docs/config-cloud-sync.md) ([中文](./docs/config-cloud-sync.zh.md)). This is a proposal, not yet implemented.
209
+
208
210
 
209
211
  ### Model-specific system prompts
210
212
 
package/cli.js CHANGED
@@ -19,6 +19,7 @@ import { normalizeBasePath } from './server/lib/base-path.js';
19
19
  import { mergeSettingsIntoArgs } from './server/lib/settings-merge.js';
20
20
  import { splitSdkLaunchArgs, resolveLaunchSystemPrompt, insertBeforeDashDash } from './server/lib/launch-config.js';
21
21
  import { createHardenedCleanup, installWinKeypressFallback } from './server/lib/term-signals.js';
22
+ import { reportSwallowed } from '@ccv/core/error-report';
22
23
 
23
24
  const __dirname = fileURLToPath(new URL('.', import.meta.url));
24
25
 
@@ -552,7 +553,7 @@ async function runCliMode(extraClaudeArgs = [], cwd, noOpen = false) {
552
553
  }
553
554
 
554
555
  // 3. 启动 PTY 中的 claude
555
- const { spawnClaude, killPty, onPtyExit } = await import('./server/pty-manager.js');
556
+ const { spawnClaude, killAllMain, onPtyExit } = await import('./server/pty-manager.js');
556
557
  const { isCodeFuseManagedEnvironment } = await import('./server/lib/codefuse-managed-mode.js');
557
558
  const codeFuseManaged = isCodeFuseManagedEnvironment();
558
559
  let managedExitCode = 0;
@@ -566,8 +567,20 @@ async function runCliMode(extraClaudeArgs = [], cwd, noOpen = false) {
566
567
  // cannot look like a second cleanup request and force the hardened 130 exit path.
567
568
  removeManagedExitListener?.();
568
569
  removeManagedExitListener = null;
569
- killPty();
570
- return serverMod.stopViewer();
570
+ // Kill ALL main PTYs, not just the active one — cross-project /resume keeps
571
+ // the previous project's main PTY alive, and it must not outlive this process
572
+ // as an orphan (node-pty children are session leaders; no OS cascade kill).
573
+ // killAllMain is idempotent and equals killPty() in the single-PTY case.
574
+ killAllMain();
575
+ // Reap scratch/resume children too — without this they outlive the main
576
+ // process as orphans (node-pty children are session leaders; the OS does
577
+ // not cascade-kill them). killAllScratch is idempotent.
578
+ return Promise.all([
579
+ serverMod.stopViewer(),
580
+ import('./server/scratch-pty-manager.js')
581
+ .then(({ killAllScratch }) => killAllScratch())
582
+ .catch((e) => reportSwallowed('cli.cleanup.scratch', e)),
583
+ ]);
571
584
  },
572
585
  exit: (code) => process.exit(code ?? managedExitCode),
573
586
  });
@@ -589,6 +602,16 @@ async function runCliMode(extraClaudeArgs = [], cwd, noOpen = false) {
589
602
  process.exit(1);
590
603
  }
591
604
 
605
+ // Keep the launcher-verified executable available to later workspace launches
606
+ // (POST /api/workspaces/launch → deps.workspaceClaudePath). Without this the
607
+ // route falls back to resolveNativePath(), which can pick a DIFFERENT binary
608
+ // than the one just spawned (e.g. the npm global build instead of the
609
+ // CodeFuse-managed one) — on managed machines that binary is SIGKILLed on
610
+ // exec, so a [+] project launch dies instantly (the "terminal loads history
611
+ // but claude never starts" bug). Restores the wiring dropped in f209f508.
612
+ serverMod.setWorkspaceClaudeArgs(extraClaudeArgs);
613
+ serverMod.setWorkspaceClaudePath(claudePath, isNpmVersion);
614
+
592
615
  // 4. 自动打开浏览器
593
616
  const protocol = serverMod.getProtocol();
594
617
  const basePath = normalizeBasePath(process.env.CCV_BASE_PATH);
@@ -898,7 +921,13 @@ async function runSdkMode(extraClaudeArgs = [], cwd, noOpen = false) {
898
921
  const cleanup = createHardenedCleanup({
899
922
  doCleanup: () => {
900
923
  sdkManager.stopSession();
901
- return serverMod.stopViewer();
924
+ // Reap scratch/resume children (see runCliMode cleanup); idempotent.
925
+ return Promise.all([
926
+ serverMod.stopViewer(),
927
+ import('./server/scratch-pty-manager.js')
928
+ .then(({ killAllScratch }) => killAllScratch())
929
+ .catch((e) => reportSwallowed('cli.cleanup.scratch', e)),
930
+ ]);
902
931
  },
903
932
  });
904
933
  process.on('SIGINT', cleanup);