@songsid/agend 2.1.11-beta.2 → 2.1.11-beta.4

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.
@@ -0,0 +1,34 @@
1
+ import type { HostMemory } from "./host-memory.js";
2
+ export declare const DARWIN_MEMORY_DEADLINE_MS = 2000;
3
+ export declare const DARWIN_MEMORY_CACHE_MS = 30000;
4
+ export declare function unknownDarwinMemory(totalBytes: number): HostMemory;
5
+ /** vm_stat's printed free count excludes speculative pages. Purgeable can overlap inactive. */
6
+ export declare function parseDarwinAvailable(text: string, totalBytes: number): number | null;
7
+ /** sysctl prints binary MiB to two decimals, including the valid unallocated 0/0 pool. */
8
+ export declare function parseDarwinSwap(text: string): Pick<HostMemory, "swapTotalBytes" | "swapFreeBytes">;
9
+ export interface MemoryCommand {
10
+ result: Promise<string | null>;
11
+ /** Physical child close, independent of logical timeout/result. */
12
+ stopped: Promise<void>;
13
+ kill(): void;
14
+ }
15
+ export type MemoryCommandRunner = (file: string, args: string[]) => MemoryCommand;
16
+ export declare const runMemoryCommand: MemoryCommandRunner;
17
+ interface Options {
18
+ run?: MemoryCommandRunner;
19
+ totalmem?: () => number;
20
+ now?: () => number;
21
+ }
22
+ /** One bounded logical read and at most one physical pair, even across stop/restart. */
23
+ export declare class DarwinMemoryProbe {
24
+ private readonly run;
25
+ private readonly total;
26
+ private readonly now;
27
+ private flight;
28
+ private cache;
29
+ private epoch;
30
+ constructor(options?: Options);
31
+ read(): Promise<HostMemory>;
32
+ stop(): void;
33
+ }
34
+ export {};
@@ -0,0 +1,160 @@
1
+ import { execFile } from "node:child_process";
2
+ import { totalmem } from "node:os";
3
+ export const DARWIN_MEMORY_DEADLINE_MS = 2_000;
4
+ export const DARWIN_MEMORY_CACHE_MS = 30_000;
5
+ const MAX_OUTPUT = 32 * 1024;
6
+ export function unknownDarwinMemory(totalBytes) {
7
+ return { totalBytes, availableBytes: null, availableKind: "unknown", swapTotalBytes: null, swapFreeBytes: null };
8
+ }
9
+ /** vm_stat's printed free count excludes speculative pages. Purgeable can overlap inactive. */
10
+ export function parseDarwinAvailable(text, totalBytes) {
11
+ const headers = [...text.matchAll(/^Mach Virtual Memory Statistics: \(page size of (\d+) bytes\)\s*$/gm)];
12
+ if (headers.length !== 1 || [...text.matchAll(/^Mach Virtual Memory Statistics:/gm)].length !== 1)
13
+ return null;
14
+ const pageSize = Number(headers[0][1]);
15
+ if (!Number.isSafeInteger(pageSize) || pageSize < 1024 || pageSize > 1024 * 1024 || Math.log2(pageSize) % 1 !== 0)
16
+ return null;
17
+ const counts = [];
18
+ for (const name of ["free", "speculative", "inactive", "purgeable"]) {
19
+ const rows = [...text.matchAll(new RegExp(`^Pages ${name}:\\s+(\\d+)\\.\\s*$`, "gm"))];
20
+ if (rows.length !== 1 || [...text.matchAll(new RegExp(`^Pages ${name}:`, "gm"))].length !== 1)
21
+ return null;
22
+ const count = Number(rows[0][1]);
23
+ if (!Number.isSafeInteger(count) || count < 0)
24
+ return null;
25
+ counts.push(count);
26
+ }
27
+ const [free, speculative, inactive, purgeable] = counts;
28
+ const bytes = (free + speculative + Math.max(inactive, purgeable)) * pageSize;
29
+ return Number.isSafeInteger(bytes) && Number.isFinite(totalBytes) && totalBytes > 0 && bytes <= totalBytes ? bytes : null;
30
+ }
31
+ /** sysctl prints binary MiB to two decimals, including the valid unallocated 0/0 pool. */
32
+ export function parseDarwinSwap(text) {
33
+ const unknown = { swapTotalBytes: null, swapFreeBytes: null };
34
+ const rows = [...text.matchAll(/^vm\.swapusage:\s+total = (\d+(?:\.\d+)?)M\s+used = (\d+(?:\.\d+)?)M\s+free = (\d+(?:\.\d+)?)M\s*(?:\(encrypted\))?\s*$/gm)];
35
+ if (rows.length !== 1)
36
+ return unknown;
37
+ const [total, used, free] = rows[0].slice(1).map(Number);
38
+ if (![total, used, free].every(Number.isFinite) || free > total || used > total || Math.abs(total - used - free) > 0.02)
39
+ return unknown;
40
+ const totalBytes = Math.round(total * 1024 ** 2), freeBytes = Math.round(free * 1024 ** 2);
41
+ if (!Number.isSafeInteger(totalBytes) || !Number.isSafeInteger(freeBytes))
42
+ return unknown;
43
+ return { swapTotalBytes: totalBytes, swapFreeBytes: freeBytes };
44
+ }
45
+ export const runMemoryCommand = (file, args) => {
46
+ let resolveResult;
47
+ let resolveStopped;
48
+ const result = new Promise(resolve => { resolveResult = resolve; });
49
+ const stopped = new Promise(resolve => { resolveStopped = resolve; });
50
+ try {
51
+ const child = execFile(file, args, {
52
+ encoding: "utf8", env: { ...process.env, LC_ALL: "C", LANG: "C" },
53
+ timeout: 1_500, killSignal: "SIGKILL", maxBuffer: MAX_OUTPUT,
54
+ }, (error, stdout) => resolveResult(error ? null : stdout));
55
+ child.once("close", resolveStopped);
56
+ // A spawn error normally also emits close. Keep the physical reservation until then.
57
+ child.once("error", () => resolveResult(null));
58
+ return { result, stopped, kill: () => { try {
59
+ child.kill("SIGKILL");
60
+ }
61
+ catch { /* wait for close */ } } };
62
+ }
63
+ catch {
64
+ resolveResult(null);
65
+ resolveStopped();
66
+ return { result, stopped, kill: () => { } };
67
+ }
68
+ };
69
+ /** One bounded logical read and at most one physical pair, even across stop/restart. */
70
+ export class DarwinMemoryProbe {
71
+ run;
72
+ total;
73
+ now;
74
+ flight = null;
75
+ cache = null;
76
+ epoch = 0;
77
+ constructor(options = {}) {
78
+ this.run = options.run ?? runMemoryCommand;
79
+ this.total = options.totalmem ?? totalmem;
80
+ this.now = options.now ?? (() => performance.now());
81
+ }
82
+ read() {
83
+ if (this.cache && this.now() - this.cache.at < DARWIN_MEMORY_CACHE_MS)
84
+ return Promise.resolve({ ...this.cache.memory });
85
+ // A timed-out or cancelled pair still owns its physical reservation.
86
+ if (this.flight) {
87
+ const flight = this.flight;
88
+ if (flight.completed)
89
+ return Promise.resolve(unknownDarwinMemory(this.total()));
90
+ return flight.result.then(value => flight.epoch === this.epoch ? { ...value } : unknownDarwinMemory(this.total()));
91
+ }
92
+ const epoch = ++this.epoch, totalBytes = this.total(), deadlineAt = this.now() + DARWIN_MEMORY_DEADLINE_MS;
93
+ const unknown = unknownDarwinMemory(totalBytes);
94
+ const commands = [];
95
+ let settle;
96
+ let completed = false;
97
+ let timer = null;
98
+ const result = new Promise(resolve => { settle = resolve; });
99
+ const finish = (value) => {
100
+ if (completed)
101
+ return;
102
+ completed = true;
103
+ flight.completed = true;
104
+ if (timer)
105
+ clearTimeout(timer);
106
+ if (epoch === this.epoch)
107
+ this.cache = { at: this.now(), memory: { ...value } };
108
+ settle(value);
109
+ };
110
+ const cancel = () => {
111
+ finish(unknown);
112
+ for (const command of commands) {
113
+ try {
114
+ command.kill();
115
+ }
116
+ catch { /* retain until close */ }
117
+ }
118
+ };
119
+ const flight = { completed: false, epoch, result, cancel };
120
+ this.flight = flight;
121
+ // Start the deadline before either constructor; a slow constructor cannot earn extra time.
122
+ timer = setTimeout(cancel, DARWIN_MEMORY_DEADLINE_MS);
123
+ timer.unref?.();
124
+ for (const [file, args] of [["/usr/bin/vm_stat", []], ["/usr/sbin/sysctl", ["vm.swapusage"]]]) {
125
+ if (this.now() >= deadlineAt) {
126
+ cancel();
127
+ break;
128
+ }
129
+ try {
130
+ commands.push(this.run(file, [...args]));
131
+ }
132
+ catch {
133
+ commands.push({ result: Promise.resolve(null), stopped: Promise.resolve(), kill: () => { } });
134
+ }
135
+ }
136
+ void Promise.all(commands.map(command => command.result.catch(() => null))).then(outputs => {
137
+ if (completed)
138
+ return;
139
+ if (epoch !== this.epoch || this.now() >= deadlineAt) {
140
+ cancel();
141
+ return;
142
+ }
143
+ const available = outputs[0] === null || outputs[0] === undefined ? null : parseDarwinAvailable(outputs[0], totalBytes);
144
+ finish(available === null ? unknown : { totalBytes, availableBytes: available, availableKind: "available",
145
+ ...parseDarwinSwap(outputs[1] ?? "") });
146
+ });
147
+ // Never release on kill request/result alone. Rejected cleanup remains reserved.
148
+ void Promise.all(commands.map(command => command.stopped.catch(() => new Promise(() => { })))).then(() => {
149
+ if (this.flight === flight)
150
+ this.flight = null;
151
+ });
152
+ return result.then(value => ({ ...value }));
153
+ }
154
+ stop() {
155
+ this.epoch++;
156
+ this.cache = null;
157
+ this.flight?.cancel();
158
+ }
159
+ }
160
+ //# sourceMappingURL=darwin-memory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"darwin-memory.js","sourceRoot":"","sources":["../src/darwin-memory.ts"],"names":[],"mappings":"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"}
@@ -63,6 +63,7 @@ import { LoginSession } from "./login-manager.js";
63
63
  import { tightenInstanceDirs } from "./private-dir.js";
