@cjwddz/mirror 0.0.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 +125 -0
- package/dist/cli/host-impl.d.ts +37 -0
- package/dist/cli/host-impl.d.ts.map +1 -0
- package/dist/cli/host-impl.js +264 -0
- package/dist/cli/host-impl.js.map +1 -0
- package/dist/cli/host.d.ts +10 -0
- package/dist/cli/host.d.ts.map +1 -0
- package/dist/cli/host.js +33 -0
- package/dist/cli/host.js.map +1 -0
- package/dist/cli/index.d.ts +6 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +24 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/link.d.ts +5 -0
- package/dist/cli/link.d.ts.map +1 -0
- package/dist/cli/link.js +222 -0
- package/dist/cli/link.js.map +1 -0
- package/dist/core/file-sync.d.ts +10 -0
- package/dist/core/file-sync.d.ts.map +1 -0
- package/dist/core/file-sync.js +18 -0
- package/dist/core/file-sync.js.map +1 -0
- package/dist/core/process-manager.d.ts +19 -0
- package/dist/core/process-manager.d.ts.map +1 -0
- package/dist/core/process-manager.js +76 -0
- package/dist/core/process-manager.js.map +1 -0
- package/dist/core/protocol.d.ts +60 -0
- package/dist/core/protocol.d.ts.map +1 -0
- package/dist/core/protocol.js +10 -0
- package/dist/core/protocol.js.map +1 -0
- package/dist/core/state-machine.d.ts +18 -0
- package/dist/core/state-machine.d.ts.map +1 -0
- package/dist/core/state-machine.js +39 -0
- package/dist/core/state-machine.js.map +1 -0
- package/dist/core/workspace.d.ts +31 -0
- package/dist/core/workspace.d.ts.map +1 -0
- package/dist/core/workspace.js +78 -0
- package/dist/core/workspace.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/test/index.test.d.ts +5 -0
- package/dist/test/index.test.d.ts.map +1 -0
- package/dist/test/index.test.js +12 -0
- package/dist/test/index.test.js.map +1 -0
- package/dist/transport/pty.d.ts +7 -0
- package/dist/transport/pty.d.ts.map +1 -0
- package/dist/transport/pty.js +26 -0
- package/dist/transport/pty.js.map +1 -0
- package/dist/transport/websocket.d.ts +20 -0
- package/dist/transport/websocket.d.ts.map +1 -0
- package/dist/transport/websocket.js +83 -0
- package/dist/transport/websocket.js.map +1 -0
- package/package.json +43 -0
package/README.md
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# Mirror —— 开发态远程工作空间镜像工具
|
|
2
|
+
|
|
3
|
+
开发态远程工作空间镜像工具,将本地项目目录镜像到远程服务器,并在远程执行命令。
|
|
4
|
+
|
|
5
|
+
## 功能特性
|
|
6
|
+
|
|
7
|
+
- ✅ 全量文件同步(SNAPSHOT)
|
|
8
|
+
- ✅ 增量文件同步(FILE_DIFF)
|
|
9
|
+
- ✅ 远程命令执行(PTY 支持)
|
|
10
|
+
- ✅ 文件变更实时监听
|
|
11
|
+
- ✅ 状态机保证一致性
|
|
12
|
+
- ✅ 一次性 workspace,完全可丢弃
|
|
13
|
+
|
|
14
|
+
## 安装
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install -g @cjwddz/mirror
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## 使用方法
|
|
21
|
+
|
|
22
|
+
### 1. 启动 Host(远程服务器)
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
mirror host --port 7331
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
或者指定 token:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
mirror host --port 7331 --token my-custom-token
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
可选参数:
|
|
35
|
+
|
|
36
|
+
- `--port <port>`: 端口号(默认: 7331)
|
|
37
|
+
- `--tmp-dir <dir>`: 临时目录(默认: /tmp)
|
|
38
|
+
- `--ignore <patterns>`: 忽略的文件模式,逗号分隔(默认: node_modules,.git)
|
|
39
|
+
- `--token <token>`: 指定 session token(不指定则自动生成)
|
|
40
|
+
|
|
41
|
+
启动后会显示连接地址:
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
Mirror host started
|
|
45
|
+
Listening on :7331
|
|
46
|
+
|
|
47
|
+
Connect using:
|
|
48
|
+
mirror link 192.168.1.100:7331?token=KJ82mZpX...
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### 2. 连接 Client(本地开发机)
|
|
52
|
+
|
|
53
|
+
在项目目录中执行:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
mirror link 192.168.1.100:7331?token=KJ82mZpX...
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
连接成功后:
|
|
60
|
+
|
|
61
|
+
1. 自动进行全量文件同步
|
|
62
|
+
2. 启动文件监听(增量同步)
|
|
63
|
+
3. 进入交互式终端
|
|
64
|
+
|
|
65
|
+
在交互式终端中输入命令,命令会在远程服务器的工作空间中执行。
|
|
66
|
+
|
|
67
|
+
输入 `exit` 或 `quit` 退出。
|
|
68
|
+
|
|
69
|
+
## 工作原理
|
|
70
|
+
|
|
71
|
+
### 状态机
|
|
72
|
+
|
|
73
|
+
Host 维护以下状态:
|
|
74
|
+
|
|
75
|
+
- `EMPTY`: 无 client 连接
|
|
76
|
+
- `SYNCING`: 文件同步中(禁止 exec)
|
|
77
|
+
- `READY`: 文件一致,可 exec
|
|
78
|
+
- `RUNNING`: 命令执行中
|
|
79
|
+
|
|
80
|
+
### Workspace Version
|
|
81
|
+
|
|
82
|
+
- version 为单调递增整数
|
|
83
|
+
- 由 client 生成
|
|
84
|
+
- exec 时必须声明 version
|
|
85
|
+
- host 仅在 `exec.version === currentVersion` 时允许执行
|
|
86
|
+
|
|
87
|
+
### 文件同步
|
|
88
|
+
|
|
89
|
+
- **全量同步(SNAPSHOT)**: 连接时一次性同步所有文件
|
|
90
|
+
- **增量同步(FILE_DIFF)**: 文件变更时实时同步
|
|
91
|
+
- `READY` 状态:立即应用
|
|
92
|
+
- `RUNNING` 状态:放入 pending 队列,命令结束后按顺序应用
|
|
93
|
+
|
|
94
|
+
### 进程管理
|
|
95
|
+
|
|
96
|
+
- 使用 PTY 支持交互式命令
|
|
97
|
+
- 命令执行在独立的进程组中
|
|
98
|
+
- 断开连接时自动清理所有进程
|
|
99
|
+
|
|
100
|
+
## 注意事项
|
|
101
|
+
|
|
102
|
+
- ⚠️ 仅用于开发阶段,不适用于生产环境
|
|
103
|
+
- ⚠️ 不支持多 client 并发(新连接会抢占旧连接)
|
|
104
|
+
- ⚠️ workspace 是临时的,断开连接后自动清理
|
|
105
|
+
- ⚠️ 不支持恢复,需要重新连接
|
|
106
|
+
|
|
107
|
+
## 开发
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
# 安装依赖
|
|
111
|
+
npm install
|
|
112
|
+
|
|
113
|
+
# 构建
|
|
114
|
+
npm run build
|
|
115
|
+
|
|
116
|
+
# 测试
|
|
117
|
+
npm test
|
|
118
|
+
|
|
119
|
+
# Lint
|
|
120
|
+
npm run lint
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## License
|
|
124
|
+
|
|
125
|
+
MIT
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host 实现类
|
|
3
|
+
*/
|
|
4
|
+
interface HostOptions {
|
|
5
|
+
port: number;
|
|
6
|
+
tmpDir?: string;
|
|
7
|
+
ignore?: string[];
|
|
8
|
+
token?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare class Host {
|
|
11
|
+
private transport;
|
|
12
|
+
private stateMachine;
|
|
13
|
+
private workspace;
|
|
14
|
+
private processManager;
|
|
15
|
+
private currentClientId;
|
|
16
|
+
private sessionToken;
|
|
17
|
+
private options;
|
|
18
|
+
private snapshotFiles;
|
|
19
|
+
private isSnapshotInProgress;
|
|
20
|
+
constructor(options: HostOptions);
|
|
21
|
+
private generateToken;
|
|
22
|
+
start(): Promise<void>;
|
|
23
|
+
private getHostname;
|
|
24
|
+
private handleConnection;
|
|
25
|
+
private handleMessage;
|
|
26
|
+
private handleHello;
|
|
27
|
+
private handleSnapshotStart;
|
|
28
|
+
private handleFile;
|
|
29
|
+
private handleSnapshotEnd;
|
|
30
|
+
private handleFileDiff;
|
|
31
|
+
private handleExec;
|
|
32
|
+
private sendError;
|
|
33
|
+
private cleanup;
|
|
34
|
+
stop(): Promise<void>;
|
|
35
|
+
}
|
|
36
|
+
export {};
|
|
37
|
+
//# sourceMappingURL=host-impl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host-impl.d.ts","sourceRoot":"","sources":["../../src/cli/host-impl.ts"],"names":[],"mappings":"AAAA;;GAEG;AAoBH,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,IAAI;IACf,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,SAAS,CAA0B;IAC3C,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,eAAe,CAAuB;IAC9C,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,aAAa,CAA6D;IAClF,OAAO,CAAC,oBAAoB,CAAkB;gBAElC,OAAO,EAAE,WAAW;IAShC,OAAO,CAAC,aAAa;IAIf,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAe5B,OAAO,CAAC,WAAW;YAoBL,gBAAgB;YA0BhB,aAAa;YAyBb,WAAW;YAcX,mBAAmB;YAanB,UAAU;YAkBV,iBAAiB;YAiBjB,cAAc;YAmCd,UAAU;IAiExB,OAAO,CAAC,SAAS;YAUH,OAAO;IAiBf,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAI5B"}
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host 实现类
|
|
3
|
+
*/
|
|
4
|
+
import { randomBytes } from 'crypto';
|
|
5
|
+
import { networkInterfaces } from 'os';
|
|
6
|
+
import { WebSocketTransport } from '../transport/websocket.js';
|
|
7
|
+
import { StateMachine, HostState } from '../core/state-machine.js';
|
|
8
|
+
import { Workspace } from '../core/workspace.js';
|
|
9
|
+
import { ProcessManager } from '../core/process-manager.js';
|
|
10
|
+
import { computeHash } from '../core/file-sync.js';
|
|
11
|
+
export class Host {
|
|
12
|
+
transport;
|
|
13
|
+
stateMachine;
|
|
14
|
+
workspace = null;
|
|
15
|
+
processManager;
|
|
16
|
+
currentClientId = null;
|
|
17
|
+
sessionToken;
|
|
18
|
+
options;
|
|
19
|
+
snapshotFiles = new Map();
|
|
20
|
+
isSnapshotInProgress = false;
|
|
21
|
+
constructor(options) {
|
|
22
|
+
this.transport = new WebSocketTransport();
|
|
23
|
+
this.stateMachine = new StateMachine();
|
|
24
|
+
this.processManager = new ProcessManager();
|
|
25
|
+
this.options = options;
|
|
26
|
+
// 如果提供了 token 就使用,否则自动生成
|
|
27
|
+
this.sessionToken = options.token || this.generateToken();
|
|
28
|
+
}
|
|
29
|
+
generateToken() {
|
|
30
|
+
return randomBytes(32).toString('base64url');
|
|
31
|
+
}
|
|
32
|
+
async start() {
|
|
33
|
+
const port = this.options.port;
|
|
34
|
+
await this.transport.createServer(port, (ws) => {
|
|
35
|
+
this.handleConnection(ws);
|
|
36
|
+
});
|
|
37
|
+
const hostname = this.getHostname();
|
|
38
|
+
console.log('Mirror host started');
|
|
39
|
+
console.log(`Listening on :${port}`);
|
|
40
|
+
console.log('');
|
|
41
|
+
console.log('Connect using:');
|
|
42
|
+
console.log(`mirror link ${hostname}:${port}?token=${this.sessionToken}`);
|
|
43
|
+
}
|
|
44
|
+
getHostname() {
|
|
45
|
+
// 尝试获取本机 IP
|
|
46
|
+
const interfaces = networkInterfaces();
|
|
47
|
+
for (const name of Object.keys(interfaces)) {
|
|
48
|
+
const ifaces = interfaces[name];
|
|
49
|
+
if (!ifaces)
|
|
50
|
+
continue;
|
|
51
|
+
for (const iface of ifaces) {
|
|
52
|
+
// 跳过内部(即 127.0.0.1)和非 IPv4 地址
|
|
53
|
+
if (iface.family === 'IPv4' && !iface.internal) {
|
|
54
|
+
return iface.address;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// 如果没有找到外部 IP,返回 localhost
|
|
59
|
+
return 'localhost';
|
|
60
|
+
}
|
|
61
|
+
async handleConnection(ws) {
|
|
62
|
+
// 清理旧连接
|
|
63
|
+
if (this.currentClientId) {
|
|
64
|
+
await this.cleanup();
|
|
65
|
+
}
|
|
66
|
+
ws.on('message', async (data) => {
|
|
67
|
+
try {
|
|
68
|
+
const message = JSON.parse(data.toString());
|
|
69
|
+
await this.handleMessage(ws, message);
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
console.error('Failed to handle message:', error);
|
|
73
|
+
this.sendError(ws, 'Failed to handle message');
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
ws.on('close', async () => {
|
|
77
|
+
await this.cleanup();
|
|
78
|
+
});
|
|
79
|
+
ws.on('error', async (error) => {
|
|
80
|
+
console.error('WebSocket error:', error);
|
|
81
|
+
await this.cleanup();
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
async handleMessage(ws, message) {
|
|
85
|
+
switch (message.type) {
|
|
86
|
+
case 'HELLO':
|
|
87
|
+
await this.handleHello(ws, message);
|
|
88
|
+
break;
|
|
89
|
+
case 'SNAPSHOT_START':
|
|
90
|
+
await this.handleSnapshotStart(ws, message);
|
|
91
|
+
break;
|
|
92
|
+
case 'FILE':
|
|
93
|
+
await this.handleFile(ws, message);
|
|
94
|
+
break;
|
|
95
|
+
case 'SNAPSHOT_END':
|
|
96
|
+
await this.handleSnapshotEnd(ws, message);
|
|
97
|
+
break;
|
|
98
|
+
case 'FILE_DIFF':
|
|
99
|
+
await this.handleFileDiff(ws, message);
|
|
100
|
+
break;
|
|
101
|
+
case 'EXEC':
|
|
102
|
+
await this.handleExec(ws, message);
|
|
103
|
+
break;
|
|
104
|
+
default:
|
|
105
|
+
this.sendError(ws, `Unknown message type: ${message.type}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
async handleHello(ws, message) {
|
|
109
|
+
// 验证 token
|
|
110
|
+
if (message.token !== this.sessionToken) {
|
|
111
|
+
this.sendError(ws, 'Invalid token');
|
|
112
|
+
ws.close();
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
this.currentClientId = message.clientId;
|
|
116
|
+
this.stateMachine.transitionTo(HostState.SYNCING);
|
|
117
|
+
this.snapshotFiles.clear();
|
|
118
|
+
this.isSnapshotInProgress = false;
|
|
119
|
+
}
|
|
120
|
+
async handleSnapshotStart(ws, _message) {
|
|
121
|
+
if (this.stateMachine.getState() !== HostState.SYNCING) {
|
|
122
|
+
this.sendError(ws, 'Invalid state for SNAPSHOT_START');
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
// 创建 workspace
|
|
126
|
+
const tmpDir = this.options.tmpDir || '/tmp';
|
|
127
|
+
this.workspace = await Workspace.create(tmpDir);
|
|
128
|
+
this.isSnapshotInProgress = true;
|
|
129
|
+
this.snapshotFiles.clear();
|
|
130
|
+
}
|
|
131
|
+
async handleFile(ws, message) {
|
|
132
|
+
if (!this.isSnapshotInProgress || !this.workspace) {
|
|
133
|
+
this.sendError(ws, 'SNAPSHOT not in progress');
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const content = Buffer.from(message.content, 'base64');
|
|
137
|
+
const hash = computeHash(content);
|
|
138
|
+
// 验证 hash
|
|
139
|
+
if (hash !== message.hash) {
|
|
140
|
+
this.sendError(ws, `Hash mismatch for ${message.path}`);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
this.snapshotFiles.set(message.path, { hash, content });
|
|
144
|
+
}
|
|
145
|
+
async handleSnapshotEnd(ws, message) {
|
|
146
|
+
if (!this.isSnapshotInProgress || !this.workspace) {
|
|
147
|
+
this.sendError(ws, 'SNAPSHOT not in progress');
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
// 写入所有文件
|
|
151
|
+
for (const [path, { content }] of this.snapshotFiles) {
|
|
152
|
+
await this.workspace.writeFile(path, content);
|
|
153
|
+
}
|
|
154
|
+
this.workspace.setVersion(message.version);
|
|
155
|
+
this.stateMachine.transitionTo(HostState.READY);
|
|
156
|
+
this.isSnapshotInProgress = false;
|
|
157
|
+
this.snapshotFiles.clear();
|
|
158
|
+
}
|
|
159
|
+
async handleFileDiff(ws, message) {
|
|
160
|
+
if (!this.workspace) {
|
|
161
|
+
this.sendError(ws, 'Workspace not initialized');
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
const state = this.stateMachine.getState();
|
|
165
|
+
if (state === HostState.READY) {
|
|
166
|
+
// 立即应用
|
|
167
|
+
if (message.op === 'update' && message.content) {
|
|
168
|
+
const content = Buffer.from(message.content, 'base64');
|
|
169
|
+
const hash = computeHash(content);
|
|
170
|
+
if (hash !== message.hash) {
|
|
171
|
+
this.sendError(ws, `Hash mismatch for ${message.path}`);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
await this.workspace.writeFile(message.path, content);
|
|
175
|
+
}
|
|
176
|
+
else if (message.op === 'delete') {
|
|
177
|
+
await this.workspace.deleteFile(message.path);
|
|
178
|
+
}
|
|
179
|
+
this.workspace.setVersion(message.version);
|
|
180
|
+
}
|
|
181
|
+
else if (state === HostState.RUNNING) {
|
|
182
|
+
// 放入 pending 队列
|
|
183
|
+
this.workspace.addPendingDiff({
|
|
184
|
+
version: message.version,
|
|
185
|
+
op: message.op,
|
|
186
|
+
path: message.path,
|
|
187
|
+
content: message.content,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
this.sendError(ws, `Invalid state for FILE_DIFF: ${state}`);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
async handleExec(ws, message) {
|
|
195
|
+
if (!this.workspace) {
|
|
196
|
+
this.sendError(ws, 'Workspace not initialized');
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
// 验证状态
|
|
200
|
+
if (!this.stateMachine.canExec()) {
|
|
201
|
+
this.sendError(ws, `Cannot exec in state: ${this.stateMachine.getState()}`);
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
// 验证版本
|
|
205
|
+
if (message.version !== this.workspace.getCurrentVersion()) {
|
|
206
|
+
this.sendError(ws, `Version mismatch: expected ${this.workspace.getCurrentVersion()}, got ${message.version}`);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
// 启动进程
|
|
210
|
+
const ptyProcess = await this.processManager.spawn(message.execId, message.command, this.workspace.getPath());
|
|
211
|
+
this.stateMachine.transitionTo(HostState.RUNNING);
|
|
212
|
+
// 监听输出
|
|
213
|
+
ptyProcess.onData((data) => {
|
|
214
|
+
ws.send(JSON.stringify({
|
|
215
|
+
type: 'EXEC_OUTPUT',
|
|
216
|
+
execId: message.execId,
|
|
217
|
+
stream: 'stdout',
|
|
218
|
+
data,
|
|
219
|
+
}));
|
|
220
|
+
});
|
|
221
|
+
// 监听退出
|
|
222
|
+
ptyProcess.onExit(async (exit) => {
|
|
223
|
+
ws.send(JSON.stringify({
|
|
224
|
+
type: 'EXEC_EXIT',
|
|
225
|
+
execId: message.execId,
|
|
226
|
+
code: exit.exitCode,
|
|
227
|
+
}));
|
|
228
|
+
// 清理进程
|
|
229
|
+
this.processManager.removeProcess(message.execId);
|
|
230
|
+
// 应用 pending diffs
|
|
231
|
+
if (this.workspace) {
|
|
232
|
+
await this.workspace.applyPendingDiffs();
|
|
233
|
+
}
|
|
234
|
+
// 回到 READY 状态
|
|
235
|
+
this.stateMachine.transitionTo(HostState.READY);
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
sendError(ws, message, code) {
|
|
239
|
+
ws.send(JSON.stringify({
|
|
240
|
+
type: 'ERROR',
|
|
241
|
+
message,
|
|
242
|
+
code,
|
|
243
|
+
}));
|
|
244
|
+
}
|
|
245
|
+
async cleanup() {
|
|
246
|
+
// 清理进程
|
|
247
|
+
await this.processManager.killAll();
|
|
248
|
+
// 清理 workspace
|
|
249
|
+
if (this.workspace) {
|
|
250
|
+
await this.workspace.cleanup();
|
|
251
|
+
this.workspace = null;
|
|
252
|
+
}
|
|
253
|
+
// 重置状态
|
|
254
|
+
this.stateMachine.reset();
|
|
255
|
+
this.currentClientId = null;
|
|
256
|
+
this.snapshotFiles.clear();
|
|
257
|
+
this.isSnapshotInProgress = false;
|
|
258
|
+
}
|
|
259
|
+
async stop() {
|
|
260
|
+
await this.cleanup();
|
|
261
|
+
this.transport.close();
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
//# sourceMappingURL=host-impl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host-impl.js","sourceRoot":"","sources":["../../src/cli/host-impl.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../../src/cli/host.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,wBAAsB,WAAW,CAAC,OAAO,EAAE;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,IAAI,CAAC,CA+BhB"}
|
package/dist/cli/host.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host CLI 命令处理
|
|
3
|
+
*/
|
|
4
|
+
import { Host } from './host-impl.js';
|
|
5
|
+
export async function hostCommand(options) {
|
|
6
|
+
const port = parseInt(options.port, 10);
|
|
7
|
+
if (isNaN(port) || port < 1 || port > 65535) {
|
|
8
|
+
console.error('Invalid port number');
|
|
9
|
+
process.exit(1);
|
|
10
|
+
}
|
|
11
|
+
const ignore = options.ignore?.split(',').map((s) => s.trim()) || ['node_modules', '.git'];
|
|
12
|
+
const host = new Host({
|
|
13
|
+
port,
|
|
14
|
+
tmpDir: options.tmpDir,
|
|
15
|
+
ignore,
|
|
16
|
+
token: options.token,
|
|
17
|
+
});
|
|
18
|
+
// 处理退出信号
|
|
19
|
+
const cleanup = async () => {
|
|
20
|
+
await host.stop();
|
|
21
|
+
process.exit(0);
|
|
22
|
+
};
|
|
23
|
+
process.on('SIGINT', cleanup);
|
|
24
|
+
process.on('SIGTERM', cleanup);
|
|
25
|
+
try {
|
|
26
|
+
await host.start();
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
console.error('Failed to start host:', error);
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=host.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host.js","sourceRoot":"","sources":["../../src/cli/host.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAEtC,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAKjC;IACC,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACxC,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,KAAK,EAAE,CAAC;QAC5C,OAAO,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;QACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;IAE3F,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC;QACpB,IAAI;QACJ,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,MAAM;QACN,KAAK,EAAE,OAAO,CAAC,KAAK;KACrB,CAAC,CAAC;IAEH,SAAS;IACT,MAAM,OAAO,GAAG,KAAK,IAAI,EAAE;QACzB,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC9B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IAE/B,IAAI,CAAC;QACH,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,uBAAuB,EAAE,KAAK,CAAC,CAAC;QAC9C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AAEA;;GAEG"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Mirror CLI 入口
|
|
4
|
+
*/
|
|
5
|
+
import { Command } from 'commander';
|
|
6
|
+
import { hostCommand } from './host.js';
|
|
7
|
+
import { linkCommand } from './link.js';
|
|
8
|
+
const program = new Command();
|
|
9
|
+
program.name('mirror').description('开发态远程工作空间镜像工具').version('0.0.0');
|
|
10
|
+
program
|
|
11
|
+
.command('host')
|
|
12
|
+
.description('启动远程 host 服务')
|
|
13
|
+
.option('-p, --port <port>', '端口号', '7331')
|
|
14
|
+
.option('--tmp-dir <dir>', '临时目录', '/tmp')
|
|
15
|
+
.option('--ignore <patterns>', '忽略的文件模式(逗号分隔)', 'node_modules,.git')
|
|
16
|
+
.option('--token <token>', '指定 session token(不指定则自动生成)')
|
|
17
|
+
.action(hostCommand);
|
|
18
|
+
program
|
|
19
|
+
.command('link')
|
|
20
|
+
.description('连接到远程 host')
|
|
21
|
+
.argument('<url>', '连接地址,格式: host:port?token=xxx')
|
|
22
|
+
.action(linkCommand);
|
|
23
|
+
program.parse();
|
|
24
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AAEA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;AAErE,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,cAAc,CAAC;KAC3B,MAAM,CAAC,mBAAmB,EAAE,KAAK,EAAE,MAAM,CAAC;KAC1C,MAAM,CAAC,iBAAiB,EAAE,MAAM,EAAE,MAAM,CAAC;KACzC,MAAM,CAAC,qBAAqB,EAAE,eAAe,EAAE,mBAAmB,CAAC;KACnE,MAAM,CAAC,iBAAiB,EAAE,4BAA4B,CAAC;KACvD,MAAM,CAAC,WAAW,CAAC,CAAC;AAEvB,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,YAAY,CAAC;KACzB,QAAQ,CAAC,OAAO,EAAE,8BAA8B,CAAC;KACjD,MAAM,CAAC,WAAW,CAAC,CAAC;AAEvB,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../../src/cli/link.ts"],"names":[],"mappings":"AAAA;;GAEG;AAYH,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAoD5D"}
|