mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-30 16:23:35 +08:00
Two bugs in the v0.5.7 "Continue from here" hand-off path landed in the wild and the user caught them while exercising 0.5.8 prep: 1. **Stray empty session.** When the user previously opened a "New session in X" tab from the sidebar, then closed the tab to declutter, the freshly-created empty session was already on disk and visible in the sidebar. Coming back to the welcome screen (activeTabId = null → EmptySession route) and clicking "Continue from here" called `createSession` unconditionally, minting yet another empty session next to the now-stale one. The user ended up with `Untitled Session 27 minutes ago` lingering in the sidebar while the hand-off ran in a completely separate fresh session. Extract the picker into `desktop/src/lib/sessionReuse.ts` — `pickReusableEmptySession(sessions, workDir, excludeSessionId?)` filters by exact-workDir match, `messageCount === 0`, excludes the previous session being handed off FROM, and sorts by `modifiedAt` desc. Caller in `EmptySession.onAutoHandoff` runs this before `createSession`; on hit, openTab on the existing sessionId and let ContentRouter switch to ActiveSession naturally; on miss, create fresh as before. 7 unit tests cover the boundaries: workDir mismatch, non-zero messageCount, excludeSessionId honored, null workDir treated as "no candidates" (so we never silently merge home-dir sessions into a project hand-off), empty workDir argument, empty session list, freshness sort order. 2. **Summary too abstract; AI doesn't know specific recent state.** The previous implementation only injected the LLM-summarized `main` + `recent` paragraphs into the next session's system prompt. That summarization tends to wash out exact wording, file paths, error messages, and the user's literal last question — the user reported "AI doesn't know what we just hit a wall on." Add `recentRaw?: string` to `SessionSummary`. New helper `buildRecentRawSlice` keeps the LAST ~12 turns (env-tunable via `CLAUDE_CODE_HANDOFF_RAW_TURNS`, range 0–50, default 12), each truncated to 400 chars preserving the `USER:` / `ASSISTANT:` role prefix, total capped at ~8000 chars (env-tunable via `CLAUDE_CODE_HANDOFF_RAW_CHARS`, range 500–30000, default 8000). Older turns drop first when the total cap is busted by dense recent turns. `formatHandoffSystemPrompt` renders the raw slice inside a fenced code block AFTER the abstracted recent summary, so the next session sees both the digest and the literal text. Section is omitted entirely when `recentRaw` is absent — v0.5.7 caches still load and produce the exact same prompt bytes (back-compat). 8 unit tests cover the formatter's back-compat path, the raw block placement, fence rendering, tail-N selection, all-fits case, per-turn truncation with role prefix preservation, total cap busting (older drops first), and the `RAW_TURNS=0` opt-out. Both fixes fold into the unreleased v0.5.8 — release-notes/v0.5.8.md gets two new fix bullets and the 范围 / 验证 sections call out the new files and 15 added tests. desktop/package.json bump to 0.5.8 stays as-is (preset earlier in the same worktree before this commit). Tested: - bun run lint (desktop) clean - bunx vitest run sessionReuse.test.ts → 7/7 pass - bun test sessionSummaryService.test.ts → 8/8 pass - bunx vitest run EmptySession.test.tsx → 22/22 pass (regression check after the helper extraction — the existing tests don't go through the hand-off branch but exercise the rest of the file) Confidence: high Scope-risk: narrow (no shape changes to any persistence — recentRaw is an additive field, old caches deserialize cleanly because `tryParseSummaryResponse` already only required main+recent) Co-authored-by: 你的姓名 <you@example.com>
143 lines
5.0 KiB
JSON
143 lines
5.0 KiB
JSON
{
|
|
"name": "claude-code-desktop",
|
|
"private": true,
|
|
"version": "0.5.8",
|
|
"description": "Desktop coding agent workbench for Claude Code Haha.",
|
|
"homepage": "https://github.com/706412584/cc-haha",
|
|
"author": {
|
|
"name": "NanmiCoder",
|
|
"email": "relakkes@gmail.com"
|
|
},
|
|
"type": "module",
|
|
"main": "electron-dist/main.cjs",
|
|
"build": {
|
|
"appId": "com.claude-code-haha.desktop",
|
|
"productName": "Claude Code Haha",
|
|
"asar": true,
|
|
"asarUnpack": [
|
|
"dist/**",
|
|
"node_modules/node-pty/**",
|
|
"src-tauri/binaries/**"
|
|
],
|
|
"artifactName": "Claude-Code-Haha-${version}-${os}-${arch}.${ext}",
|
|
"npmRebuild": false,
|
|
"directories": {
|
|
"output": "build-artifacts/electron"
|
|
},
|
|
"files": [
|
|
"dist/**",
|
|
"electron-dist/**",
|
|
"node_modules/node-pty/**",
|
|
"src-tauri/binaries/**",
|
|
"src-tauri/icons/**",
|
|
"src-tauri/resources/preview-agent.js",
|
|
"package.json"
|
|
],
|
|
"mac": {
|
|
"category": "public.app-category.developer-tools",
|
|
"target": [
|
|
"dmg",
|
|
"zip"
|
|
],
|
|
"icon": "src-tauri/icons/icon.icns",
|
|
"hardenedRuntime": true,
|
|
"gatekeeperAssess": false,
|
|
"entitlements": "build/entitlements.mac.plist",
|
|
"entitlementsInherit": "build/entitlements.mac.inherit.plist",
|
|
"notarize": true
|
|
},
|
|
"win": {
|
|
"target": "nsis",
|
|
"icon": "src-tauri/icons/icon.ico"
|
|
},
|
|
"nsis": {
|
|
"oneClick": false,
|
|
"allowElevation": true,
|
|
"allowToChangeInstallationDirectory": true,
|
|
"perMachine": false,
|
|
"deleteAppDataOnUninstall": false,
|
|
"createDesktopShortcut": true,
|
|
"createStartMenuShortcut": true,
|
|
"license": "build/license.txt"
|
|
},
|
|
"linux": {
|
|
"target": [
|
|
"AppImage",
|
|
"deb"
|
|
],
|
|
"icon": "src-tauri/icons",
|
|
"category": "Development",
|
|
"maintainer": "NanmiCoder <relakkes@gmail.com>"
|
|
},
|
|
"publish": [
|
|
{
|
|
"provider": "github",
|
|
"owner": "706412584",
|
|
"repo": "cc-haha"
|
|
}
|
|
]
|
|
},
|
|
"scripts": {
|
|
"dev": "vite",
|
|
"build": "bun run build:preview-agent && node ./node_modules/typescript/bin/tsc -b && node ./node_modules/vite/bin/vite.js build",
|
|
"prepare:node-pty": "bun run ./scripts/prepare-node-pty.ts",
|
|
"build:electron": "bun run prepare:node-pty && bun build ./electron/main.ts --outfile ./electron-dist/main.cjs --target node --format cjs --external electron --external node-pty && bun build ./electron/preload.ts --outfile ./electron-dist/preload.cjs --target node --format cjs --external electron && bun build ./electron/preview-preload.ts --outfile ./electron-dist/preview-preload.cjs --target node --format cjs --external electron",
|
|
"build:preview-agent": "bun run ./scripts/build-preview-agent.ts",
|
|
"build:sidecars": "bun run ./scripts/build-sidecars.ts",
|
|
"clean:electron-output": "bun run ./scripts/clean-electron-output.ts",
|
|
"build:macos-arm64": "bash ./scripts/build-macos-arm64.sh",
|
|
"build:windows-x64": "powershell -ExecutionPolicy Bypass -File ./scripts/build-windows-x64.ps1",
|
|
"build:linux-x64": "bash ./scripts/build-linux.sh",
|
|
"build:linux-arm64": "LINUX_ARCH=arm64 bash ./scripts/build-linux.sh",
|
|
"electron:dev": "bun run build:electron && bun run ./scripts/electron-dev.ts",
|
|
"electron:build": "bun run build:sidecars && bun run build && bun run build:electron",
|
|
"electron:package": "bun run clean:electron-output && bun run electron:build && bunx electron-builder --publish never",
|
|
"electron:package:dir": "bun run clean:electron-output && bun run electron:build && bunx electron-builder --dir --publish never",
|
|
"check:electron": "node ./node_modules/typescript/bin/tsc -p electron/tsconfig.json && bun test electron && bun run build:electron",
|
|
"preview": "vite preview",
|
|
"test": "vitest",
|
|
"test:ui": "vitest --ui",
|
|
"lint": "node ./node_modules/typescript/bin/tsc --noEmit"
|
|
},
|
|
"dependencies": {
|
|
"@tailwindcss/typography": "^0.5.19",
|
|
"@types/dompurify": "^3.2.0",
|
|
"@xterm/addon-fit": "^0.11.0",
|
|
"@xterm/xterm": "^6.0.0",
|
|
"dompurify": "^3.3.3",
|
|
"electron-updater": "^6.8.3",
|
|
"html2canvas": "^1.4.1",
|
|
"katex": "^0.16.45",
|
|
"lucide-react": "^0.469.0",
|
|
"marked": "^15.0.7",
|
|
"mermaid": "^11.14.0",
|
|
"node-pty": "^1.1.0",
|
|
"prism-react-renderer": "^2.4.1",
|
|
"qrcode": "^1.5.4",
|
|
"react": "^18.3.1",
|
|
"react-diff-viewer-continued": "^4.2.0",
|
|
"react-dom": "^18.3.1",
|
|
"react-shiki": "^0.9.2",
|
|
"shiki": "^4.0.2",
|
|
"zustand": "^5.0.3"
|
|
},
|
|
"devDependencies": {
|
|
"@tailwindcss/vite": "^4.0.0",
|
|
"@testing-library/dom": "^10.4.1",
|
|
"@testing-library/jest-dom": "^6.6.3",
|
|
"@testing-library/react": "^16.1.0",
|
|
"@types/node": "^25.9.1",
|
|
"@types/react": "^18.3.18",
|
|
"@types/react-dom": "^18.3.5",
|
|
"@vitejs/plugin-react": "^6.0.1",
|
|
"@vitest/coverage-v8": "3.2.4",
|
|
"electron": "^42.3.0",
|
|
"electron-builder": "^26.8.1",
|
|
"jsdom": "^25.0.1",
|
|
"tailwindcss": "^4.0.0",
|
|
"typescript": "^5.9.3",
|
|
"vite": "^8.0.10",
|
|
"vitest": "^3.0.4"
|
|
}
|
|
}
|