@znmin/claude-remote-cli 0.1.0 → 0.1.1
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.
- package/README.md +13 -6
- package/package.json +1 -1
- package/src/cli.js +5 -4
- package/src/client.js +5 -6
- package/src/remote-claude.js +39 -0
package/README.md
CHANGED
|
@@ -25,10 +25,10 @@ npm install -g git+https://github.com/znmin/claude-remote-cli.git
|
|
|
25
25
|
也可以从已下载的分发包安装:
|
|
26
26
|
|
|
27
27
|
```bash
|
|
28
|
-
npm install -g ./znmin-claude-remote-cli-0.1.
|
|
28
|
+
npm install -g ./znmin-claude-remote-cli-0.1.1.tgz
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
若系统 npm 全局目录不可写,可使用 `npm install -g --prefix "$HOME/.local" ./znmin-claude-remote-cli-0.1.
|
|
31
|
+
若系统 npm 全局目录不可写,可使用 `npm install -g --prefix "$HOME/.local" ./znmin-claude-remote-cli-0.1.1.tgz`,并确保 `~/.local/bin` 在 PATH 中;卸载时也使用相同的 `--prefix`。
|
|
32
32
|
|
|
33
33
|
npm 中不带作用域的 `claude-remote-cli` 属于其他项目。本项目使用独立的 `@znmin/claude-remote-cli` 作用域包名;请安装完整包名,或使用上述 GitHub 地址及本项目分发的 `.tgz` 文件。
|
|
34
34
|
|
|
@@ -38,7 +38,14 @@ npm 中不带作用域的 `claude-remote-cli` 属于其他项目。本项目使
|
|
|
38
38
|
|
|
39
39
|
## 开始使用
|
|
40
40
|
|
|
41
|
-
服务器需要 Linux/macOS、可用的 SSH/SCP
|
|
41
|
+
服务器需要 Linux/macOS、可用的 SSH/SCP 和 Bash。启动时会检查 Claude Code:
|
|
42
|
+
|
|
43
|
+
- 已安装:直接使用已有程序。
|
|
44
|
+
- 默认 `claude` 命令不存在:通过服务器上的 `curl` 或 `wget` 下载并执行 [Anthropic 官方原生安装器](https://github.com/anthropics/claude-code#get-started),无需服务器安装 Node.js,也不会使用 `sudo`。
|
|
45
|
+
- 安装完成:检查命令已可用,再开始目录同步并启动 Claude。首次启动时按 Claude 的提示完成账号认证;不会复制本机账号凭据。
|
|
46
|
+
- 下载失败、安装失败或缺少 `curl`/`wget`:停止启动并报告原因,不建立新的项目同步会话。自动安装最多等待 10 分钟,可修复网络/权限后重试。
|
|
47
|
+
|
|
48
|
+
安装过程只在默认命令缺失时触发,不会自动重装或升级已有 Claude Code。
|
|
42
49
|
|
|
43
50
|
```bash
|
|
44
51
|
# 配置你的服务器,不会立即连接或上传文件
|
|
@@ -60,7 +67,7 @@ claude --continue
|
|
|
60
67
|
|
|
61
68
|
未配置服务器时,也可以直接运行 `claude`,按终端提示输入服务器地址和端口。请勿把密码或私钥填入配置;登录使用 OpenSSH 原有认证流程和主机身份验证。
|
|
62
69
|
|
|
63
|
-
|
|
70
|
+
若需要使用特定的 Claude 可执行文件,可指定绝对路径;自定义路径不存在时会提示修正配置,不会自动改用其他程序:
|
|
64
71
|
|
|
65
72
|
```bash
|
|
66
73
|
claude-remote configure my-server --claude /absolute/path/to/claude
|
|
@@ -127,7 +134,7 @@ npm test
|
|
|
127
134
|
CLAUDE_REMOTE_INTEGRATION=1 npm test
|
|
128
135
|
|
|
129
136
|
npm pack
|
|
130
|
-
npm install -g ./znmin-claude-remote-cli-0.1.
|
|
137
|
+
npm install -g ./znmin-claude-remote-cli-0.1.1.tgz
|
|
131
138
|
|
|
132
139
|
# 确定包名、版本和使用条款后,使用有发布权限的 npm 账号发布
|
|
133
140
|
npm login
|
|
@@ -136,6 +143,6 @@ npm publish --access public
|
|
|
136
143
|
|
|
137
144
|
GitHub 仓库名为 `claude-remote-cli`,npm 包名为 `@znmin/claude-remote-cli`,命令名为 `claude` 和 `claude-remote`。发布账号必须拥有 npm 用户作用域 `@znmin`,或拥有同名 npm 组织的发布权限;GitHub 身份不会自动授予 npm 权限。当前 `license` 为 `UNLICENSED`,尚未指定开源许可证。
|
|
138
145
|
|
|
139
|
-
|
|
146
|
+
测试覆盖全局安装、命令入口、项目隔离、参数引用、冲突阻断、下载校验、本地真实双向同步,以及使用隔离环境模拟的远程自动安装、下载失败和安装失败。由于尚未提供服务器,真实 SSH 认证、服务器上的官方安装与 Claude 交互、Linux 和其他 CPU 架构尚未实测。
|
|
140
147
|
|
|
141
148
|
参考:[npm 命令入口配置](https://docs.npmjs.com/cli/configuring-npm/package-json#bin)、[Mutagen 同步机制](https://mutagen.io/documentation/synchronization/)、[Mutagen SSH 支持](https://mutagen.io/documentation/transports/ssh/)。
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -4,7 +4,7 @@ import { Client, DEFAULTS } from './client.js';
|
|
|
4
4
|
import { cachedBinary, ensureMutagen, VERSION } from './installer.js';
|
|
5
5
|
import { exists, readJSON, which } from './system.js';
|
|
6
6
|
|
|
7
|
-
const HELP = `@znmin/claude-remote-cli 0.1.
|
|
7
|
+
const HELP = `@znmin/claude-remote-cli 0.1.1(非 Anthropic 官方客户端)
|
|
8
8
|
|
|
9
9
|
安装后使用:
|
|
10
10
|
claude 首次引导设置服务器,之后启动远程 Claude Code
|
|
@@ -18,7 +18,8 @@ const HELP = `@znmin/claude-remote-cli 0.1.0(非 Anthropic 官方客户端)
|
|
|
18
18
|
claude-remote run [Claude 参数] 启动远程 Claude
|
|
19
19
|
|
|
20
20
|
configure 可选:--root 远程根目录、--ignore 忽略规则(可重复)。
|
|
21
|
-
|
|
21
|
+
服务器缺少默认 Claude Code 时会自动安装;首次启动需完成认证。
|
|
22
|
+
此工具不提供服务器或 Claude 账号。
|
|
22
23
|
退出 Claude 后会继续后台同步;停止请运行 claude-remote stop。
|
|
23
24
|
`;
|
|
24
25
|
|
|
@@ -47,14 +48,14 @@ export async function main(asClaude, args = process.argv.slice(2), client = new
|
|
|
47
48
|
const saved = await readJSON(client.configFile, {});
|
|
48
49
|
if (!saved.host && !client.env.CLAUDE_REMOTE_HOST) {
|
|
49
50
|
if (args.includes('--help') || args.includes('-h')) { console.log(HELP); return 0; }
|
|
50
|
-
if (args.includes('--version')) { console.log('@znmin/claude-remote-cli 0.1.
|
|
51
|
+
if (args.includes('--version')) { console.log('@znmin/claude-remote-cli 0.1.1'); return 0; }
|
|
51
52
|
if (process.stdin.isTTY) await configure(client, []);
|
|
52
53
|
}
|
|
53
54
|
return client.launch(await client.settings(), args);
|
|
54
55
|
}
|
|
55
56
|
const [action, ...rest] = args;
|
|
56
57
|
if (!action || ['--help', '-h', 'help'].includes(action)) { console.log(HELP); return 0; }
|
|
57
|
-
if (['--version', '-v'].includes(action)) { console.log('0.1.
|
|
58
|
+
if (['--version', '-v'].includes(action)) { console.log('0.1.1'); return 0; }
|
|
58
59
|
if (action === 'configure') { await configure(client, rest); return 0; }
|
|
59
60
|
if (action === 'run') return client.launch(await client.settings(), rest[0] === '--' ? rest.slice(1) : rest);
|
|
60
61
|
if (action === 'stop') {
|
package/src/client.js
CHANGED
|
@@ -4,6 +4,7 @@ import os from 'node:os';
|
|
|
4
4
|
import { createHash, randomUUID } from 'node:crypto';
|
|
5
5
|
import { execute, exists, quote, readJSON, shellJoin, which, withLock, writeJSON } from './system.js';
|
|
6
6
|
import { ensureMutagen } from './installer.js';
|
|
7
|
+
import { ensureRemoteClaude, remoteEnvironment as prefix } from './remote-claude.js';
|
|
7
8
|
|
|
8
9
|
export const DEFAULTS = {
|
|
9
10
|
root: '.local/share/claude-remote/projects', claude: 'claude',
|
|
@@ -28,7 +29,6 @@ export function validate(config) {
|
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
export const remotePath = file => file.startsWith('/') ? quote(file) : '"$HOME"/' + quote(file);
|
|
31
|
-
const prefix = 'export PATH="$HOME/.local/bin:$PATH"; ';
|
|
32
32
|
|
|
33
33
|
export function sshArgs(config, script, { interactive = false, tty = false } = {}) {
|
|
34
34
|
const args = ['-o', 'ConnectTimeout=15', '-o', 'ServerAliveInterval=15', '-o', 'ServerAliveCountMax=3'];
|
|
@@ -136,9 +136,9 @@ export class Client {
|
|
|
136
136
|
assertSynchronized((await this.sessions()).find(session => session.name === name));
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
-
async remote(config, script, interactive = false) {
|
|
139
|
+
async remote(config, script, interactive = false, { timeout = 180000 } = {}) {
|
|
140
140
|
return this.execute('ssh', sshArgs(config, script, { interactive, tty: interactive && this.tty }),
|
|
141
|
-
{ env: this.env, timeout: interactive ? 0 :
|
|
141
|
+
{ env: this.env, timeout: interactive ? 0 : timeout, check: !interactive });
|
|
142
142
|
}
|
|
143
143
|
|
|
144
144
|
async launch(config, extra) {
|
|
@@ -162,9 +162,8 @@ export class Client {
|
|
|
162
162
|
if (inside(relative) || inside(reverse))
|
|
163
163
|
throw new Error(`目录与正在同步的项目重叠:${other}\n先运行:claude-remote stop --name ${session.name}`);
|
|
164
164
|
}
|
|
165
|
-
await this.remote(config,
|
|
166
|
-
|
|
167
|
-
'mkdir -p -- ' + remotePath(item.remote));
|
|
165
|
+
await this.remote(config, ensureRemoteClaude(config.claude) +
|
|
166
|
+
'mkdir -p -- ' + remotePath(item.remote), false, { timeout: 600000 });
|
|
168
167
|
if (existing.some(session => session.name === item.name)) {
|
|
169
168
|
await this.sync(['resume', item.name], { timeout: 60000, capture: !this.tty });
|
|
170
169
|
} else {
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { quote } from './system.js';
|
|
2
|
+
|
|
3
|
+
export const remoteEnvironment = 'export PATH="$HOME/.local/bin:$PATH"; ';
|
|
4
|
+
|
|
5
|
+
export function ensureRemoteClaude(command) {
|
|
6
|
+
const missing = command === 'claude' ? `
|
|
7
|
+
echo '服务器未安装 Claude Code,正在执行官方安装流程……' >&2
|
|
8
|
+
(
|
|
9
|
+
set -e
|
|
10
|
+
installer=$(mktemp "\${TMPDIR:-/tmp}/claude-remote-install.XXXXXXXX")
|
|
11
|
+
trap 'rm -f -- "$installer"' EXIT
|
|
12
|
+
if command -v curl >/dev/null 2>&1; then
|
|
13
|
+
curl -fSL --connect-timeout 20 --max-time 120 --retry 2 \\
|
|
14
|
+
--output "$installer" https://claude.ai/install.sh
|
|
15
|
+
elif command -v wget >/dev/null 2>&1; then
|
|
16
|
+
wget --timeout=120 --tries=3 --output-document="$installer" https://claude.ai/install.sh
|
|
17
|
+
else
|
|
18
|
+
echo '自动安装需要服务器提供 curl 或 wget,请先安装其中一个工具。' >&2
|
|
19
|
+
exit 127
|
|
20
|
+
fi
|
|
21
|
+
if ! bash "$installer" >&2; then
|
|
22
|
+
echo 'Claude Code 官方安装失败,请检查上述输出、网络连接和目录权限后重试。' >&2
|
|
23
|
+
exit 1
|
|
24
|
+
fi
|
|
25
|
+
)
|
|
26
|
+
hash -r
|
|
27
|
+
if ! command -v claude >/dev/null 2>&1; then
|
|
28
|
+
echo '安装器已退出,但仍找不到 Claude Code。请检查 ~/.local/bin/claude 或通过 --claude 指定绝对路径。' >&2
|
|
29
|
+
exit 127
|
|
30
|
+
fi
|
|
31
|
+
echo 'Claude Code 已安装,首次启动时请按提示完成账号认证。' >&2
|
|
32
|
+
` : `
|
|
33
|
+
echo ${quote('找不到配置的 Claude 程序:' + command + '。请修正 --claude 路径,或配置 --claude claude 使用自动安装。')} >&2
|
|
34
|
+
exit 127
|
|
35
|
+
`;
|
|
36
|
+
// A failed download/installer must stop before any project directory is created or synced.
|
|
37
|
+
return 'set -e\n' + remoteEnvironment + '\n' +
|
|
38
|
+
`if ! command -v ${quote(command)} >/dev/null 2>&1; then\n${missing}fi\n`;
|
|
39
|
+
}
|