code-server-sync 0.0.0-stage → 0.1.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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,12 @@
1
+ # 更新日志
2
+
3
+ ## 0.1.0 - 2026-10-27
4
+
5
+ 首次发布 npm 包 `code-server-sync`,命令名是 `cs-sync`。
6
+
7
+ - 本机(Windows、macOS)和云端(Linux)安装同一个包
8
+ - 经 code-server 已登录的 `/proxy/<端口>/` 同步项目代码
9
+ - `token` 直接打印 `cs-sync recv ...`,不必再填写云端脚本路径
10
+ - 支持 `init`、`login`、`cookie`、`doctor`、`list`、`remove`、`token`、`to-cloud`、`to-local`、`diff-to-cloud`、`diff-to-local`、`sync`、`recv`、`self-test`
11
+ - 整份同步、行级 diff、启动后的双向监视,以及 `--dry-run`
12
+ - `cs-sync --version` 打印当前安装的版本
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Nie Tao
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,252 @@
1
- # Temporary Holding Version
1
+ # cs-sync
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ `cs-sync` 在本机目录与运行 code-server 的云主机目录之间同步代码。
4
+
5
+ 通道使用 code-server 已经登录的 `/proxy/<端口>/`,不另外开放公网入口。云端用同一个命令启动接收进程 `recv`。
6
+
7
+ 本机可以是 Windows 或 macOS。云端接收进程运行在 Linux 上。
8
+
9
+ ## 适合谁
10
+
11
+ 适合需要在本机编辑,并把代码同步到一台已经登录的 code-server 云主机的人。
12
+
13
+ 它不替代编辑器、编译器或部署流水线。
14
+
15
+ ## 一次完整使用会经过什么
16
+
17
+ 1. 在本机和云端都安装 `code-server-sync`
18
+ 2. 登记本机目录、云端目录和 code-server 地址
19
+ 3. 写入 code-server 登录态
20
+ 4. 用 `token` 打印云端接收命令
21
+ 5. 把打印出的 `cs-sync recv ...` 贴到云端终端
22
+ 6. 用 `doctor` 检查通道
23
+ 7. 先 `--dry-run`,再正式同步
24
+
25
+ | 步骤 | 命令 | 结果 |
26
+ |------|------|------|
27
+ | 登记 | `cs-sync init` | 生成项目令牌和接收端口,并打印云端启动命令 |
28
+ | 登录 | `cs-sync login` 或 `cs-sync cookie` | 把 code-server 登录态记到本机配置 |
29
+ | 打印命令 | `cs-sync token` | 再次打印要贴到云端的 `cs-sync recv ...` |
30
+ | 启动接收 | 云端执行 `cs-sync recv ...` | 云端开始在该端口接收 |
31
+ | 检查 | `cs-sync doctor` | 确认代理、令牌和路径校验 |
32
+ | 演练 | `cs-sync to-cloud --dry-run` | 只列出将要发生的变化 |
33
+ | 同步 | `cs-sync to-cloud` 或 `cs-sync sync` | 按所选方式写入 |
34
+
35
+ 在 `localRoot` 目录内运行时可以省略 `--name`。
36
+
37
+ ## 前提
38
+
39
+ 本机(Windows 或 macOS):
40
+
41
+ - Node.js 18 及以上
42
+ - Python 3.9 及以上。Windows 上使用 `py -3` 或 `python`,macOS 上使用 `python3`
43
+ - Git。整份同步前的暂存、行级 diff 和 `sync` 都会用到
44
+
45
+ 云端(Linux):
46
+
47
+ - 已安装同一个包
48
+ - Python 3.9 及以上
49
+
50
+ ## 安装
51
+
52
+ 本机和云端都执行:
53
+
54
+ ```bash
55
+ npm install -g code-server-sync
56
+ cs-sync --help
57
+ cs-sync --version
58
+ ```
59
+
60
+ 不安装到全局时:
61
+
62
+ ```bash
63
+ npx code-server-sync --help
64
+ ```
65
+
66
+ ## 最短上手
67
+
68
+ ```bash
69
+ cs-sync init \
70
+ --name 我的项目 \
71
+ --local /本机/项目目录 \
72
+ --remote /云端/绝对路径 \
73
+ --base https://code-server主机:端口
74
+
75
+ cs-sync login
76
+
77
+ cs-sync token --name 我的项目
78
+ ```
79
+
80
+ 把 `token` 打印的那一行贴到云端 code-server 终端。它的形式是:
81
+
82
+ ```bash
83
+ cs-sync recv --root '/云端/绝对路径' --token '…' --port 27182
84
+ ```
85
+
86
+ 然后:
87
+
88
+ ```bash
89
+ cs-sync doctor --name 我的项目
90
+ cs-sync to-cloud --name 我的项目 --dry-run
91
+ cs-sync to-cloud --name 我的项目
92
+ cs-sync sync --name 我的项目
93
+ ```
94
+
95
+ Windows 上 `--local` 使用本机路径,例如 `C:\work\demo`。`--remote` 始终是云端 Linux 绝对路径。`token` 打印的引号按云端 shell 转义,直接粘贴到云端终端。
96
+
97
+ ## 按意图选择命令
98
+
99
+ ### 我要检查通道
100
+
101
+ ```bash
102
+ cs-sync doctor --name 我的项目
103
+ ```
104
+
105
+ ### 我要把本机整份覆盖到云端同名路径
106
+
107
+ ```bash
108
+ cs-sync to-cloud --name 我的项目
109
+ ```
110
+
111
+ ### 我要把云端整份覆盖到本机同名路径
112
+
113
+ ```bash
114
+ cs-sync to-local --name 我的项目
115
+ ```
116
+
117
+ ### 我只想把本机尚未提交的行级改动推上去
118
+
119
+ ```bash
120
+ cs-sync diff-to-cloud --name 我的项目
121
+ ```
122
+
123
+ ### 我只想把云端尚未提交的行级改动拉下来
124
+
125
+ ```bash
126
+ cs-sync diff-to-local --name 我的项目
127
+ ```
128
+
129
+ ### 我要在保存之后双向同步启动后的增量
130
+
131
+ ```bash
132
+ cs-sync sync --name 我的项目
133
+ ```
134
+
135
+ ## 命令一览
136
+
137
+ | 命令 | 作用 |
138
+ |------|------|
139
+ | `init` | 登记项目,生成令牌并分配端口 |
140
+ | `list` / `remove` | 列出或删除映射,不删除目录里的代码 |
141
+ | `login` / `cookie` | 写入 code-server 登录态,所有项目共用 |
142
+ | `token` | 打印云端 `recv` 启动命令 |
143
+ | `doctor` | 检查代理、令牌和路径校验 |
144
+ | `to-cloud` | 云端先 `git add -A`,再用本机文件覆盖云端同名路径 |
145
+ | `to-local` | 本机先 `git add -A`,再用云端文件覆盖本机同名路径 |
146
+ | `diff-to-cloud` | 云端先暂存,再把本机 `git diff` 行级推到云端;合不上则跳过 |
147
+ | `diff-to-local` | 本机先暂存,再把云端 `git diff` 行级拉到本机 |
148
+ | `sync` | 记下基线后,按行级增量与三路合并双向同步之后的保存 |
149
+ | `recv` | 只在云端 Linux 上运行,负责接收 |
150
+ | `self-test` | 在本机临时目录检查协议,不连接真实 code-server |
151
+
152
+ 同步类命令都支持 `--dry-run`。全局可选 `--config /某/项目.json`。`cs-sync --version` 打印当前安装的版本。
153
+
154
+ ## 三种同步
155
+
156
+ ### 整份:`to-cloud` / `to-local`
157
+
158
+ 按相对路径扫描,用 SHA-256 比较内容,相同则跳过。覆盖同名文件,对端独有的文件保留。正式执行前,对即将被覆盖的一侧执行 `git add -A`,把当前改动放进 index。`--dry-run` 不会暂存。
159
+
160
+ 默认同步忽略 `.git`、`node_modules`、`dist`、`build`、`.agents`、常见虚拟环境目录等。扫描时跳过约 32MB 以上的单个文件。上传和下载使用同一个大小限制,超过会拒绝。
161
+
162
+ ### 行级:`diff-to-cloud` / `diff-to-local`
163
+
164
+ 收集相对 `HEAD` 的 `git diff`,没有 `HEAD` 时使用已暂存内容,并包含未跟踪的新文件。对端在临时目录用 `git apply` 试算后再写入。合不上则跳过该文件,保留对端原内容。二进制、对端已经存在的「新增」和补丁冲突记为失败或冲突。
165
+
166
+ ### 监视:`sync`
167
+
168
+ 启动时扫描本机并读取云端清单,记下基线。两边当时已经不一致的内容只记基线,启动前的差异留给 `to-*` 或 `diff-*`。之后只同步启动后的保存。
169
+
170
+ 本地改动按相对上次已同步内容的行级 diff 推到云端。云端改动先试行级补丁,对不上再做三路合并。真冲突时保留这一侧已有内容,并打印提示。二进制不能按行同步。
171
+
172
+ | 日志 | 含义 |
173
+ |------|------|
174
+ | `本地改动` | 本机先改,并已同步到云端。删除时带「(删除)」 |
175
+ | `本地写入` | 因为云端变更,本机文件被写入或删除 |
176
+ | `云端改动` | 云端工作区先出现变更 |
177
+ | `云端写入` | 因为本机同步,云端文件被写入或删除 |
178
+
179
+ 云端日志仍是旧文案时,在云端升级 `code-server-sync` 并重启 `cs-sync recv`。本机的 `sync` 也要重新启动。
180
+
181
+ ## `.cs-syncignore`
182
+
183
+ 在本机目录或云端目录放置 `.cs-syncignore`,语法与 gitignore 类似:`*`、`?`、`**`、目录尾 `/`、`#` 注释、`!` 否定。
184
+
185
+ 它和内置忽略取并集,命中任一即跳过。`!` 不能抵消内置忽略,例如 `!node_modules` 无效。各端读取自己目录下的这份文件。扫描、整份同步、行级同步、`sync` 和 `--dry-run` 都会用它。
186
+
187
+ ## `--dry-run`
188
+
189
+ 适用于 `to-cloud`、`to-local`、`diff-to-cloud`、`diff-to-local`、`sync`。
190
+
191
+ 不会执行 `git add -A`,不会调用云端暂存,不会写入或删除项目目录中的文件,不会把补丁落到工作区,也不会推送忽略规则。`sync --dry-run` 不进入持续监视,打印当前双边差异后退出。
192
+
193
+ 会做连通检查,并只读读取云端清单。行级预览可能只读拉取对端内容,用来判断是相同跳过还是能够合入。
194
+
195
+ 清单标签包括:`add`、`modify`、`delete`、`skip-same`、`conflict`、`binary`、`local-only`、`remote-only`。
196
+
197
+ ## 配置
198
+
199
+ 默认目录是 `~/.config/cs-sync/`。Windows 上是 `%USERPROFILE%\.config\cs-sync`。环境变量 `CS_SYNC_HOME` 可以改到别处。
200
+
201
+ ```
202
+ ~/.config/cs-sync/
203
+ host.json
204
+ projects/
205
+ 我的项目.json
206
+ ```
207
+
208
+ **host.json**
209
+
210
+ | 字段 | 含义 |
211
+ |------|------|
212
+ | `baseUrl` | code-server 根地址 |
213
+ | `cookie` | `code-server-session=…` |
214
+ | `auth` | 例如 `password` 或 `none` |
215
+ | `insecure` | 是否跳过 TLS 校验 |
216
+
217
+ **projects/\*.json**
218
+
219
+ | 字段 | 含义 |
220
+ |------|------|
221
+ | `name` | 项目简称 |
222
+ | `localRoot` / `remoteRoot` | 本机目录 / 云端绝对路径 |
223
+ | `port` | 云端 recv 端口,默认从 27182 递增 |
224
+ | `token` | 项目令牌 |
225
+ | `ignoreDirs` | 忽略的目录名 |
226
+
227
+ 配置文件按 `0600` 写入。Windows 上权限由系统落成它能表达的结果。项目名区分大小写。
228
+
229
+ ## 使用时要注意
230
+
231
+ - 外网要先登录 code-server,才能到达同步接口。
232
+ - 持有项目 `token` 才能对 `recv` 做写入。`/health` 不校验令牌。
233
+ - `recv` 在云端监听 `0.0.0.0`,经 code-server `/proxy` 访问。端口不要对公网直接开放。
234
+ - `host.json` 可能含登录相关字段。它不是系统钥匙串。
235
+ - `token` 会出现在云端进程的命令行里,同机可以看见。
236
+ - 正式同步前的暂存是 `git add -A`,会改动对应仓库的 index。`--dry-run` 不会暂存。
237
+ - 常见初始化路径下,HTTPS 可能跳过证书校验。
238
+ - 单个文件超过约 32MB 时,上传和下载都会拒绝。
239
+
240
+ ## 常见问题
241
+
242
+ | 现象 | 可能原因 | 处理 |
243
+ |------|----------|------|
244
+ | doctor 返回网页 | Cookie 失效或未登录 | 重新 `cs-sync login` 或 `cs-sync cookie` |
245
+ | 502 / 连接被拒绝 | 云端 `recv` 未启动或端口不对 | 再执行 `cs-sync token`,把命令贴到云端 |
246
+ | 403 | 本机令牌与云端 `--token` 不一致 | 使用当前项目 `token` 打印出的命令 |
247
+ | 提示接收程序过旧 | 云端的包装版本旧,缺接口 | 在云端升级 `code-server-sync` 并重启 `cs-sync recv` |
248
+ | sync 不传启动前就改过的文件 | 只跟踪启动后的增量 | 改用 `to-*` 或 `diff-*`,或先看 `sync --dry-run` |
249
+ | 冲突后该文件本轮不动 | 同一处行变更合不上 | 人工对齐后再保存,或改用整份 / 行级命令 |
250
+ | 行级大量失败 | 补丁合不上或是二进制 | 改用整份同步,或先对齐内容 |
251
+ | 端口被其他程序占用 | 不是本工具的接收进程 | 按提示检查该端口后手动处理 |
252
+ | sync 在网络中断后继续 | 读超时被接住 | 恢复网络后会继续监视 |
package/bin/cs-sync.js ADDED
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ const { spawnSync } = require("child_process");
5
+ const path = require("path");
6
+
7
+ const VERSION_CHECK =
8
+ "import sys; raise SystemExit(0 if sys.version_info >= (3, 9) else 1)";
9
+
10
+ function candidates() {
11
+ if (process.platform === "win32") {
12
+ return [["py", "-3"], ["python"], ["python3"]];
13
+ }
14
+ return [["python3"], ["python"]];
15
+ }
16
+
17
+ function tryVersion(parts) {
18
+ const result = spawnSync(parts[0], parts.slice(1).concat(["-c", VERSION_CHECK]), {
19
+ encoding: "utf8",
20
+ stdio: ["ignore", "pipe", "pipe"],
21
+ });
22
+ if (result.error && result.error.code === "ENOENT") {
23
+ return "missing";
24
+ }
25
+ if (result.status === 0) {
26
+ return "ok";
27
+ }
28
+ return "old";
29
+ }
30
+
31
+ function fail(tried) {
32
+ const names = tried.map((parts) => parts.join(" ")).join("、");
33
+ const hint = process.platform === "win32"
34
+ ? "在 Windows 上安装 Python 3.9 及以上,并确认 py -3 或 python 可用。"
35
+ : "请安装 Python 3.9 及以上,并确认 python3 在 PATH 中。";
36
+ console.error("需要 Python 3.9 及以上才能运行 cs-sync。\n已尝试:" + names + "\n" + hint);
37
+ process.exit(1);
38
+ }
39
+
40
+ function main() {
41
+ const tried = [];
42
+ let chosen = null;
43
+ for (const parts of candidates()) {
44
+ tried.push(parts);
45
+ if (tryVersion(parts) === "ok") {
46
+ chosen = parts;
47
+ break;
48
+ }
49
+ }
50
+ if (!chosen) {
51
+ fail(tried);
52
+ }
53
+ const root = path.resolve(__dirname, "..");
54
+ const env = Object.assign({}, process.env);
55
+ env.PYTHONPATH = env.PYTHONPATH ? root + path.delimiter + env.PYTHONPATH : root;
56
+ const result = spawnSync(
57
+ chosen[0],
58
+ chosen.slice(1).concat(["-m", "cs_sync"], process.argv.slice(2)),
59
+ { env: env, stdio: "inherit" }
60
+ );
61
+ if (result.error) {
62
+ console.error("启动 Python 失败:" + result.error.message);
63
+ process.exit(1);
64
+ }
65
+ process.exit(result.status === null ? 1 : result.status);
66
+ }
67
+
68
+ main();
File without changes
@@ -0,0 +1,6 @@
1
+ from __future__ import annotations
2
+
3
+ from cs_sync.cli import main
4
+
5
+ if __name__ == "__main__":
6
+ main()