@kdonev/termscape 0.1.9 → 0.2.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/README.md +25 -0
- package/dist/cli-args.d.ts +10 -0
- package/dist/cli-args.d.ts.map +1 -1
- package/dist/cli-args.js +2 -0
- package/dist/cli-args.js.map +1 -1
- package/dist/cli.js +15 -258
- package/dist/cli.js.map +1 -1
- package/dist/hub.d.ts +28 -1
- package/dist/hub.d.ts.map +1 -1
- package/dist/hub.js +65 -2
- package/dist/hub.js.map +1 -1
- package/dist/hub.tgz +0 -0
- package/dist/main.d.ts +7 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +343 -0
- package/dist/main.js.map +1 -0
- package/dist/protocol/domain.d.ts +35 -0
- package/dist/protocol/domain.d.ts.map +1 -1
- package/dist/protocol/domain.js +31 -2
- package/dist/protocol/domain.js.map +1 -1
- package/dist/protocol/index.d.ts +1 -0
- package/dist/protocol/index.d.ts.map +1 -1
- package/dist/protocol/index.js +1 -0
- package/dist/protocol/index.js.map +1 -1
- package/dist/protocol/peer.d.ts +12 -0
- package/dist/protocol/peer.d.ts.map +1 -1
- package/dist/protocol/peer.js +30 -1
- package/dist/protocol/peer.js.map +1 -1
- package/dist/protocol/version.d.ts +12 -0
- package/dist/protocol/version.d.ts.map +1 -0
- package/dist/protocol/version.js +37 -0
- package/dist/protocol/version.js.map +1 -0
- package/dist/protocol/ws.d.ts +67 -1
- package/dist/protocol/ws.d.ts.map +1 -1
- package/dist/protocol/ws.js +11 -1
- package/dist/protocol/ws.js.map +1 -1
- package/dist/remote/enroll.d.ts.map +1 -1
- package/dist/remote/enroll.js +22 -1
- package/dist/remote/enroll.js.map +1 -1
- package/dist/remote/join.d.ts.map +1 -1
- package/dist/remote/join.js +10 -1
- package/dist/remote/join.js.map +1 -1
- package/dist/remote/peer-serve.d.ts.map +1 -1
- package/dist/remote/peer-serve.js +14 -0
- package/dist/remote/peer-serve.js.map +1 -1
- package/dist/remote/peer.d.ts +7 -0
- package/dist/remote/peer.d.ts.map +1 -1
- package/dist/remote/peer.js +25 -1
- package/dist/remote/peer.js.map +1 -1
- package/dist/remote/registry.d.ts +24 -2
- package/dist/remote/registry.d.ts.map +1 -1
- package/dist/remote/registry.js +76 -5
- package/dist/remote/registry.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +11 -1
- package/dist/server.js.map +1 -1
- package/dist/supervisor.d.ts +44 -0
- package/dist/supervisor.d.ts.map +1 -0
- package/dist/supervisor.js +125 -0
- package/dist/supervisor.js.map +1 -0
- package/dist/update/host.d.ts +19 -0
- package/dist/update/host.d.ts.map +1 -0
- package/dist/update/host.js +56 -0
- package/dist/update/host.js.map +1 -0
- package/dist/update/install.d.ts +38 -0
- package/dist/update/install.d.ts.map +1 -0
- package/dist/update/install.js +81 -0
- package/dist/update/install.js.map +1 -0
- package/dist/update/post-install.d.ts +2 -0
- package/dist/update/post-install.d.ts.map +1 -0
- package/dist/update/post-install.js +39 -0
- package/dist/update/post-install.js.map +1 -0
- package/dist/update/restart.d.ts +31 -0
- package/dist/update/restart.d.ts.map +1 -0
- package/dist/update/restart.js +65 -0
- package/dist/update/restart.js.map +1 -0
- package/dist/update/resume.d.ts +5 -0
- package/dist/update/resume.d.ts.map +1 -0
- package/dist/update/resume.js +47 -0
- package/dist/update/resume.js.map +1 -0
- package/dist/update/updater.d.ts +57 -0
- package/dist/update/updater.d.ts.map +1 -0
- package/dist/update/updater.js +190 -0
- package/dist/update/updater.js.map +1 -0
- package/package.json +1 -1
- package/web/assets/{index-i7fXLKF0.js → index-BoqmaIyh.js} +9 -9
- package/web/assets/index-Czi_vAR-.css +1 -0
- package/web/index.html +2 -2
- package/web/assets/index-gfbbNQK4.css +0 -1
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { type ChildProcess } from 'node:child_process';
|
|
2
|
+
import { type RestartPlan } from './update/restart.js';
|
|
3
|
+
/**
|
|
4
|
+
* The process a terminal actually holds, when the hub can update itself.
|
|
5
|
+
*
|
|
6
|
+
* An update replaces the hub, and the hub cannot restart itself: the new one
|
|
7
|
+
* needs the old one's port, so the old one has to be gone first. Something
|
|
8
|
+
* has to outlive it, and this is that thing. It does nothing but run the hub
|
|
9
|
+
* as a child with the terminal passed straight through, and start whatever
|
|
10
|
+
* the hub left in its restart plan when it exits with EXIT_RESTART - so the
|
|
11
|
+
* terminal stays attached, logs keep printing, and Ctrl+C still stops it.
|
|
12
|
+
*
|
|
13
|
+
* It must stay this small. It never loads the hub, and so never loads a
|
|
14
|
+
* native module: on Windows a loaded .node cannot be replaced, and a global
|
|
15
|
+
* update has to replace exactly those files while this is still running.
|
|
16
|
+
*/
|
|
17
|
+
type Values = {
|
|
18
|
+
headless?: boolean;
|
|
19
|
+
join?: string;
|
|
20
|
+
version?: boolean;
|
|
21
|
+
help?: boolean;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Only an installed copy of the published package is supervised: that is the
|
|
25
|
+
* only kind that can update itself. A checkout, a joined machine (updated
|
|
26
|
+
* from its canvas, by an installer that expects to find the hub in hub.pid)
|
|
27
|
+
* and a headless hub all run exactly as before.
|
|
28
|
+
*/
|
|
29
|
+
export declare function shouldSupervise(values: Values, cliPath: string, env?: NodeJS.ProcessEnv): boolean;
|
|
30
|
+
/** Tell the supervisor, if there is one, that this hub is exiting and how. */
|
|
31
|
+
export declare function announceExit(code: number): Promise<void>;
|
|
32
|
+
/** Run the hub, and every hub an update asks for after it, until one exits for good. */
|
|
33
|
+
export declare function supervise(cliPath: string): Promise<never>;
|
|
34
|
+
/**
|
|
35
|
+
* The loop itself: start a hub, and when it exits asking to be restarted,
|
|
36
|
+
* start what it left in its restart plan. Resolves with the exit code of the
|
|
37
|
+
* first hub that exits for any other reason.
|
|
38
|
+
*/
|
|
39
|
+
export declare function runHubs(first: RestartPlan, opts?: {
|
|
40
|
+
stdio?: Array<'ignore' | 'inherit' | 'pipe'>;
|
|
41
|
+
onChild?: (child: ChildProcess | null) => void;
|
|
42
|
+
}): Promise<number>;
|
|
43
|
+
export {};
|
|
44
|
+
//# sourceMappingURL=supervisor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"supervisor.d.ts","sourceRoot":"","sources":["../src/supervisor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAiC,KAAK,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAGtF;;;;;;;;;;;;;GAaG;AAEH,KAAK,MAAM,GAAG;IACZ,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,OAAO,CAIT;AAuBD,8EAA8E;AAC9E,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAWxD;AAED,wFAAwF;AACxF,wBAAsB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAiB/D;AAED;;;;GAIG;AACH,wBAAsB,OAAO,CAC3B,KAAK,EAAE,WAAW,EAClB,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,KAAK,CAAC,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,KAAK,IAAI,CAAA;CAAO,GAC1G,OAAO,CAAC,MAAM,CAAC,CAmDjB"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { EXIT_RESTART, takeRestartPlan } from './update/restart.js';
|
|
3
|
+
import { isInstalledPackage } from './update/install.js';
|
|
4
|
+
/**
|
|
5
|
+
* Only an installed copy of the published package is supervised: that is the
|
|
6
|
+
* only kind that can update itself. A checkout, a joined machine (updated
|
|
7
|
+
* from its canvas, by an installer that expects to find the hub in hub.pid)
|
|
8
|
+
* and a headless hub all run exactly as before.
|
|
9
|
+
*/
|
|
10
|
+
export function shouldSupervise(values, cliPath, env = process.env) {
|
|
11
|
+
if (env.TERMSCAPE_SUPERVISED === '1' || env.TERMSCAPE_NO_SUPERVISOR === '1')
|
|
12
|
+
return false;
|
|
13
|
+
if (values.version || values.help || values.headless || values.join)
|
|
14
|
+
return false;
|
|
15
|
+
return isInstalledPackage(cliPath);
|
|
16
|
+
}
|
|
17
|
+
/** How long a hub that said it is exiting gets to actually be gone. */
|
|
18
|
+
const EXIT_GRACE_MS = 5_000;
|
|
19
|
+
/**
|
|
20
|
+
* Stop a hub that is stuck on its way out, and anything it still holds. On
|
|
21
|
+
* Windows only taskkill reaches the whole tree; its agents' terminals were
|
|
22
|
+
* closed already, but a straggler would keep the new hub's files busy.
|
|
23
|
+
*/
|
|
24
|
+
function killTree(child) {
|
|
25
|
+
if (child.pid === undefined || child.exitCode !== null)
|
|
26
|
+
return;
|
|
27
|
+
console.error('[termscape] the hub did not exit; stopping it');
|
|
28
|
+
if (process.platform === 'win32') {
|
|
29
|
+
spawn('taskkill', ['/pid', String(child.pid), '/t', '/f'], {
|
|
30
|
+
stdio: 'ignore',
|
|
31
|
+
windowsHide: true,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
child.kill('SIGKILL');
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/** Tell the supervisor, if there is one, that this hub is exiting and how. */
|
|
39
|
+
export function announceExit(code) {
|
|
40
|
+
const send = process.send?.bind(process);
|
|
41
|
+
if (!send || !process.connected)
|
|
42
|
+
return Promise.resolve();
|
|
43
|
+
return new Promise((resolve) => {
|
|
44
|
+
// A supervisor that went away must not hold this exit up.
|
|
45
|
+
const timer = setTimeout(resolve, 500);
|
|
46
|
+
send({ t: 'exiting', code }, undefined, {}, () => {
|
|
47
|
+
clearTimeout(timer);
|
|
48
|
+
resolve();
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
/** Run the hub, and every hub an update asks for after it, until one exits for good. */
|
|
53
|
+
export async function supervise(cliPath) {
|
|
54
|
+
let child = null;
|
|
55
|
+
// Ctrl+C reaches every process on the terminal, the hub included, and the
|
|
56
|
+
// hub is the one that decides what stopping means. This only waits for it.
|
|
57
|
+
process.on('SIGINT', () => { });
|
|
58
|
+
for (const sig of ['SIGTERM', 'SIGHUP']) {
|
|
59
|
+
process.on(sig, () => {
|
|
60
|
+
if (child)
|
|
61
|
+
child.kill(sig);
|
|
62
|
+
else
|
|
63
|
+
process.exit(1);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
const code = await runHubs({ command: process.execPath, args: [...process.execArgv, cliPath, ...process.argv.slice(2)] }, { onChild: (c) => (child = c) });
|
|
67
|
+
process.exit(code);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* The loop itself: start a hub, and when it exits asking to be restarted,
|
|
71
|
+
* start what it left in its restart plan. Resolves with the exit code of the
|
|
72
|
+
* first hub that exits for any other reason.
|
|
73
|
+
*/
|
|
74
|
+
export async function runHubs(first, opts = {}) {
|
|
75
|
+
// Anything left over from a restart that never happened is not ours to run.
|
|
76
|
+
takeRestartPlan();
|
|
77
|
+
const [stdin, stdout, stderr] = opts.stdio ?? ['inherit', 'inherit', 'inherit'];
|
|
78
|
+
let plan = first;
|
|
79
|
+
for (;;) {
|
|
80
|
+
const started = spawn(plan.command, plan.args, {
|
|
81
|
+
// The extra channel is how a hub says it is on its way out; see below.
|
|
82
|
+
stdio: [stdin, stdout, stderr, 'ipc'],
|
|
83
|
+
env: { ...process.env, ...plan.env, TERMSCAPE_SUPERVISED: '1' },
|
|
84
|
+
});
|
|
85
|
+
opts.onChild?.(started);
|
|
86
|
+
const code = await new Promise((resolve) => {
|
|
87
|
+
/*
|
|
88
|
+
* A hub announces its exit, and its code, before calling process.exit -
|
|
89
|
+
* because on Windows that call has been seen to never return once an
|
|
90
|
+
* agent's terminal had been open, leaving a process with its state
|
|
91
|
+
* saved and its port closed that nothing would ever restart. Past the
|
|
92
|
+
* grace period it is killed here, and its announced code stands.
|
|
93
|
+
*/
|
|
94
|
+
let announced = null;
|
|
95
|
+
let watchdog = null;
|
|
96
|
+
started.on('message', (msg) => {
|
|
97
|
+
const m = msg;
|
|
98
|
+
if (m?.t !== 'exiting' || typeof m.code !== 'number' || watchdog)
|
|
99
|
+
return;
|
|
100
|
+
announced = m.code;
|
|
101
|
+
watchdog = setTimeout(() => killTree(started), EXIT_GRACE_MS);
|
|
102
|
+
});
|
|
103
|
+
started.on('error', (err) => {
|
|
104
|
+
console.error(`[termscape] could not start the hub: ${err.message}`);
|
|
105
|
+
resolve(1);
|
|
106
|
+
});
|
|
107
|
+
started.on('exit', (c, signal) => {
|
|
108
|
+
if (watchdog)
|
|
109
|
+
clearTimeout(watchdog);
|
|
110
|
+
resolve(announced ?? c ?? (signal ? 1 : 0));
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
opts.onChild?.(null);
|
|
114
|
+
if (code !== EXIT_RESTART)
|
|
115
|
+
return code;
|
|
116
|
+
const next = takeRestartPlan();
|
|
117
|
+
if (!next) {
|
|
118
|
+
console.error('[termscape] the hub asked to be restarted but left no plan; stopping');
|
|
119
|
+
return 1;
|
|
120
|
+
}
|
|
121
|
+
console.log('\n[termscape] restarting\n');
|
|
122
|
+
plan = next;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=supervisor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"supervisor.js","sourceRoot":"","sources":["../src/supervisor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Update a machine joined to a canvas, to the build that canvas runs.
|
|
3
|
+
*
|
|
4
|
+
* It runs the canvas's own join installer again, which already knows how to
|
|
5
|
+
* do every part of this - stop the hub that is running (this one), swap the
|
|
6
|
+
* install while keeping the dependency tree where it can, start the new hub
|
|
7
|
+
* and wait for it to rejoin. The installer carries a fresh join key, but the
|
|
8
|
+
* host token already on disk is tried first, so this machine comes back as
|
|
9
|
+
* itself rather than as a second machine.
|
|
10
|
+
*
|
|
11
|
+
* The installer is started detached, because it outlives this process by
|
|
12
|
+
* design: the first thing it does is stop it. Its output goes to
|
|
13
|
+
* update.log beside the hub's own, which is the one place to look when a
|
|
14
|
+
* machine was told to update and never came back.
|
|
15
|
+
*
|
|
16
|
+
* Resolves once the installer is fetched and running.
|
|
17
|
+
*/
|
|
18
|
+
export declare function runHostUpdate(hubUrl: string, platform?: NodeJS.Platform): Promise<void>;
|
|
19
|
+
//# sourceMappingURL=host.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../../src/update/host.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAC3C,OAAO,CAAC,IAAI,CAAC,CAiCf"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { closeSync, openSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { paths } from '../paths.js';
|
|
5
|
+
/**
|
|
6
|
+
* Update a machine joined to a canvas, to the build that canvas runs.
|
|
7
|
+
*
|
|
8
|
+
* It runs the canvas's own join installer again, which already knows how to
|
|
9
|
+
* do every part of this - stop the hub that is running (this one), swap the
|
|
10
|
+
* install while keeping the dependency tree where it can, start the new hub
|
|
11
|
+
* and wait for it to rejoin. The installer carries a fresh join key, but the
|
|
12
|
+
* host token already on disk is tried first, so this machine comes back as
|
|
13
|
+
* itself rather than as a second machine.
|
|
14
|
+
*
|
|
15
|
+
* The installer is started detached, because it outlives this process by
|
|
16
|
+
* design: the first thing it does is stop it. Its output goes to
|
|
17
|
+
* update.log beside the hub's own, which is the one place to look when a
|
|
18
|
+
* machine was told to update and never came back.
|
|
19
|
+
*
|
|
20
|
+
* Resolves once the installer is fetched and running.
|
|
21
|
+
*/
|
|
22
|
+
export async function runHostUpdate(hubUrl, platform = process.platform) {
|
|
23
|
+
const windows = platform === 'win32';
|
|
24
|
+
const origin = new URL(hubUrl).origin;
|
|
25
|
+
const res = await fetch(`${origin}/${windows ? 'join.ps1' : 'join.sh'}`, {
|
|
26
|
+
signal: AbortSignal.timeout(30_000),
|
|
27
|
+
});
|
|
28
|
+
if (!res.ok)
|
|
29
|
+
throw new Error(`the canvas answered ${res.status} for its installer`);
|
|
30
|
+
const script = await res.text();
|
|
31
|
+
const home = paths.home();
|
|
32
|
+
const file = join(home, windows ? 'update.ps1' : 'update.sh');
|
|
33
|
+
writeFileSync(file, script, { mode: 0o700 });
|
|
34
|
+
const log = openSync(join(home, 'update.log'), 'w');
|
|
35
|
+
try {
|
|
36
|
+
const [command, args] = windows
|
|
37
|
+
? ['powershell.exe', ['-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Bypass', '-File', file]]
|
|
38
|
+
: ['sh', [file]];
|
|
39
|
+
const child = spawn(command, args, {
|
|
40
|
+
detached: true,
|
|
41
|
+
windowsHide: true,
|
|
42
|
+
stdio: ['ignore', log, log],
|
|
43
|
+
// The installer reads TERMSCAPE_HOME to find the install it replaces.
|
|
44
|
+
env: { ...process.env, TERMSCAPE_HOME: home },
|
|
45
|
+
});
|
|
46
|
+
await new Promise((resolve, reject) => {
|
|
47
|
+
child.once('spawn', () => resolve());
|
|
48
|
+
child.once('error', reject);
|
|
49
|
+
});
|
|
50
|
+
child.unref();
|
|
51
|
+
}
|
|
52
|
+
finally {
|
|
53
|
+
closeSync(log);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=host.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host.js","sourceRoot":"","sources":["../../src/update/host.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEpC;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,MAAc,EACd,WAA4B,OAAO,CAAC,QAAQ;IAE5C,MAAM,OAAO,GAAG,QAAQ,KAAK,OAAO,CAAC;IACrC,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC;IACtC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,EAAE,EAAE;QACvE,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC;KACpC,CAAC,CAAC;IACH,IAAI,CAAC,GAAG,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,GAAG,CAAC,MAAM,oBAAoB,CAAC,CAAC;IACpF,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;IAEhC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;IAC9D,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAE7C,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,EAAE,GAAG,CAAC,CAAC;IACpD,IAAI,CAAC;QACH,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,OAAO;YAC7B,CAAC,CAAC,CAAC,gBAAgB,EAAE,CAAC,YAAY,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;YACpG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;QACnB,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE;YACjC,QAAQ,EAAE,IAAI;YACd,WAAW,EAAE,IAAI;YACjB,KAAK,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,GAAG,CAAC;YAC3B,sEAAsE;YACtE,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE;SAC9C,CAAC,CAAC;QACH,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC1C,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;YACrC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC9B,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,KAAK,EAAE,CAAC;IAChB,CAAC;YAAS,CAAC;QACT,SAAS,CAAC,GAAG,CAAC,CAAC;IACjB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { InstallKind } from '../protocol/index.js';
|
|
2
|
+
/** What the package is called on the registry. */
|
|
3
|
+
export declare const PACKAGE_NAME = "@kdonev/termscape";
|
|
4
|
+
/**
|
|
5
|
+
* Whether this file sits inside an installed copy of the published package,
|
|
6
|
+
* as opposed to a checkout. The one thing the supervisor needs to know, and it
|
|
7
|
+
* is decided from the path alone because the supervisor must not spend a
|
|
8
|
+
* second asking npm before the hub has even started.
|
|
9
|
+
*/
|
|
10
|
+
export declare function isInstalledPackage(cliPath: string): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* How this hub came to be running, which is how it can replace itself.
|
|
13
|
+
*
|
|
14
|
+
* A global install is told apart from a copy inside somebody's project by
|
|
15
|
+
* the shim npm puts beside it: `<prefix>/termscape.cmd` on Windows,
|
|
16
|
+
* `<prefix>/bin/termscape` beside `<prefix>/lib/node_modules` elsewhere. The
|
|
17
|
+
* project copy cannot be updated by `npm install -g`, which would install a
|
|
18
|
+
* second copy nothing runs.
|
|
19
|
+
*
|
|
20
|
+
* Read off the disk rather than asked of `npm root -g`, whose answer npm
|
|
21
|
+
* redacts: a path segment that looks like a token, a UUID say, comes back as
|
|
22
|
+
* `***` and then matches nothing.
|
|
23
|
+
*/
|
|
24
|
+
export declare function installKind(cliPath: string, opts: {
|
|
25
|
+
joined: boolean;
|
|
26
|
+
exists?: (p: string) => boolean;
|
|
27
|
+
platform?: NodeJS.Platform;
|
|
28
|
+
}): InstallKind;
|
|
29
|
+
/**
|
|
30
|
+
* npm's own entry point, run with this Node rather than through `npm` on the
|
|
31
|
+
* PATH: on Windows that is npm.cmd, which cannot be spawned without a shell,
|
|
32
|
+
* and a shell drags its quoting rules into every argument. Null when npm is
|
|
33
|
+
* not where Node's own distribution puts it.
|
|
34
|
+
*/
|
|
35
|
+
export declare function npmCliPath(nodeExe?: string): string | null;
|
|
36
|
+
/** Run npm and collect its stdout. Rejects with its output on a non-zero exit. */
|
|
37
|
+
export declare function runNpm(args: string[], timeoutMs?: number): Promise<string>;
|
|
38
|
+
//# sourceMappingURL=install.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../src/update/install.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,kDAAkD;AAClD,eAAO,MAAM,YAAY,sBAAsB,CAAC;AAQhD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAE3D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAA;CAAE,GACrF,WAAW,CAeb;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,OAAO,SAAmB,GAAG,MAAM,GAAG,IAAI,CAOpE;AAED,kFAAkF;AAClF,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,SAAS,SAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAoB9E"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { dirname, join, posix } from 'node:path';
|
|
4
|
+
/** What the package is called on the registry. */
|
|
5
|
+
export const PACKAGE_NAME = '@kdonev/termscape';
|
|
6
|
+
/** A path compared the same way on every platform. */
|
|
7
|
+
function norm(p) {
|
|
8
|
+
const slashed = p.replace(/\\/g, '/');
|
|
9
|
+
return process.platform === 'win32' ? slashed.toLowerCase() : slashed;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Whether this file sits inside an installed copy of the published package,
|
|
13
|
+
* as opposed to a checkout. The one thing the supervisor needs to know, and it
|
|
14
|
+
* is decided from the path alone because the supervisor must not spend a
|
|
15
|
+
* second asking npm before the hub has even started.
|
|
16
|
+
*/
|
|
17
|
+
export function isInstalledPackage(cliPath) {
|
|
18
|
+
return norm(cliPath).includes(`/node_modules/${PACKAGE_NAME}/`);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* How this hub came to be running, which is how it can replace itself.
|
|
22
|
+
*
|
|
23
|
+
* A global install is told apart from a copy inside somebody's project by
|
|
24
|
+
* the shim npm puts beside it: `<prefix>/termscape.cmd` on Windows,
|
|
25
|
+
* `<prefix>/bin/termscape` beside `<prefix>/lib/node_modules` elsewhere. The
|
|
26
|
+
* project copy cannot be updated by `npm install -g`, which would install a
|
|
27
|
+
* second copy nothing runs.
|
|
28
|
+
*
|
|
29
|
+
* Read off the disk rather than asked of `npm root -g`, whose answer npm
|
|
30
|
+
* redacts: a path segment that looks like a token, a UUID say, comes back as
|
|
31
|
+
* `***` and then matches nothing.
|
|
32
|
+
*/
|
|
33
|
+
export function installKind(cliPath, opts) {
|
|
34
|
+
if (opts.joined)
|
|
35
|
+
return 'host';
|
|
36
|
+
if (!isInstalledPackage(cliPath))
|
|
37
|
+
return 'source';
|
|
38
|
+
if (norm(cliPath).includes('/_npx/'))
|
|
39
|
+
return 'npx';
|
|
40
|
+
const exists = opts.exists ?? existsSync;
|
|
41
|
+
const slashed = cliPath.replace(/\\/g, '/');
|
|
42
|
+
const at = slashed.toLowerCase().lastIndexOf(`/node_modules/${PACKAGE_NAME}/`);
|
|
43
|
+
const modules = slashed.slice(0, at + '/node_modules'.length);
|
|
44
|
+
const prefix = posix.dirname(modules);
|
|
45
|
+
const global = (opts.platform ?? process.platform) === 'win32'
|
|
46
|
+
? exists(`${prefix}/termscape.cmd`)
|
|
47
|
+
: posix.basename(prefix) === 'lib' && exists(`${posix.dirname(prefix)}/bin/termscape`);
|
|
48
|
+
return global ? 'global' : 'source';
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* npm's own entry point, run with this Node rather than through `npm` on the
|
|
52
|
+
* PATH: on Windows that is npm.cmd, which cannot be spawned without a shell,
|
|
53
|
+
* and a shell drags its quoting rules into every argument. Null when npm is
|
|
54
|
+
* not where Node's own distribution puts it.
|
|
55
|
+
*/
|
|
56
|
+
export function npmCliPath(nodeExe = process.execPath) {
|
|
57
|
+
const dir = dirname(nodeExe);
|
|
58
|
+
const candidates = [
|
|
59
|
+
join(dir, 'node_modules', 'npm', 'bin', 'npm-cli.js'), // Windows layout
|
|
60
|
+
join(dir, '..', 'lib', 'node_modules', 'npm', 'bin', 'npm-cli.js'), // POSIX layout
|
|
61
|
+
];
|
|
62
|
+
return candidates.find((p) => existsSync(p)) ?? null;
|
|
63
|
+
}
|
|
64
|
+
/** Run npm and collect its stdout. Rejects with its output on a non-zero exit. */
|
|
65
|
+
export function runNpm(args, timeoutMs = 5 * 60_000) {
|
|
66
|
+
const cli = npmCliPath();
|
|
67
|
+
const [cmd, argv, shell] = cli
|
|
68
|
+
? [process.execPath, [cli, ...args], false]
|
|
69
|
+
: ['npm', args, process.platform === 'win32'];
|
|
70
|
+
return new Promise((resolve, reject) => {
|
|
71
|
+
execFile(cmd, argv, { timeout: timeoutMs, shell, windowsHide: true, maxBuffer: 16 * 1024 * 1024 }, (err, stdout, stderr) => {
|
|
72
|
+
if (err) {
|
|
73
|
+
const detail = `${stderr}`.trim().split('\n').slice(-5).join('\n');
|
|
74
|
+
reject(new Error(`npm ${args[0]} failed: ${detail || err.message}`));
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
resolve(`${stdout}`);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=install.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../src/update/install.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"post-install.d.ts","sourceRoot":"","sources":["../../src/update/post-install.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The step between a hub and its update, for a global install.
|
|
3
|
+
*
|
|
4
|
+
* Started by the supervisor once the old hub has exited - by then nothing
|
|
5
|
+
* holds the package's native modules open, which is what lets Windows replace
|
|
6
|
+
* them. It installs the release, then exits with EXIT_RESTART and a plan to
|
|
7
|
+
* start the hub from the same place it always ran from. If the install fails,
|
|
8
|
+
* the plan starts the old hub again instead, carrying the error so the canvas
|
|
9
|
+
* can say what happened rather than simply not having updated.
|
|
10
|
+
*
|
|
11
|
+
* node post-install.js <version> <cli.js> [hub args...]
|
|
12
|
+
*/
|
|
13
|
+
import { spawnSync } from 'node:child_process';
|
|
14
|
+
import { EXIT_RESTART, writeRestartPlan } from './restart.js';
|
|
15
|
+
import { PACKAGE_NAME, npmCliPath } from './install.js';
|
|
16
|
+
const [version, cliPath, ...args] = process.argv.slice(2);
|
|
17
|
+
if (!version || !cliPath) {
|
|
18
|
+
console.error('usage: post-install.js <version> <cli.js> [hub args...]');
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
const spec = `${PACKAGE_NAME}@${version}`;
|
|
22
|
+
console.log(`[termscape] installing ${spec}`);
|
|
23
|
+
const npm = npmCliPath();
|
|
24
|
+
const npmArgs = ['install', '-g', '--no-audit', '--no-fund', spec];
|
|
25
|
+
const result = npm
|
|
26
|
+
? spawnSync(process.execPath, [npm, ...npmArgs], { stdio: 'inherit' })
|
|
27
|
+
: spawnSync('npm', npmArgs, { stdio: 'inherit', shell: process.platform === 'win32' });
|
|
28
|
+
const failed = result.error?.message ??
|
|
29
|
+
(result.status === 0 ? null : `npm install -g exited with ${result.status}`);
|
|
30
|
+
if (failed) {
|
|
31
|
+
console.error(`[termscape] update failed: ${failed}; starting the version already installed`);
|
|
32
|
+
}
|
|
33
|
+
writeRestartPlan({
|
|
34
|
+
command: process.execPath,
|
|
35
|
+
args: [cliPath, ...args],
|
|
36
|
+
...(failed ? { env: { TERMSCAPE_UPDATE_ERROR: `could not install ${spec}: ${failed}` } } : {}),
|
|
37
|
+
});
|
|
38
|
+
process.exit(EXIT_RESTART);
|
|
39
|
+
//# sourceMappingURL=post-install.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"post-install.js","sourceRoot":"","sources":["../../src/update/post-install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAExD,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC1D,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC;IACzB,OAAO,CAAC,KAAK,CAAC,yDAAyD,CAAC,CAAC;IACzE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,IAAI,GAAG,GAAG,YAAY,IAAI,OAAO,EAAE,CAAC;AAC1C,OAAO,CAAC,GAAG,CAAC,0BAA0B,IAAI,EAAE,CAAC,CAAC;AAC9C,MAAM,GAAG,GAAG,UAAU,EAAE,CAAC;AACzB,MAAM,OAAO,GAAG,CAAC,SAAS,EAAE,IAAI,EAAE,YAAY,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC;AACnE,MAAM,MAAM,GAAG,GAAG;IAChB,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;IACtE,CAAC,CAAC,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC,CAAC;AAEzF,MAAM,MAAM,GACV,MAAM,CAAC,KAAK,EAAE,OAAO;IACrB,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,8BAA8B,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;AAC/E,IAAI,MAAM,EAAE,CAAC;IACX,OAAO,CAAC,KAAK,CAAC,8BAA8B,MAAM,0CAA0C,CAAC,CAAC;AAChG,CAAC;AAED,gBAAgB,CAAC;IACf,OAAO,EAAE,OAAO,CAAC,QAAQ;IACzB,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC;IACxB,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,sBAAsB,EAAE,qBAAqB,IAAI,KAAK,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;CAC/F,CAAC,CAAC;AACH,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The exit code a supervised hub uses to say "start me again, as the restart
|
|
3
|
+
* plan says". 75 is EX_TEMPFAIL: nothing else in the hub exits with it.
|
|
4
|
+
*/
|
|
5
|
+
export declare const EXIT_RESTART = 75;
|
|
6
|
+
/** What the supervisor runs next, written by the hub on its way out. */
|
|
7
|
+
export interface RestartPlan {
|
|
8
|
+
command: string;
|
|
9
|
+
args: string[];
|
|
10
|
+
env?: Record<string, string>;
|
|
11
|
+
}
|
|
12
|
+
export declare function restartFile(): string;
|
|
13
|
+
export declare function writeRestartPlan(plan: RestartPlan): void;
|
|
14
|
+
/** Read and remove the plan, so a stale one can never start anything twice. */
|
|
15
|
+
export declare function takeRestartPlan(): RestartPlan | null;
|
|
16
|
+
/**
|
|
17
|
+
* The command line the updated hub starts with: the one this hub was given,
|
|
18
|
+
* pinned to the port and token it actually ended up with.
|
|
19
|
+
*
|
|
20
|
+
* Pinned because a canvas already open - in the app window about to be
|
|
21
|
+
* replaced, in a browser tab, on a phone - holds a URL with both in it, and
|
|
22
|
+
* reconnects to that URL on its own if the new hub is where the old one was.
|
|
23
|
+
* A browser tab needs no second tab opened beside it, so `--browser` becomes
|
|
24
|
+
* `--no-open` too; the app window closes with the hub that owned it and the
|
|
25
|
+
* new hub opens its own.
|
|
26
|
+
*/
|
|
27
|
+
export declare function restartArgs(argv: readonly string[], pin: {
|
|
28
|
+
port: number;
|
|
29
|
+
token: string;
|
|
30
|
+
}): string[];
|
|
31
|
+
//# sourceMappingURL=restart.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"restart.d.ts","sourceRoot":"","sources":["../../src/update/restart.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,eAAO,MAAM,YAAY,KAAK,CAAC;AAE/B,wEAAwE;AACxE,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAED,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,CAExD;AAED,+EAA+E;AAC/E,wBAAgB,eAAe,IAAI,WAAW,GAAG,IAAI,CAgBpD;AAID;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,GAAG,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,EAAE,CAcnG"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { paths } from '../paths.js';
|
|
4
|
+
/**
|
|
5
|
+
* The exit code a supervised hub uses to say "start me again, as the restart
|
|
6
|
+
* plan says". 75 is EX_TEMPFAIL: nothing else in the hub exits with it.
|
|
7
|
+
*/
|
|
8
|
+
export const EXIT_RESTART = 75;
|
|
9
|
+
export function restartFile() {
|
|
10
|
+
return join(paths.home(), 'restart.json');
|
|
11
|
+
}
|
|
12
|
+
export function writeRestartPlan(plan) {
|
|
13
|
+
writeFileSync(restartFile(), JSON.stringify(plan));
|
|
14
|
+
}
|
|
15
|
+
/** Read and remove the plan, so a stale one can never start anything twice. */
|
|
16
|
+
export function takeRestartPlan() {
|
|
17
|
+
const file = restartFile();
|
|
18
|
+
let raw;
|
|
19
|
+
try {
|
|
20
|
+
raw = readFileSync(file, 'utf8');
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
rmSync(file, { force: true });
|
|
26
|
+
try {
|
|
27
|
+
const plan = JSON.parse(raw);
|
|
28
|
+
if (typeof plan.command !== 'string' || !Array.isArray(plan.args))
|
|
29
|
+
return null;
|
|
30
|
+
return plan;
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const PINNED = ['--port', '--token'];
|
|
37
|
+
/**
|
|
38
|
+
* The command line the updated hub starts with: the one this hub was given,
|
|
39
|
+
* pinned to the port and token it actually ended up with.
|
|
40
|
+
*
|
|
41
|
+
* Pinned because a canvas already open - in the app window about to be
|
|
42
|
+
* replaced, in a browser tab, on a phone - holds a URL with both in it, and
|
|
43
|
+
* reconnects to that URL on its own if the new hub is where the old one was.
|
|
44
|
+
* A browser tab needs no second tab opened beside it, so `--browser` becomes
|
|
45
|
+
* `--no-open` too; the app window closes with the hub that owned it and the
|
|
46
|
+
* new hub opens its own.
|
|
47
|
+
*/
|
|
48
|
+
export function restartArgs(argv, pin) {
|
|
49
|
+
const out = [];
|
|
50
|
+
for (let i = 0; i < argv.length; i++) {
|
|
51
|
+
const arg = argv[i];
|
|
52
|
+
const name = arg.split('=')[0];
|
|
53
|
+
if (PINNED.includes(name)) {
|
|
54
|
+
if (!arg.includes('='))
|
|
55
|
+
i++; // `--port 7777`: skip the value too
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
out.push(arg);
|
|
59
|
+
}
|
|
60
|
+
if (out.includes('--browser') && !out.includes('--no-open'))
|
|
61
|
+
out.push('--no-open');
|
|
62
|
+
out.push(`--port=${pin.port}`, `--token=${pin.token}`);
|
|
63
|
+
return out;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=restart.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"restart.js","sourceRoot":"","sources":["../../src/update/restart.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC9D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEpC;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,EAAE,CAAC;AAS/B,MAAM,UAAU,WAAW;IACzB,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,cAAc,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAAiB;IAChD,aAAa,CAAC,WAAW,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;AACrD,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,eAAe;IAC7B,MAAM,IAAI,GAAG,WAAW,EAAE,CAAC;IAC3B,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9B,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAgB,CAAC;QAC5C,IAAI,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QAC/E,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,MAAM,GAAG,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;AAErC;;;;;;;;;;GAUG;AACH,MAAM,UAAU,WAAW,CAAC,IAAuB,EAAE,GAAoC;IACvF,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;QACrB,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;QAChC,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1B,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC;gBAAE,CAAC,EAAE,CAAC,CAAC,oCAAoC;YACjE,SAAS;QACX,CAAC;QACD,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAChB,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC;QAAE,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACnF,GAAG,CAAC,IAAI,CAAC,UAAU,GAAG,CAAC,IAAI,EAAE,EAAE,WAAW,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;IACvD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function resumeFile(): string;
|
|
2
|
+
export declare function saveResumeList(sessionIds: string[], now?: number): void;
|
|
3
|
+
/** Read and remove the list, so it is acted on once. Empty when stale or absent. */
|
|
4
|
+
export declare function takeResumeList(now?: number): string[];
|
|
5
|
+
//# sourceMappingURL=resume.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resume.d.ts","sourceRoot":"","sources":["../../src/update/resume.ts"],"names":[],"mappings":"AAwBA,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,GAAG,SAAa,GAAG,IAAI,CAG3E;AAED,oFAAoF;AACpF,wBAAgB,cAAc,CAAC,GAAG,SAAa,GAAG,MAAM,EAAE,CAkBzD"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { paths } from '../paths.js';
|
|
4
|
+
/**
|
|
5
|
+
* Which agents were running when a hub went down to be updated, so the hub
|
|
6
|
+
* that replaces it can bring exactly those back.
|
|
7
|
+
*
|
|
8
|
+
* Only an update writes this. Stopping a hub by hand is a decision about the
|
|
9
|
+
* agents too, and those come back stopped, as they always have.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* An update that never finished - an installer that failed, a machine that
|
|
13
|
+
* went to sleep halfway - must not resume agents at some unrelated start
|
|
14
|
+
* days later.
|
|
15
|
+
*/
|
|
16
|
+
const MAX_AGE_MS = 30 * 60_000;
|
|
17
|
+
export function resumeFile() {
|
|
18
|
+
return join(paths.home(), 'resume.json');
|
|
19
|
+
}
|
|
20
|
+
export function saveResumeList(sessionIds, now = Date.now()) {
|
|
21
|
+
const list = { at: now, sessionIds };
|
|
22
|
+
writeFileSync(resumeFile(), JSON.stringify(list));
|
|
23
|
+
}
|
|
24
|
+
/** Read and remove the list, so it is acted on once. Empty when stale or absent. */
|
|
25
|
+
export function takeResumeList(now = Date.now()) {
|
|
26
|
+
const file = resumeFile();
|
|
27
|
+
let raw;
|
|
28
|
+
try {
|
|
29
|
+
raw = readFileSync(file, 'utf8');
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return [];
|
|
33
|
+
}
|
|
34
|
+
rmSync(file, { force: true });
|
|
35
|
+
try {
|
|
36
|
+
const list = JSON.parse(raw);
|
|
37
|
+
if (typeof list.at !== 'number' || now - list.at > MAX_AGE_MS)
|
|
38
|
+
return [];
|
|
39
|
+
return Array.isArray(list.sessionIds)
|
|
40
|
+
? list.sessionIds.filter((id) => typeof id === 'string')
|
|
41
|
+
: [];
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=resume.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resume.js","sourceRoot":"","sources":["../../src/update/resume.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC9D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEpC;;;;;;GAMG;AAEH;;;;GAIG;AACH,MAAM,UAAU,GAAG,EAAE,GAAG,MAAM,CAAC;AAO/B,MAAM,UAAU,UAAU;IACxB,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,aAAa,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,UAAoB,EAAE,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IACnE,MAAM,IAAI,GAAe,EAAE,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC;IACjD,aAAa,CAAC,UAAU,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;AACpD,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,cAAc,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IAC7C,MAAM,IAAI,GAAG,UAAU,EAAE,CAAC;IAC1B,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9B,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAwB,CAAC;QACpD,IAAI,OAAO,IAAI,CAAC,EAAE,KAAK,QAAQ,IAAI,GAAG,GAAG,IAAI,CAAC,EAAE,GAAG,UAAU;YAAE,OAAO,EAAE,CAAC;QACzE,OAAO,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC;YACnC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,EAAE,EAAgB,EAAE,CAAC,OAAO,EAAE,KAAK,QAAQ,CAAC;YACtE,CAAC,CAAC,EAAE,CAAC;IACT,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC"}
|