home-hosted 0.7.20 → 0.7.21
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/AGENTS.md
CHANGED
|
@@ -191,7 +191,9 @@ nobody reads is worse than a long file.
|
|
|
191
191
|
commit*. A stale doc is a bug like stale code.
|
|
192
192
|
- **UIs move together.** `uis/stock` is not the only client: a change to it — or to a shared contract
|
|
193
193
|
it reads — lands in every other UI under `uis/`, and each altered UI bumps its `ui.json` (see
|
|
194
|
-
[`.agentDocs/ARCHITECTURE.md`](.agentDocs/ARCHITECTURE.md)).
|
|
194
|
+
[`.agentDocs/ARCHITECTURE.md`](.agentDocs/ARCHITECTURE.md)). `src/shared/**` is a UI build input, so
|
|
195
|
+
a contract a UI *calls* at runtime ships in its bundle and needs the bump — the pre-commit hook only
|
|
196
|
+
inspects `uis/` paths and stays silent on that commit.
|
|
195
197
|
|
|
196
198
|
## Releasing
|
|
197
199
|
|
package/dist/cli.js
CHANGED
|
@@ -1077,7 +1077,14 @@ maxRssBytes: "number.integer >= 0 = 0" }).onUndeclaredKey("reject");
|
|
|
1077
1077
|
logBufferLines: logBufferLinesSchema.optional()
|
|
1078
1078
|
}).onUndeclaredKey("reject");
|
|
1079
1079
|
editableFields = {
|
|
1080
|
-
|
|
1080
|
+
/**
|
|
1081
|
+
* `null` clears it, the same spelling `serverSchema` accepts and every display's `label ?? id`
|
|
1082
|
+
* fallback needs — an empty string satisfies neither. `serverPatchSchema` is what the editor
|
|
1083
|
+
* validates its payload against and what `PATCH /api/servers/:id` checks, so without this a
|
|
1084
|
+
* cleared Label was refused with "label must be a string (was null)" and could not be saved at all
|
|
1085
|
+
* (`1f58a5d` fixed `applyPatch` and the *control* patch schema, and cited that one in its message).
|
|
1086
|
+
*/
|
|
1087
|
+
label: labelOrNullSchema.optional(),
|
|
1081
1088
|
enabled: "boolean?",
|
|
1082
1089
|
autostart: "boolean?",
|
|
1083
1090
|
persistent: "boolean?",
|
|
@@ -8336,6 +8343,7 @@ var init_proxy$1 = __esmMin((() => {
|
|
|
8336
8343
|
init_types();
|
|
8337
8344
|
init_nanny$2();
|
|
8338
8345
|
init_port();
|
|
8346
|
+
init_proc();
|
|
8339
8347
|
init_proxy$2();
|
|
8340
8348
|
init_proxy_config();
|
|
8341
8349
|
init_tls$1();
|
|
@@ -9731,7 +9739,9 @@ var init_proxy$1 = __esmMin((() => {
|
|
|
9731
9739
|
const statePath = nannyStatePath(this.options.stateDir, PROXY_ID);
|
|
9732
9740
|
const state = readNannyState(statePath);
|
|
9733
9741
|
if (state !== null && state.serverId === PROXY_ID) {
|
|
9734
|
-
const
|
|
9742
|
+
const nanny = await nannyIsAlive(state, PROXY_ID);
|
|
9743
|
+
const child = state.childPid !== null && state.childPid > 0 && await processCarriesServerId(state.childPid, PROXY_ID);
|
|
9744
|
+
const pids = [...nanny ? [state.nannyPid] : [], ...nanny || child ? [state.childPid] : []].filter((pid) => pid !== null && pid > 0);
|
|
9735
9745
|
for (const pid of pids) {
|
|
9736
9746
|
if (!isProcessAlive(pid)) continue;
|
|
9737
9747
|
try {
|
|
@@ -9742,10 +9752,12 @@ var init_proxy$1 = __esmMin((() => {
|
|
|
9742
9752
|
}
|
|
9743
9753
|
const deadline = Date.now() + (this.options.stopGraceMs ?? 1e4);
|
|
9744
9754
|
while (Date.now() < deadline && pids.some((pid) => isProcessAlive(pid))) await new Promise((resolve) => setTimeout(resolve, 100));
|
|
9745
|
-
|
|
9755
|
+
const survivors = pids.filter(isProcessAlive);
|
|
9756
|
+
for (const pid of survivors) try {
|
|
9746
9757
|
process.kill(pid, "SIGKILL");
|
|
9747
9758
|
} catch {}
|
|
9748
|
-
|
|
9759
|
+
if (survivors.some(isProcessAlive)) logger.warn(`proxy: pid ${survivors.join(", ")} ignored SIGKILL — keeping ${path.basename(statePath)} so a later boot can still stop it`);
|
|
9760
|
+
else fs.rmSync(statePath, { force: true });
|
|
9749
9761
|
}
|
|
9750
9762
|
this.nanny = null;
|
|
9751
9763
|
this.admin = null;
|
|
@@ -11962,28 +11974,24 @@ function signalPid(pid, signal, killGroup) {
|
|
|
11962
11974
|
process.kill(pid, signal);
|
|
11963
11975
|
} catch {}
|
|
11964
11976
|
}
|
|
11965
|
-
function alive(pid) {
|
|
11966
|
-
try {
|
|
11967
|
-
process.kill(pid, 0);
|
|
11968
|
-
return true;
|
|
11969
|
-
} catch {
|
|
11970
|
-
return false;
|
|
11971
|
-
}
|
|
11972
|
-
}
|
|
11973
11977
|
/**
|
|
11974
11978
|
* The same shutdown a supervised child gets, for a process we adopted instead of
|
|
11975
11979
|
* spawned: a detached successor is not our child, so it is signalled by pid (and
|
|
11976
11980
|
* by process group when asked) and its exit is polled rather than awaited.
|
|
11981
|
+
*
|
|
11982
|
+
* Liveness comes from `isProcessAlive`, never a local signal-0 copy: a second definition returned
|
|
11983
|
+
* `false` for `EPERM`, so a process that was there but not ours to signal read as "exited" and
|
|
11984
|
+
* `'force-killed'` was returned for one still running. One predicate, one answer.
|
|
11977
11985
|
*/
|
|
11978
11986
|
async function terminatePid(pid, options) {
|
|
11979
|
-
if (!
|
|
11987
|
+
if (!isProcessAlive(pid)) return "exited";
|
|
11980
11988
|
signalPid(pid, options.signal, options.killGroup);
|
|
11981
11989
|
const deadline = Date.now() + Math.max(0, options.graceMs);
|
|
11982
|
-
while (Date.now() < deadline &&
|
|
11983
|
-
if (!
|
|
11990
|
+
while (Date.now() < deadline && isProcessAlive(pid)) await delay$1(50);
|
|
11991
|
+
if (!isProcessAlive(pid)) return "exited";
|
|
11984
11992
|
signalPid(pid, "SIGKILL", options.killGroup);
|
|
11985
11993
|
const hardDeadline = Date.now() + 2e3;
|
|
11986
|
-
while (Date.now() < hardDeadline &&
|
|
11994
|
+
while (Date.now() < hardDeadline && isProcessAlive(pid)) await delay$1(50);
|
|
11987
11995
|
return "force-killed";
|
|
11988
11996
|
}
|
|
11989
11997
|
function delay$1(ms) {
|
|
@@ -12007,6 +12015,7 @@ function waitForExit$1(child, timeoutMs) {
|
|
|
12007
12015
|
var execFileAsync$1, WINDOWS_SHIM_EXTENSIONS;
|
|
12008
12016
|
var init_process = __esmMin((() => {
|
|
12009
12017
|
init_paths();
|
|
12018
|
+
init_port();
|
|
12010
12019
|
execFileAsync$1 = promisify(execFile);
|
|
12011
12020
|
WINDOWS_SHIM_EXTENSIONS = [
|
|
12012
12021
|
".cmd",
|
|
@@ -12823,6 +12832,7 @@ var init_supervisor = __esmMin((() => {
|
|
|
12823
12832
|
nannyExit: null,
|
|
12824
12833
|
starting: false,
|
|
12825
12834
|
stopping: false,
|
|
12835
|
+
removed: false,
|
|
12826
12836
|
bootstrapDone: !config.bootstrap,
|
|
12827
12837
|
logs: new LogBuffer(config.logBufferLines),
|
|
12828
12838
|
echoed: /* @__PURE__ */ new Set(),
|
|
@@ -12841,6 +12851,7 @@ var init_supervisor = __esmMin((() => {
|
|
|
12841
12851
|
this.relay.unfollow(id);
|
|
12842
12852
|
this.options.logFiles.clear(id);
|
|
12843
12853
|
this.options.history.forget(id);
|
|
12854
|
+
entry.removed = true;
|
|
12844
12855
|
this.stopEntry(entry).catch((error) => {
|
|
12845
12856
|
logger.error(`could not stop the removed server ${id}`, error);
|
|
12846
12857
|
});
|
|
@@ -13026,7 +13037,7 @@ var init_supervisor = __esmMin((() => {
|
|
|
13026
13037
|
entry.responseMs = null;
|
|
13027
13038
|
entry.exitCode = null;
|
|
13028
13039
|
entry.exitSignal = null;
|
|
13029
|
-
this.options.history.record(entry.config.id, {
|
|
13040
|
+
if (!entry.removed) this.options.history.record(entry.config.id, {
|
|
13030
13041
|
type: "exit",
|
|
13031
13042
|
detail,
|
|
13032
13043
|
runtimeMs: ranForMs
|
|
@@ -13425,7 +13436,7 @@ var init_supervisor = __esmMin((() => {
|
|
|
13425
13436
|
at: Date.now()
|
|
13426
13437
|
});
|
|
13427
13438
|
const ranForMs = nannyExit?.runtimeMs ?? (entry.startedAt === null ? 0 : Date.now() - entry.startedAt);
|
|
13428
|
-
this.options.history.record(entry.config.id, {
|
|
13439
|
+
if (!entry.removed) this.options.history.record(entry.config.id, {
|
|
13429
13440
|
type: "exit",
|
|
13430
13441
|
detail,
|
|
13431
13442
|
runtimeMs: ranForMs
|
|
@@ -13616,6 +13627,10 @@ var init_supervisor = __esmMin((() => {
|
|
|
13616
13627
|
};
|
|
13617
13628
|
}
|
|
13618
13629
|
log(entry, stream, text) {
|
|
13630
|
+
if (entry.removed) {
|
|
13631
|
+
logger.debug(`[${entry.config.id}] ${text}`);
|
|
13632
|
+
return;
|
|
13633
|
+
}
|
|
13619
13634
|
const line = {
|
|
13620
13635
|
ts: Date.now(),
|
|
13621
13636
|
stream,
|
|
@@ -15695,6 +15710,7 @@ var init_log_files = __esmMin((() => {
|
|
|
15695
15710
|
return lines.slice(-tail);
|
|
15696
15711
|
}
|
|
15697
15712
|
clear(serverId) {
|
|
15713
|
+
this.pending.delete(serverId);
|
|
15698
15714
|
for (const file of this.rotateTargets(serverId)) try {
|
|
15699
15715
|
fs.rmSync(file, { force: true });
|
|
15700
15716
|
} catch {}
|