64
64
  import { decideSlash } from "./slash-authz.js";
65
65
  import { commandSpec, decideCommand } from "./command-table.js";
66
+ import { UPDATE_COMMAND, isPrereleaseVersion, updateNoticeKey } from "./update-check.js";
66
67
  import { LoginController, LOGIN_TOKEN_RESEND_PREFIX, POST_LOGIN_RECOVERY_DEADLINE_MS } from "./login-controller.js";
67
68
  import { runBeforeDeadline } from "./deadline.js";
68
69
  import { LoginWindowLock } from "./login-window-lock.js";
@@ -987,6 +988,10 @@ export class FleetManager {
987
988
  this.logger.debug({ hostMemory: snapshot }, "Host memory sample");
988
989
  }
989
990
  const changed = snapshot.level !== this.memoryLogLevel;
991
+ if (this.memoryPressure.allowsUnknown(snapshot)) {
992
+ this.memoryLogLevel = snapshot.level;
993
+ return;
994
+ }
990
995
  if (snapshot.level === "normal") {
991
996
  if (this.memoryLogLevel === "critical" || this.memoryLogLevel === "elevated") {
992
997
  this.logger.info({ hostMemory: snapshot }, "Host memory recovered");
@@ -1492,8 +1497,10 @@ export class FleetManager {
1492
1497
  this.beginUpdateProgress(adapter, chatId, data.channelId, messageId);
1493
1498
  }
1494
1499
  const { spawn } = await import("node:child_process");
1495
- const currentVersion = JSON.parse(readFileSync(join(dirname(fileURLToPath(import.meta.url)), "..", "package.json"), "utf-8")).version ?? "";
1496
- const command = currentVersion.includes("beta") ? "agend update --beta" : "agend update";
1500
+ // Plain `agend update`: the CLI picks the channel from the version it is about to replace (a beta install
1501
+ // stays on beta). Deciding here, from the package.json next to THIS code, read a source checkout's 1.22.0 as
1502
+ // "not a beta" and sent a beta install to @latest.
1503
+ const command = UPDATE_COMMAND;
1497
1504
  const origin = `slash /update by ${adapterId}:${data.userId}`;
1498
1505
  recordInternalRequest(this.dataDir, "update", origin);
1499
1506
  const child = spawn("sh", ["-c", `sleep 2 && ${command}`], {
@@ -13961,7 +13968,8 @@ Plus the operational skills (fleet-health, instance-lifecycle, scheduling, sessi
13961
13968
  const currentVersion = JSON.parse(readFileSync(pkgPath, "utf-8")).version ?? "0.0.0";
13962
13969
  const latest = await npmVersion("@songsid/agend");
13963
13970
  let target = latest;
13964
- if (currentVersion.includes("-beta")) {
13971
+ // The same channel rule as `agend update` (any SemVer prerelease is on @beta): rc and alpha too.
13972
+ if (isPrereleaseVersion(currentVersion)) {
13965
13973
  // Beta users track the @beta channel (never fall back to @latest, which is
13966
13974
  // older), but should also hear when a newer STABLE ships — pick whichever
13967
13975
  // of beta/latest is the newest.
@@ -13981,7 +13989,7 @@ Plus the operational skills (fleet-health, instance-lifecycle, scheduling, sessi
13981
13989
  // only that same-core stable-vs-my-beta case; a higher stable core (2.0.12)
13982
13990
  // or a newer beta (2.0.11-beta.50) still notifies via semverGt below.
13983
13991
  const core = (v) => v.replace(/^v/, "").split("-")[0];
13984
- const betaSupersedesStable = currentVersion.includes("-") && !target.includes("-") && core(target) === core(currentVersion);
13992
+ const betaSupersedesStable = isPrereleaseVersion(currentVersion) && !isPrereleaseVersion(target) && core(target) === core(currentVersion);
13985
13993
  // Only notify when target is genuinely newer (semver), so a beta user on
13986
13994
  // 2.0.8-beta.16 is never told that stable 2.0.7 is "available".
13987
13995
  if (target && !betaSupersedesStable && this.semverGt(target, currentVersion)) {
@@ -13989,7 +13997,7 @@ Plus the operational skills (fleet-health, instance-lifecycle, scheduling, sessi
13989
13997
  if (generalId) {
13990
13998
  // No release URL — Discord's SuppressEmbeds proved unreliable and the
13991
13999
  // link preview looked bad. Version + /update instruction is enough.
13992
- this.notifyInstanceTopic(generalId, t("update.available_current", `v${target}`, `v${currentVersion}`));
14000
+ this.notifyInstanceTopic(generalId, t(updateNoticeKey(currentVersion, target), `v${target}`, `v${currentVersion}`));
13993
14001
  }
13994
14002
  }
13995
14003
  }