itwillsync 1.3.0 → 1.3.2
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/dist/hub/daemon.js +17 -2
- package/dist/hub/daemon.js.map +1 -1
- package/dist/index.js +120 -14
- package/dist/index.js.map +1 -1
- package/dist/web-client/assets/{index--759FJd4.js → index-CpcOfuy-.js} +17 -16
- package/dist/web-client/assets/index-viCDtpt6.css +1 -0
- package/dist/web-client/index.html +2 -2
- package/package.json +1 -1
- package/dist/web-client/assets/index-DI3EO9qL.css +0 -1
package/dist/index.js
CHANGED
|
@@ -3683,6 +3683,14 @@ function ensureSpawnHelperPermissions() {
|
|
|
3683
3683
|
}
|
|
3684
3684
|
var PtyManager = class {
|
|
3685
3685
|
ptyProcess;
|
|
3686
|
+
_cols = 80;
|
|
3687
|
+
_rows = 24;
|
|
3688
|
+
get cols() {
|
|
3689
|
+
return this._cols;
|
|
3690
|
+
}
|
|
3691
|
+
get rows() {
|
|
3692
|
+
return this._rows;
|
|
3693
|
+
}
|
|
3686
3694
|
/** The process ID of the spawned PTY process. */
|
|
3687
3695
|
pid;
|
|
3688
3696
|
constructor(command, args) {
|
|
@@ -3725,6 +3733,8 @@ var PtyManager = class {
|
|
|
3725
3733
|
resize(cols, rows) {
|
|
3726
3734
|
try {
|
|
3727
3735
|
this.ptyProcess.resize(cols, rows);
|
|
3736
|
+
this._cols = cols;
|
|
3737
|
+
this._rows = rows;
|
|
3728
3738
|
} catch {
|
|
3729
3739
|
}
|
|
3730
3740
|
}
|
|
@@ -3929,7 +3939,7 @@ async function serveStaticFile(webClientPath, filePath, req, res) {
|
|
|
3929
3939
|
var PING_INTERVAL_MS = 3e4;
|
|
3930
3940
|
var SCROLLBACK_BUFFER_SIZE = 5e4;
|
|
3931
3941
|
function createSyncServer(options) {
|
|
3932
|
-
const { ptyManager, token, webClientPath, host, port } = options;
|
|
3942
|
+
const { ptyManager, token, webClientPath, host, port, localTerminalOwnsResize = false } = options;
|
|
3933
3943
|
const clients = /* @__PURE__ */ new Set();
|
|
3934
3944
|
const aliveMap = /* @__PURE__ */ new WeakMap();
|
|
3935
3945
|
let scrollbackBuffer = "";
|
|
@@ -3972,6 +3982,7 @@ function createSyncServer(options) {
|
|
|
3972
3982
|
if (scrollbackBuffer.length > 0) {
|
|
3973
3983
|
ws.send(JSON.stringify({ type: "data", data: scrollbackBuffer, seq }));
|
|
3974
3984
|
}
|
|
3985
|
+
ws.send(JSON.stringify({ type: "resize", cols: ptyManager.cols, rows: ptyManager.rows }));
|
|
3975
3986
|
ws.on("pong", () => {
|
|
3976
3987
|
aliveMap.set(ws, true);
|
|
3977
3988
|
});
|
|
@@ -3981,7 +3992,9 @@ function createSyncServer(options) {
|
|
|
3981
3992
|
if (message.type === "input" && typeof message.data === "string") {
|
|
3982
3993
|
ptyManager.write(message.data);
|
|
3983
3994
|
} else if (message.type === "resize" && typeof message.cols === "number" && typeof message.rows === "number") {
|
|
3984
|
-
|
|
3995
|
+
if (!localTerminalOwnsResize) {
|
|
3996
|
+
ptyManager.resize(message.cols, message.rows);
|
|
3997
|
+
}
|
|
3985
3998
|
} else if (message.type === "resume" && typeof message.lastSeq === "number") {
|
|
3986
3999
|
const missed = seq - message.lastSeq;
|
|
3987
4000
|
if (missed > 0 && scrollbackBuffer.length > 0) {
|
|
@@ -4024,6 +4037,14 @@ function createSyncServer(options) {
|
|
|
4024
4037
|
clients.clear();
|
|
4025
4038
|
wssServer.close();
|
|
4026
4039
|
httpServer.close();
|
|
4040
|
+
},
|
|
4041
|
+
broadcastResize(cols, rows) {
|
|
4042
|
+
const msg = JSON.stringify({ type: "resize", cols, rows });
|
|
4043
|
+
for (const client of clients) {
|
|
4044
|
+
if (client.readyState === client.OPEN) {
|
|
4045
|
+
client.send(msg);
|
|
4046
|
+
}
|
|
4047
|
+
}
|
|
4027
4048
|
}
|
|
4028
4049
|
};
|
|
4029
4050
|
}
|
|
@@ -4151,7 +4172,7 @@ async function runSetupWizard() {
|
|
|
4151
4172
|
|
|
4152
4173
|
// src/hub-client.ts
|
|
4153
4174
|
import { spawn as spawn2 } from "child_process";
|
|
4154
|
-
import { readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
|
|
4175
|
+
import { readFileSync as readFileSync2, existsSync as existsSync2, unlinkSync } from "fs";
|
|
4155
4176
|
import { homedir as homedir2 } from "os";
|
|
4156
4177
|
import { join as join4, dirname as dirname2 } from "path";
|
|
4157
4178
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
@@ -4198,13 +4219,70 @@ async function discoverHub() {
|
|
|
4198
4219
|
req.end();
|
|
4199
4220
|
});
|
|
4200
4221
|
}
|
|
4222
|
+
async function getHubPidFromHealth() {
|
|
4223
|
+
return new Promise((resolve) => {
|
|
4224
|
+
const req = request(
|
|
4225
|
+
{
|
|
4226
|
+
hostname: "127.0.0.1",
|
|
4227
|
+
port: HUB_INTERNAL_PORT,
|
|
4228
|
+
path: "/api/health",
|
|
4229
|
+
method: "GET",
|
|
4230
|
+
timeout: 2e3
|
|
4231
|
+
},
|
|
4232
|
+
(res) => {
|
|
4233
|
+
let data = "";
|
|
4234
|
+
res.on("data", (chunk) => {
|
|
4235
|
+
data += chunk;
|
|
4236
|
+
});
|
|
4237
|
+
res.on("end", () => {
|
|
4238
|
+
try {
|
|
4239
|
+
const json = JSON.parse(data);
|
|
4240
|
+
resolve(json.pid && typeof json.pid === "number" ? json.pid : null);
|
|
4241
|
+
} catch {
|
|
4242
|
+
resolve(null);
|
|
4243
|
+
}
|
|
4244
|
+
});
|
|
4245
|
+
}
|
|
4246
|
+
);
|
|
4247
|
+
req.on("error", () => resolve(null));
|
|
4248
|
+
req.on("timeout", () => {
|
|
4249
|
+
req.destroy();
|
|
4250
|
+
resolve(null);
|
|
4251
|
+
});
|
|
4252
|
+
req.end();
|
|
4253
|
+
});
|
|
4254
|
+
}
|
|
4255
|
+
async function killStaleHub() {
|
|
4256
|
+
const pid = await getHubPidFromHealth();
|
|
4257
|
+
if (!pid) return false;
|
|
4258
|
+
try {
|
|
4259
|
+
process.kill(pid, "SIGTERM");
|
|
4260
|
+
} catch {
|
|
4261
|
+
return false;
|
|
4262
|
+
}
|
|
4263
|
+
for (let i = 0; i < 20; i++) {
|
|
4264
|
+
await new Promise((r) => setTimeout(r, 200));
|
|
4265
|
+
const stillRunning = await discoverHub();
|
|
4266
|
+
if (!stillRunning) break;
|
|
4267
|
+
}
|
|
4268
|
+
const hubDir = getHubDir();
|
|
4269
|
+
try {
|
|
4270
|
+
unlinkSync(join4(hubDir, "hub.json"));
|
|
4271
|
+
} catch {
|
|
4272
|
+
}
|
|
4273
|
+
try {
|
|
4274
|
+
unlinkSync(join4(hubDir, "hub.pid"));
|
|
4275
|
+
} catch {
|
|
4276
|
+
}
|
|
4277
|
+
return true;
|
|
4278
|
+
}
|
|
4201
4279
|
async function spawnHub() {
|
|
4202
4280
|
const __dirname = dirname2(fileURLToPath2(import.meta.url));
|
|
4203
4281
|
const hubPath = join4(__dirname, "hub", "daemon.js");
|
|
4204
4282
|
return new Promise((resolve, reject) => {
|
|
4205
4283
|
const child = spawn2("node", [hubPath], {
|
|
4206
4284
|
detached: true,
|
|
4207
|
-
stdio: ["ignore", "pipe", "
|
|
4285
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
4208
4286
|
env: {
|
|
4209
4287
|
...process.env,
|
|
4210
4288
|
// Pass config dir to hub
|
|
@@ -4213,6 +4291,7 @@ async function spawnHub() {
|
|
|
4213
4291
|
});
|
|
4214
4292
|
child.unref();
|
|
4215
4293
|
let output = "";
|
|
4294
|
+
let stderrOutput = "";
|
|
4216
4295
|
const timeout = setTimeout(() => {
|
|
4217
4296
|
reject(new Error("Hub daemon startup timed out"));
|
|
4218
4297
|
}, 1e4);
|
|
@@ -4221,9 +4300,13 @@ async function spawnHub() {
|
|
|
4221
4300
|
if (output.includes("hub:ready:")) {
|
|
4222
4301
|
clearTimeout(timeout);
|
|
4223
4302
|
child.stdout?.destroy();
|
|
4303
|
+
child.stderr?.destroy();
|
|
4224
4304
|
resolve();
|
|
4225
4305
|
}
|
|
4226
4306
|
});
|
|
4307
|
+
child.stderr?.on("data", (data) => {
|
|
4308
|
+
stderrOutput += data.toString();
|
|
4309
|
+
});
|
|
4227
4310
|
child.on("error", (err) => {
|
|
4228
4311
|
clearTimeout(timeout);
|
|
4229
4312
|
reject(new Error(`Failed to spawn hub daemon: ${err.message}`));
|
|
@@ -4231,7 +4314,11 @@ async function spawnHub() {
|
|
|
4231
4314
|
child.on("exit", (code) => {
|
|
4232
4315
|
clearTimeout(timeout);
|
|
4233
4316
|
if (code !== null && code !== 0) {
|
|
4234
|
-
|
|
4317
|
+
const detail = stderrOutput.trim();
|
|
4318
|
+
reject(new Error(
|
|
4319
|
+
`Hub daemon exited with code ${code}${detail ? `:
|
|
4320
|
+
${detail}` : ""}`
|
|
4321
|
+
));
|
|
4235
4322
|
}
|
|
4236
4323
|
});
|
|
4237
4324
|
});
|
|
@@ -4343,11 +4430,19 @@ async function listSessions() {
|
|
|
4343
4430
|
req.end();
|
|
4344
4431
|
});
|
|
4345
4432
|
}
|
|
4346
|
-
function stopHub() {
|
|
4433
|
+
async function stopHub() {
|
|
4347
4434
|
const config = getHubConfig();
|
|
4348
|
-
if (
|
|
4435
|
+
if (config) {
|
|
4436
|
+
try {
|
|
4437
|
+
process.kill(config.pid, "SIGTERM");
|
|
4438
|
+
return true;
|
|
4439
|
+
} catch {
|
|
4440
|
+
}
|
|
4441
|
+
}
|
|
4442
|
+
const pid = await getHubPidFromHealth();
|
|
4443
|
+
if (!pid) return false;
|
|
4349
4444
|
try {
|
|
4350
|
-
process.kill(
|
|
4445
|
+
process.kill(pid, "SIGTERM");
|
|
4351
4446
|
return true;
|
|
4352
4447
|
} catch {
|
|
4353
4448
|
return false;
|
|
@@ -4516,11 +4611,15 @@ function preventSleep() {
|
|
|
4516
4611
|
async function ensureHub() {
|
|
4517
4612
|
const hubRunning = await discoverHub();
|
|
4518
4613
|
if (hubRunning) {
|
|
4519
|
-
|
|
4614
|
+
const config = getHubConfig();
|
|
4615
|
+
if (config) {
|
|
4616
|
+
return false;
|
|
4617
|
+
}
|
|
4618
|
+
console.warn(" Detected stale hub daemon (no config). Restarting...");
|
|
4619
|
+
await killStaleHub();
|
|
4520
4620
|
}
|
|
4521
4621
|
try {
|
|
4522
4622
|
await spawnHub();
|
|
4523
|
-
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
4524
4623
|
return true;
|
|
4525
4624
|
} catch (err) {
|
|
4526
4625
|
console.warn(`
|
|
@@ -4533,11 +4632,11 @@ async function handleHubCommand(options) {
|
|
|
4533
4632
|
const hubConfig = getHubConfig();
|
|
4534
4633
|
const hubRunning = await discoverHub();
|
|
4535
4634
|
if (options.hubStop) {
|
|
4536
|
-
if (!hubRunning
|
|
4635
|
+
if (!hubRunning) {
|
|
4537
4636
|
console.log("\n No hub daemon is running.\n");
|
|
4538
4637
|
return;
|
|
4539
4638
|
}
|
|
4540
|
-
const stopped = stopHub();
|
|
4639
|
+
const stopped = await stopHub();
|
|
4541
4640
|
if (stopped) {
|
|
4542
4641
|
console.log("\n Hub daemon stopped.\n");
|
|
4543
4642
|
} else {
|
|
@@ -4564,11 +4663,16 @@ async function handleHubCommand(options) {
|
|
|
4564
4663
|
return;
|
|
4565
4664
|
}
|
|
4566
4665
|
if (options.hubInfo) {
|
|
4567
|
-
if (!hubRunning
|
|
4666
|
+
if (!hubRunning) {
|
|
4568
4667
|
console.log("\n No hub daemon is running.");
|
|
4569
4668
|
console.log(" Start a session with: itwillsync -- <agent>\n");
|
|
4570
4669
|
return;
|
|
4571
4670
|
}
|
|
4671
|
+
if (!hubConfig) {
|
|
4672
|
+
console.log("\n Hub daemon is running but its config is missing (stale state).");
|
|
4673
|
+
console.log(" Run: itwillsync hub stop\n");
|
|
4674
|
+
return;
|
|
4675
|
+
}
|
|
4572
4676
|
let networkingMode = "local";
|
|
4573
4677
|
if (options.tailscale) {
|
|
4574
4678
|
networkingMode = "tailscale";
|
|
@@ -4639,7 +4743,8 @@ async function main() {
|
|
|
4639
4743
|
token,
|
|
4640
4744
|
webClientPath,
|
|
4641
4745
|
host,
|
|
4642
|
-
port
|
|
4746
|
+
port,
|
|
4747
|
+
localTerminalOwnsResize: true
|
|
4643
4748
|
});
|
|
4644
4749
|
let registeredSession = null;
|
|
4645
4750
|
let heartbeatInterval = null;
|
|
@@ -4698,6 +4803,7 @@ async function main() {
|
|
|
4698
4803
|
function handleResize() {
|
|
4699
4804
|
if (process.stdout.columns && process.stdout.rows) {
|
|
4700
4805
|
ptyManager.resize(process.stdout.columns, process.stdout.rows);
|
|
4806
|
+
server.broadcastResize(process.stdout.columns, process.stdout.rows);
|
|
4701
4807
|
}
|
|
4702
4808
|
}
|
|
4703
4809
|
process.stdout.on("resize", handleResize);
|