mirror of
https://github.com/siteboon/claudecodeui.git
synced 2025-12-09 10:59:47 +00:00
Compare commits
35 Commits
v1.8.3
...
7d0fd141ff
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7d0fd141ff | ||
|
|
e5a05d9865 | ||
|
|
2d6c3b5755 | ||
|
|
2a5d27ffc0 | ||
|
|
3c9a4cab82 | ||
|
|
ce9ab0cd16 | ||
|
|
66fad9a6a2 | ||
|
|
0fcf906ff0 | ||
|
|
7e1f2940d3 | ||
|
|
533d589132 | ||
|
|
d1f310161f | ||
|
|
b853e8cda1 | ||
|
|
1610de1f22 | ||
|
|
3f743d8210 | ||
|
|
cbb18fb010 | ||
|
|
d8d754274a | ||
|
|
eb12aef641 | ||
|
|
5e574dbdec | ||
|
|
af9e9eec02 | ||
|
|
8c3ee770c3 | ||
|
|
58108c083c | ||
|
|
af0ad6b4b6 | ||
|
|
36d9f47e29 | ||
|
|
1f25f1e79b | ||
|
|
d7ed1de1cb | ||
|
|
9be54233d0 | ||
|
|
c8bcad71e7 | ||
|
|
a3f504aed2 | ||
|
|
f766ac1517 | ||
|
|
680d8f6fb1 | ||
|
|
d74a99ef24 | ||
|
|
133af82935 | ||
|
|
3daf21c3d1 | ||
|
|
f52ca8e702 | ||
|
|
d82a004224 |
@@ -9,4 +9,7 @@
|
|||||||
#API server
|
#API server
|
||||||
PORT=3001
|
PORT=3001
|
||||||
#Frontend port
|
#Frontend port
|
||||||
VITE_PORT=5173
|
VITE_PORT=5173
|
||||||
|
|
||||||
|
# Uncomment the following line if you have a custom claude cli path other than the default "claude"
|
||||||
|
# CLAUDE_CLI_PATH=claude
|
||||||
|
|||||||
21
.release-it.json
Normal file
21
.release-it.json
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"git": {
|
||||||
|
"commitMessage": "Release ${version}",
|
||||||
|
"tagName": "v${version}",
|
||||||
|
"changelog": "git log --pretty=format:\"* %s (%h)\" ${from}...${to}"
|
||||||
|
},
|
||||||
|
"npm": {
|
||||||
|
"publish": true
|
||||||
|
},
|
||||||
|
"github": {
|
||||||
|
"release": true,
|
||||||
|
"releaseName": "Claude Code UI v${version}",
|
||||||
|
"releaseNotes": {
|
||||||
|
"commit": "* ${commit.subject} (${sha}){ - thanks @${author.login}!}",
|
||||||
|
"excludeMatches": ["viper151"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hooks": {
|
||||||
|
"before:init": ["npm run build"]
|
||||||
|
}
|
||||||
|
}
|
||||||
12
README.md
12
README.md
@@ -59,7 +59,17 @@ A desktop and mobile UI for [Claude Code](https://docs.anthropic.com/en/docs/cla
|
|||||||
- [Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code) installed and configured, and/or
|
- [Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code) installed and configured, and/or
|
||||||
- [Cursor CLI](https://docs.cursor.com/en/cli/overview) installed and configured
|
- [Cursor CLI](https://docs.cursor.com/en/cli/overview) installed and configured
|
||||||
|
|
||||||
### Installation
|
### One-click Operation (Recommended)
|
||||||
|
|
||||||
|
No installation required, direct operation:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx @siteboon/claude-code-ui
|
||||||
|
```
|
||||||
|
|
||||||
|
Your default browser will automatically open the Claude Code UI interface.
|
||||||
|
|
||||||
|
### Local Development Installation
|
||||||
|
|
||||||
1. **Clone the repository:**
|
1. **Clone the repository:**
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
201
package-lock.json
generated
201
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "claude-code-ui",
|
"name": "@siteboon/claude-code-ui",
|
||||||
"version": "1.8.3",
|
"version": "1.8.10",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "claude-code-ui",
|
"name": "@siteboon/claude-code-ui",
|
||||||
"version": "1.8.3",
|
"version": "1.8.10",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/lang-css": "^6.3.1",
|
"@codemirror/lang-css": "^6.3.1",
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
"@codemirror/lang-markdown": "^6.3.3",
|
"@codemirror/lang-markdown": "^6.3.3",
|
||||||
"@codemirror/lang-python": "^6.2.1",
|
"@codemirror/lang-python": "^6.2.1",
|
||||||
"@codemirror/theme-one-dark": "^6.1.2",
|
"@codemirror/theme-one-dark": "^6.1.2",
|
||||||
|
"@siteboon/claude-code-ui": "^1.8.4",
|
||||||
"@tailwindcss/typography": "^0.5.16",
|
"@tailwindcss/typography": "^0.5.16",
|
||||||
"@uiw/react-codemirror": "^4.23.13",
|
"@uiw/react-codemirror": "^4.23.13",
|
||||||
"@xterm/addon-clipboard": "^0.1.0",
|
"@xterm/addon-clipboard": "^0.1.0",
|
||||||
@@ -46,10 +47,14 @@
|
|||||||
"xterm": "^5.3.0",
|
"xterm": "^5.3.0",
|
||||||
"xterm-addon-fit": "^0.8.0"
|
"xterm-addon-fit": "^0.8.0"
|
||||||
},
|
},
|
||||||
|
"bin": {
|
||||||
|
"claude-code-ui": "server/index.js"
|
||||||
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/react": "^18.2.43",
|
"@types/react": "^18.2.43",
|
||||||
"@types/react-dom": "^18.2.17",
|
"@types/react-dom": "^18.2.17",
|
||||||
"@vitejs/plugin-react": "^4.6.0",
|
"@vitejs/plugin-react": "^4.6.0",
|
||||||
|
"auto-changelog": "^2.5.0",
|
||||||
"autoprefixer": "^10.4.16",
|
"autoprefixer": "^10.4.16",
|
||||||
"concurrently": "^8.2.2",
|
"concurrently": "^8.2.2",
|
||||||
"node-gyp": "^10.0.0",
|
"node-gyp": "^10.0.0",
|
||||||
@@ -2501,6 +2506,50 @@
|
|||||||
"win32"
|
"win32"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"node_modules/@siteboon/claude-code-ui": {
|
||||||
|
"version": "1.8.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@siteboon/claude-code-ui/-/claude-code-ui-1.8.4.tgz",
|
||||||
|
"integrity": "sha512-9moBlMDNF/6IfIcqShavxdq0TI9aNuY3+33YZcnvYagWsZMdJ/7d5tgDwAZEp3Uup/nHU+bdrkiXmFfLcRQLCQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@codemirror/lang-css": "^6.3.1",
|
||||||
|
"@codemirror/lang-html": "^6.4.9",
|
||||||
|
"@codemirror/lang-javascript": "^6.2.4",
|
||||||
|
"@codemirror/lang-json": "^6.0.1",
|
||||||
|
"@codemirror/lang-markdown": "^6.3.3",
|
||||||
|
"@codemirror/lang-python": "^6.2.1",
|
||||||
|
"@codemirror/theme-one-dark": "^6.1.2",
|
||||||
|
"@tailwindcss/typography": "^0.5.16",
|
||||||
|
"@uiw/react-codemirror": "^4.23.13",
|
||||||
|
"@xterm/addon-clipboard": "^0.1.0",
|
||||||
|
"@xterm/addon-webgl": "^0.18.0",
|
||||||
|
"bcrypt": "^6.0.0",
|
||||||
|
"better-sqlite3": "^12.2.0",
|
||||||
|
"chokidar": "^4.0.3",
|
||||||
|
"class-variance-authority": "^0.7.1",
|
||||||
|
"clsx": "^2.1.1",
|
||||||
|
"cors": "^2.8.5",
|
||||||
|
"cross-spawn": "^7.0.3",
|
||||||
|
"express": "^4.18.2",
|
||||||
|
"jsonwebtoken": "^9.0.2",
|
||||||
|
"lucide-react": "^0.515.0",
|
||||||
|
"mime-types": "^3.0.1",
|
||||||
|
"multer": "^2.0.1",
|
||||||
|
"node-fetch": "^2.7.0",
|
||||||
|
"node-pty": "^1.1.0-beta34",
|
||||||
|
"react": "^18.2.0",
|
||||||
|
"react-dom": "^18.2.0",
|
||||||
|
"react-dropzone": "^14.2.3",
|
||||||
|
"react-markdown": "^10.1.0",
|
||||||
|
"react-router-dom": "^6.8.1",
|
||||||
|
"sqlite": "^5.1.1",
|
||||||
|
"sqlite3": "^5.1.7",
|
||||||
|
"tailwind-merge": "^3.3.1",
|
||||||
|
"ws": "^8.14.2",
|
||||||
|
"xterm": "^5.3.0",
|
||||||
|
"xterm-addon-fit": "^0.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@tailwindcss/typography": {
|
"node_modules/@tailwindcss/typography": {
|
||||||
"version": "0.5.16",
|
"version": "0.5.16",
|
||||||
"resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.16.tgz",
|
"resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.16.tgz",
|
||||||
@@ -2982,6 +3031,50 @@
|
|||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/auto-changelog": {
|
||||||
|
"version": "2.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/auto-changelog/-/auto-changelog-2.5.0.tgz",
|
||||||
|
"integrity": "sha512-UTnLjT7I9U2U/xkCUH5buDlp8C7g0SGChfib+iDrJkamcj5kaMqNKHNfbKJw1kthJUq8sUo3i3q2S6FzO/l/wA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"commander": "^7.2.0",
|
||||||
|
"handlebars": "^4.7.7",
|
||||||
|
"import-cwd": "^3.0.0",
|
||||||
|
"node-fetch": "^2.6.1",
|
||||||
|
"parse-github-url": "^1.0.3",
|
||||||
|
"semver": "^7.3.5"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"auto-changelog": "src/index.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/auto-changelog/node_modules/commander": {
|
||||||
|
"version": "7.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
|
||||||
|
"integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/auto-changelog/node_modules/semver": {
|
||||||
|
"version": "7.7.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
|
||||||
|
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "ISC",
|
||||||
|
"bin": {
|
||||||
|
"semver": "bin/semver.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/autoprefixer": {
|
"node_modules/autoprefixer": {
|
||||||
"version": "10.4.21",
|
"version": "10.4.21",
|
||||||
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz",
|
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz",
|
||||||
@@ -5122,6 +5215,28 @@
|
|||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/handlebars": {
|
||||||
|
"version": "4.7.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz",
|
||||||
|
"integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"minimist": "^1.2.5",
|
||||||
|
"neo-async": "^2.6.2",
|
||||||
|
"source-map": "^0.6.1",
|
||||||
|
"wordwrap": "^1.0.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"handlebars": "bin/handlebars"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.4.7"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"uglify-js": "^3.1.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/has-flag": {
|
"node_modules/has-flag": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||||
@@ -5316,6 +5431,32 @@
|
|||||||
],
|
],
|
||||||
"license": "BSD-3-Clause"
|
"license": "BSD-3-Clause"
|
||||||
},
|
},
|
||||||
|
"node_modules/import-cwd": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-4pnzH16plW+hgvRECbDWpQl3cqtvSofHWh44met7ESfZ8UZOWWddm8hEyDTqREJ9RbYHY8gi8DqmaelApoOGMg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"import-from": "^3.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/import-from": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/import-from/-/import-from-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-CiuXOFFSzkU5x/CR0+z7T91Iht4CXgfCxVOFRhh2Zyhg5wOpWvvDLQUsWl+gcN+QscYBjez8hDCt85O7RLDttQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"resolve-from": "^5.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/imurmurhash": {
|
"node_modules/imurmurhash": {
|
||||||
"version": "0.1.4",
|
"version": "0.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
|
||||||
@@ -7011,6 +7152,13 @@
|
|||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/neo-async": {
|
||||||
|
"version": "2.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
|
||||||
|
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/netmask": {
|
"node_modules/netmask": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz",
|
||||||
@@ -7557,6 +7705,19 @@
|
|||||||
"integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==",
|
"integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/parse-github-url": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/parse-github-url/-/parse-github-url-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-tfalY5/4SqGaV/GIGzWyHnFjlpTPTNpENR9Ea2lLldSJ8EWXMsvacWucqY3m3I4YPtas15IxTLQVQ5NSYXPrww==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"parse-github-url": "cli.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/parse-path": {
|
"node_modules/parse-path": {
|
||||||
"version": "7.1.0",
|
"version": "7.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/parse-path/-/parse-path-7.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/parse-path/-/parse-path-7.1.0.tgz",
|
||||||
@@ -8368,6 +8529,16 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/resolve-from": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/restore-cursor": {
|
"node_modules/restore-cursor": {
|
||||||
"version": "5.1.0",
|
"version": "5.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz",
|
||||||
@@ -9181,7 +9352,6 @@
|
|||||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "BSD-3-Clause",
|
"license": "BSD-3-Clause",
|
||||||
"optional": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@@ -10257,6 +10427,20 @@
|
|||||||
"integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
|
"integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/uglify-js": {
|
||||||
|
"version": "3.19.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz",
|
||||||
|
"integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"optional": true,
|
||||||
|
"bin": {
|
||||||
|
"uglifyjs": "bin/uglifyjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/undici": {
|
"node_modules/undici": {
|
||||||
"version": "6.21.3",
|
"version": "6.21.3",
|
||||||
"resolved": "https://registry.npmjs.org/undici/-/undici-6.21.3.tgz",
|
"resolved": "https://registry.npmjs.org/undici/-/undici-6.21.3.tgz",
|
||||||
@@ -10707,6 +10891,13 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/wordwrap": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/wrap-ansi": {
|
"node_modules/wrap-ansi": {
|
||||||
"version": "8.1.0",
|
"version": "8.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@siteboon/claude-code-ui",
|
"name": "@siteboon/claude-code-ui",
|
||||||
"version": "1.8.3",
|
"version": "1.8.10",
|
||||||
"description": "A web-based UI for Claude Code CLI",
|
"description": "A web-based UI for Claude Code CLI",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "server/index.js",
|
"main": "server/index.js",
|
||||||
|
"bin": {
|
||||||
|
"claude-code-ui": "server/index.js"
|
||||||
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"server/",
|
"server/",
|
||||||
"dist/",
|
"dist/",
|
||||||
@@ -77,6 +80,7 @@
|
|||||||
"@types/react": "^18.2.43",
|
"@types/react": "^18.2.43",
|
||||||
"@types/react-dom": "^18.2.17",
|
"@types/react-dom": "^18.2.17",
|
||||||
"@vitejs/plugin-react": "^4.6.0",
|
"@vitejs/plugin-react": "^4.6.0",
|
||||||
|
"auto-changelog": "^2.5.0",
|
||||||
"autoprefixer": "^10.4.16",
|
"autoprefixer": "^10.4.16",
|
||||||
"concurrently": "^8.2.2",
|
"concurrently": "^8.2.2",
|
||||||
"node-gyp": "^10.0.0",
|
"node-gyp": "^10.0.0",
|
||||||
|
|||||||
@@ -25,15 +25,6 @@ async function spawnClaude(command, options = {}, ws) {
|
|||||||
// Build Claude CLI command - start with print/resume flags first
|
// Build Claude CLI command - start with print/resume flags first
|
||||||
const args = [];
|
const args = [];
|
||||||
|
|
||||||
// Add print flag with command if we have a command
|
|
||||||
if (command && command.trim()) {
|
|
||||||
|
|
||||||
// Separate arguments for better cross-platform compatibility
|
|
||||||
// This prevents issues with spaces and quotes on Windows
|
|
||||||
args.push('--print');
|
|
||||||
args.push(command);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use cwd (actual project directory) instead of projectPath (Claude's metadata directory)
|
// Use cwd (actual project directory) instead of projectPath (Claude's metadata directory)
|
||||||
const workingDir = cwd || process.cwd();
|
const workingDir = cwd || process.cwd();
|
||||||
|
|
||||||
@@ -225,6 +216,17 @@ async function spawnClaude(command, options = {}, ws) {
|
|||||||
console.log('📝 Skip permissions disabled due to plan mode');
|
console.log('📝 Skip permissions disabled due to plan mode');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add print flag with command if we have a command
|
||||||
|
if (command && command.trim()) {
|
||||||
|
|
||||||
|
// Separate arguments for better cross-platform compatibility
|
||||||
|
// This prevents issues with spaces and quotes on Windows
|
||||||
|
args.push('--print');
|
||||||
|
// Use `--` so user input is always treated as text, not options
|
||||||
|
args.push('--');
|
||||||
|
args.push(command);
|
||||||
|
}
|
||||||
|
|
||||||
console.log('Spawning Claude CLI:', 'claude', args.map(arg => {
|
console.log('Spawning Claude CLI:', 'claude', args.map(arg => {
|
||||||
const cleanArg = arg.replace(/\n/g, '\\n').replace(/\r/g, '\\r');
|
const cleanArg = arg.replace(/\n/g, '\\n').replace(/\r/g, '\\r');
|
||||||
@@ -235,7 +237,11 @@ async function spawnClaude(command, options = {}, ws) {
|
|||||||
console.log('🔍 Full command args:', JSON.stringify(args, null, 2));
|
console.log('🔍 Full command args:', JSON.stringify(args, null, 2));
|
||||||
console.log('🔍 Final Claude command will be: claude ' + args.join(' '));
|
console.log('🔍 Final Claude command will be: claude ' + args.join(' '));
|
||||||
|
|
||||||
const claudeProcess = spawnFunction('claude', args, {
|
// Use Claude CLI from environment variable or default to 'claude'
|
||||||
|
const claudePath = process.env.CLAUDE_CLI_PATH || 'claude';
|
||||||
|
console.log('🔍 Using Claude CLI path:', claudePath);
|
||||||
|
|
||||||
|
const claudeProcess = spawnFunction(claudePath, args, {
|
||||||
cwd: workingDir,
|
cwd: workingDir,
|
||||||
stdio: ['pipe', 'pipe', 'pipe'],
|
stdio: ['pipe', 'pipe', 'pipe'],
|
||||||
env: { ...process.env } // Inherit all environment variables
|
env: { ...process.env } // Inherit all environment variables
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
// Load environment variables from .env file
|
// Load environment variables from .env file
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|||||||
47
src/App.jsx
47
src/App.jsx
@@ -33,6 +33,7 @@ import { TasksSettingsProvider } from './contexts/TasksSettingsContext';
|
|||||||
import { WebSocketProvider, useWebSocketContext } from './contexts/WebSocketContext';
|
import { WebSocketProvider, useWebSocketContext } from './contexts/WebSocketContext';
|
||||||
import ProtectedRoute from './components/ProtectedRoute';
|
import ProtectedRoute from './components/ProtectedRoute';
|
||||||
import { useVersionCheck } from './hooks/useVersionCheck';
|
import { useVersionCheck } from './hooks/useVersionCheck';
|
||||||
|
import useLocalStorage from './hooks/useLocalStorage';
|
||||||
import { api, authenticatedFetch } from './utils/api';
|
import { api, authenticatedFetch } from './utils/api';
|
||||||
|
|
||||||
|
|
||||||
@@ -54,22 +55,10 @@ function AppContent() {
|
|||||||
const [isInputFocused, setIsInputFocused] = useState(false);
|
const [isInputFocused, setIsInputFocused] = useState(false);
|
||||||
const [showSettings, setShowSettings] = useState(false);
|
const [showSettings, setShowSettings] = useState(false);
|
||||||
const [showQuickSettings, setShowQuickSettings] = useState(false);
|
const [showQuickSettings, setShowQuickSettings] = useState(false);
|
||||||
const [autoExpandTools, setAutoExpandTools] = useState(() => {
|
const [autoExpandTools, setAutoExpandTools] = useLocalStorage('autoExpandTools', false);
|
||||||
const saved = localStorage.getItem('autoExpandTools');
|
const [showRawParameters, setShowRawParameters] = useLocalStorage('showRawParameters', false);
|
||||||
return saved !== null ? JSON.parse(saved) : false;
|
const [autoScrollToBottom, setAutoScrollToBottom] = useLocalStorage('autoScrollToBottom', true);
|
||||||
});
|
const [sendByCtrlEnter, setSendByCtrlEnter] = useLocalStorage('sendByCtrlEnter', false);
|
||||||
const [showRawParameters, setShowRawParameters] = useState(() => {
|
|
||||||
const saved = localStorage.getItem('showRawParameters');
|
|
||||||
return saved !== null ? JSON.parse(saved) : false;
|
|
||||||
});
|
|
||||||
const [autoScrollToBottom, setAutoScrollToBottom] = useState(() => {
|
|
||||||
const saved = localStorage.getItem('autoScrollToBottom');
|
|
||||||
return saved !== null ? JSON.parse(saved) : true;
|
|
||||||
});
|
|
||||||
const [sendByCtrlEnter, setSendByCtrlEnter] = useState(() => {
|
|
||||||
const saved = localStorage.getItem('sendByCtrlEnter');
|
|
||||||
return saved !== null ? JSON.parse(saved) : false;
|
|
||||||
});
|
|
||||||
// Session Protection System: Track sessions with active conversations to prevent
|
// Session Protection System: Track sessions with active conversations to prevent
|
||||||
// automatic project updates from interrupting ongoing chats. When a user sends
|
// automatic project updates from interrupting ongoing chats. When a user sends
|
||||||
// a message, the session is marked as "active" and project updates are paused
|
// a message, the session is marked as "active" and project updates are paused
|
||||||
@@ -491,9 +480,10 @@ function AppContent() {
|
|||||||
return (
|
return (
|
||||||
<div className="fixed inset-0 z-50 flex items-center justify-center">
|
<div className="fixed inset-0 z-50 flex items-center justify-center">
|
||||||
{/* Backdrop */}
|
{/* Backdrop */}
|
||||||
<div
|
<button
|
||||||
className="fixed inset-0 bg-black/50 backdrop-blur-sm"
|
className="fixed inset-0 bg-black/50 backdrop-blur-sm"
|
||||||
onClick={() => setShowVersionModal(false)}
|
onClick={() => setShowVersionModal(false)}
|
||||||
|
aria-label="Close version upgrade modal"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Modal */}
|
{/* Modal */}
|
||||||
@@ -604,7 +594,7 @@ function AppContent() {
|
|||||||
<div className={`fixed inset-0 z-50 flex transition-all duration-150 ease-out ${
|
<div className={`fixed inset-0 z-50 flex transition-all duration-150 ease-out ${
|
||||||
sidebarOpen ? 'opacity-100 visible' : 'opacity-0 invisible'
|
sidebarOpen ? 'opacity-100 visible' : 'opacity-0 invisible'
|
||||||
}`}>
|
}`}>
|
||||||
<div
|
<button
|
||||||
className="fixed inset-0 bg-background/80 backdrop-blur-sm transition-opacity duration-150 ease-out"
|
className="fixed inset-0 bg-background/80 backdrop-blur-sm transition-opacity duration-150 ease-out"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
@@ -615,6 +605,7 @@ function AppContent() {
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setSidebarOpen(false);
|
setSidebarOpen(false);
|
||||||
}}
|
}}
|
||||||
|
aria-label="Close sidebar"
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
className={`relative w-[85vw] max-w-sm sm:w-80 bg-card border-r border-border transform transition-transform duration-150 ease-out ${
|
className={`relative w-[85vw] max-w-sm sm:w-80 bg-card border-r border-border transform transition-transform duration-150 ease-out ${
|
||||||
@@ -688,25 +679,13 @@ function AppContent() {
|
|||||||
isOpen={showQuickSettings}
|
isOpen={showQuickSettings}
|
||||||
onToggle={setShowQuickSettings}
|
onToggle={setShowQuickSettings}
|
||||||
autoExpandTools={autoExpandTools}
|
autoExpandTools={autoExpandTools}
|
||||||
onAutoExpandChange={(value) => {
|
onAutoExpandChange={setAutoExpandTools}
|
||||||
setAutoExpandTools(value);
|
|
||||||
localStorage.setItem('autoExpandTools', JSON.stringify(value));
|
|
||||||
}}
|
|
||||||
showRawParameters={showRawParameters}
|
showRawParameters={showRawParameters}
|
||||||
onShowRawParametersChange={(value) => {
|
onShowRawParametersChange={setShowRawParameters}
|
||||||
setShowRawParameters(value);
|
|
||||||
localStorage.setItem('showRawParameters', JSON.stringify(value));
|
|
||||||
}}
|
|
||||||
autoScrollToBottom={autoScrollToBottom}
|
autoScrollToBottom={autoScrollToBottom}
|
||||||
onAutoScrollChange={(value) => {
|
onAutoScrollChange={setAutoScrollToBottom}
|
||||||
setAutoScrollToBottom(value);
|
|
||||||
localStorage.setItem('autoScrollToBottom', JSON.stringify(value));
|
|
||||||
}}
|
|
||||||
sendByCtrlEnter={sendByCtrlEnter}
|
sendByCtrlEnter={sendByCtrlEnter}
|
||||||
onSendByCtrlEnterChange={(value) => {
|
onSendByCtrlEnterChange={setSendByCtrlEnter}
|
||||||
setSendByCtrlEnter(value);
|
|
||||||
localStorage.setItem('sendByCtrlEnter', JSON.stringify(value));
|
|
||||||
}}
|
|
||||||
isMobile={isMobile}
|
isMobile={isMobile}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
41
src/hooks/useLocalStorage.jsx
Normal file
41
src/hooks/useLocalStorage.jsx
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom hook to persist state in localStorage.
|
||||||
|
*
|
||||||
|
* @param {string} key The key to use for localStorage.
|
||||||
|
* @param {any} initialValue The initial value to use if nothing is in localStorage.
|
||||||
|
* @returns {[any, Function]} A tuple containing the stored value and a setter function.
|
||||||
|
*/
|
||||||
|
function useLocalStorage(key, initialValue) {
|
||||||
|
const [storedValue, setStoredValue] = useState(() => {
|
||||||
|
if (typeof window === 'undefined') {
|
||||||
|
return initialValue;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const item = window.localStorage.getItem(key);
|
||||||
|
return item ? JSON.parse(item) : initialValue;
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
return initialValue;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const setValue = (value) => {
|
||||||
|
if (typeof window === 'undefined') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const valueToStore =
|
||||||
|
value instanceof Function ? value(storedValue) : value;
|
||||||
|
window.localStorage.setItem(key, JSON.stringify(valueToStore));
|
||||||
|
setStoredValue(valueToStore);
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return [storedValue, setValue];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useLocalStorage;
|
||||||
Reference in New Issue
Block a user