glimmervoid 0.37.0 → 0.38.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.
Files changed (36) hide show
  1. package/dist/bin/glimmervoid.js +14 -14
  2. package/dist/chunks/{adapters-BmfVPxlH.js → adapters-B-IkWl-r.js} +19 -4
  3. package/dist/chunks/{adapters-CqFFmM2R.js → adapters-Dt3vwxwY.js} +1 -1
  4. package/dist/chunks/{agent-api-cli-BTHEyJKS.js → agent-api-cli-3hryuewm.js} +1 -1
  5. package/dist/chunks/{agent-api-cli-CBgOKXoO.js → agent-api-cli-BcZ9DLCF.js} +3 -3
  6. package/dist/chunks/{agent-api-core-DzKhakCv.js → agent-api-core--8WtU1xU.js} +3 -12
  7. package/dist/chunks/{agent-setup-cli-C8DGxlA-.js → agent-setup-cli-BixDoCkF.js} +2 -2
  8. package/dist/chunks/{config-BYc2z1Oc.js → config-BHBZsCBc.js} +9 -8
  9. package/dist/chunks/config-store-DYj3wYgw.js +1 -0
  10. package/dist/chunks/{config-store-B7MpiYxG.js → config-store-DbfMbz4j.js} +41 -64
  11. package/dist/chunks/{contracts-C6ipN_zw.js → contracts-u40eJhaf.js} +20 -14
  12. package/dist/chunks/{git-version-6QFnKbWa.js → git-version-BpnTd8sU.js} +1 -1
  13. package/dist/chunks/{grok-CZ6kP_vD.js → grok-xFs6zIu4.js} +1 -1
  14. package/dist/chunks/{json-file-BaxGcB2R.js → json-file-CIJf0Cel.js} +190 -9
  15. package/dist/chunks/{knowledge-graph-cli-DApeMzA8.js → knowledge-graph-cli-DcspNqhz.js} +1 -1
  16. package/dist/chunks/{loopback-post-DJ6iYWuL.js → loopback-post-DZK7YibD.js} +1 -1
  17. package/dist/chunks/{main-BUfjroXE.js → main-w01-P1oZ.js} +1048 -440
  18. package/dist/chunks/{pair-cli-GZ9t1mIO.js → pair-cli-BdoyrDCr.js} +2 -2
  19. package/dist/chunks/{remote-config-D2Is89Kj.js → remote-config-61zJ0hME.js} +2 -2
  20. package/dist/chunks/{session-BZbariv5.js → session-8Pv0y1vz.js} +1 -1
  21. package/dist/chunks/{session-routes-C4t8O8yg.js → session-routes-D-GZC-Sy.js} +1 -1
  22. package/dist/chunks/{settings-cli-DQOjmjev.js → settings-cli-DKJsm3AP.js} +3 -3
  23. package/dist/chunks/{ssh-sign-cli-LIBP8ppO.js → ssh-sign-cli-Dc2gOCwE.js} +2 -2
  24. package/dist/client/assets/index-BfqmOGgc.js +275 -0
  25. package/dist/client/assets/index-DxABp5yJ.css +1 -0
  26. package/dist/client/index.html +10 -3
  27. package/dist/server/index.js +1 -1
  28. package/dist/session/command-hook-relay.js +1 -1
  29. package/dist/session/hook-relay.js +1 -1
  30. package/dist/session/statusline-relay.js +1 -1
  31. package/dist/session/visions-relay.js +7 -7
  32. package/package.json +1 -1
  33. package/scripts/recover-handoff.mjs +1 -1
  34. package/dist/chunks/config-store-CsUoy88Q.js +0 -1
  35. package/dist/client/assets/index-B_Qt7fbZ.css +0 -1
  36. package/dist/client/assets/index-D-upBor0.js +0 -265
@@ -3,11 +3,60 @@ import { r as nextBackoffMs } from "./backoff-DjVpfHk7.js";
3
3
  import fs from "node:fs";
4
4
  import path from "node:path";
5
5
  import crypto from "node:crypto";
6
+ //#region server/core/memory-admission-core.ts
7
+ var BYTES_PER_MEGABYTE$1 = 1048576;
8
+ var MEMORY_RECHECK_MS = 5e3;
9
+ var MEMORY_RESERVATION_SETTLE_MS = 3e4;
10
+ var DEFAULT_CHECK_MEMORY_RESERVE_MB = 1500;
11
+ function memoryReserveBytes(config, kind) {
12
+ return (kind === "session" ? config.sessionMemoryReserveMB ?? 600 : config.checkMemoryReserveMB ?? 1500) * BYTES_PER_MEGABYTE$1;
13
+ }
14
+ function parseCgroupV2Path(procSelfCgroupText) {
15
+ const unifiedLine = procSelfCgroupText.split("\n").find((line) => line.startsWith("0::"));
16
+ if (unifiedLine === void 0) return null;
17
+ const cgroupPath = unifiedLine.slice(3).trim();
18
+ return cgroupPath.startsWith("/") ? cgroupPath : null;
19
+ }
20
+ function cgroupAncestorPaths(cgroupPath) {
21
+ const segments = cgroupPath.split("/").filter((segment) => segment.length > 0);
22
+ return segments.map((_segment, depthFromLeaf) => `/${segments.slice(0, segments.length - depthFromLeaf).join("/")}`);
23
+ }
24
+ function parseCgroupBytes(text) {
25
+ if (text === null) return null;
26
+ const trimmed = text.trim();
27
+ return /^\d+$/.test(trimmed) ? Number(trimmed) : null;
28
+ }
29
+ function cgroupLimitBytes(memoryHighText, memoryMaxText) {
30
+ return parseCgroupBytes(memoryHighText) ?? parseCgroupBytes(memoryMaxText);
31
+ }
32
+ function parseMemAvailableBytes(meminfoText) {
33
+ const match = /^MemAvailable:\s+(\d+)\s+kB$/m.exec(meminfoText);
34
+ return match ? Number(match[1]) * 1024 : null;
35
+ }
36
+ function headroomFromReadings({ cgroupLevels, hostAvailableBytes }) {
37
+ const candidates = cgroupLevels.flatMap(({ limitBytes, currentBytes }) => limitBytes === null || currentBytes === null ? [] : [Math.max(0, limitBytes - currentBytes)]);
38
+ if (hostAvailableBytes !== null) candidates.push(hostAvailableBytes);
39
+ return candidates.length === 0 ? null : Math.min(...candidates);
40
+ }
41
+ function liveReservations(reservations, nowMs) {
42
+ return reservations.filter((reservation) => nowMs - reservation.admittedAtMs < MEMORY_RESERVATION_SETTLE_MS);
43
+ }
44
+ function shouldAdmitStart({ reading, reserveBytes, reservations, nowMs }) {
45
+ if (!reading.ok) return true;
46
+ const reservedBytes = liveReservations(reservations, nowMs).reduce((total, reservation) => total + reservation.bytes, 0);
47
+ return reading.headroomBytes - reservedBytes >= reserveBytes;
48
+ }
49
+ //#endregion
6
50
  //#region server/spawn-gate.ts
51
+ var BYTES_PER_MEGABYTE = 1048576;
7
52
  var QUEUE_ADMISSION_TIMED_OUT = "serial-queue-admission-timed-out";
53
+ var QUEUE_ADMISSION_ABANDONED = "serial-queue-admission-abandoned";
8
54
  function isQueueAdmissionTimeout(error) {
9
55
  return error instanceof Error && error.message === QUEUE_ADMISSION_TIMED_OUT;
10
56
  }
57
+ function isQueueAdmissionAbandoned(error) {
58
+ return error instanceof Error && error.message === QUEUE_ADMISSION_ABANDONED;
59
+ }
11
60
  function createSerialQueue() {
12
61
  let tail = Promise.resolve();
13
62
  function run(fn, options = {}) {
@@ -19,19 +68,27 @@ function createSerialQueue() {
19
68
  return fn();
20
69
  });
21
70
  tail = result.then(() => void 0, () => void 0);
22
- const admissionTimeoutMs = options.admissionTimeoutMs;
23
- if (admissionTimeoutMs === void 0) return result;
71
+ const { admissionTimeoutMs, signal } = options;
72
+ if (admissionTimeoutMs === void 0 && signal === void 0) return result;
24
73
  return new Promise((resolve, reject) => {
25
- const admissionTimer = setTimeout(() => {
74
+ const leaveUnlessStarted = (reason) => {
26
75
  if (started) return;
27
76
  abandoned = true;
28
- reject(/* @__PURE__ */ new Error(QUEUE_ADMISSION_TIMED_OUT));
29
- }, admissionTimeoutMs);
30
- result.then((value) => {
77
+ reject(new Error(reason));
78
+ };
79
+ const admissionTimer = admissionTimeoutMs === void 0 ? void 0 : setTimeout(() => leaveUnlessStarted(QUEUE_ADMISSION_TIMED_OUT), admissionTimeoutMs);
80
+ const leaveOnAbort = () => leaveUnlessStarted(QUEUE_ADMISSION_ABANDONED);
81
+ signal?.addEventListener("abort", leaveOnAbort, { once: true });
82
+ if (signal?.aborted) leaveOnAbort();
83
+ const stopWatching = () => {
31
84
  clearTimeout(admissionTimer);
85
+ signal?.removeEventListener("abort", leaveOnAbort);
86
+ };
87
+ result.then((value) => {
88
+ stopWatching();
32
89
  resolve(value);
33
90
  }, (error) => {
34
- clearTimeout(admissionTimer);
91
+ stopWatching();
35
92
  reject(error);
36
93
  });
37
94
  });
@@ -59,7 +116,131 @@ function createKeyedSerialQueue() {
59
116
  }
60
117
  return { run };
61
118
  }
62
- var createSpawnGate = createSerialQueue;
119
+ function toMegabytes(bytes) {
120
+ return Math.round(bytes / BYTES_PER_MEGABYTE);
121
+ }
122
+ function createMemoryAdmission({ readHeadroom, reserveBytesFor, nowMs = Date.now, sleep = (ms) => new Promise((resolve) => {
123
+ setTimeout(resolve, ms);
124
+ }), warn = (message) => console.warn(message) }) {
125
+ let reservations = [];
126
+ let isInProbeFailureStreak = false;
127
+ let heldStartCount = 0;
128
+ let latestHeadroomBytes = null;
129
+ let latestHeadroomReadAtMs = null;
130
+ function noteReading(reading, readAtMs) {
131
+ latestHeadroomReadAtMs = readAtMs;
132
+ latestHeadroomBytes = reading.ok ? reading.headroomBytes : null;
133
+ if (reading.ok) {
134
+ isInProbeFailureStreak = false;
135
+ return;
136
+ }
137
+ if (isInProbeFailureStreak) return;
138
+ isInProbeFailureStreak = true;
139
+ warn(`[memory] could not read memory headroom, so starts go ahead unchecked: ${reading.reason}`);
140
+ }
141
+ async function admitOrDescribeShortfall(kind, { isDryRun = false } = {}) {
142
+ const reserveBytes = reserveBytesFor(kind);
143
+ if (reserveBytes <= 0) return null;
144
+ const reading = await readHeadroom();
145
+ const admittedAtMs = nowMs();
146
+ reservations = liveReservations(reservations, admittedAtMs);
147
+ noteReading(reading, admittedAtMs);
148
+ if (!(isDryRun && reading.ok && heldStartCount > 0) && shouldAdmitStart({
149
+ reading,
150
+ reserveBytes,
151
+ reservations,
152
+ nowMs: admittedAtMs
153
+ })) {
154
+ if (!isDryRun) reservations.push({
155
+ bytes: reserveBytes,
156
+ admittedAtMs
157
+ });
158
+ return null;
159
+ }
160
+ const heldBytes = reservations.reduce((total, reservation) => total + reservation.bytes, 0);
161
+ return {
162
+ headroomBytes: reading.ok ? reading.headroomBytes : 0,
163
+ heldBytes,
164
+ reserveBytes,
165
+ waitingStartCount: heldStartCount
166
+ };
167
+ }
168
+ async function recheckUntilAdmitted(kind, isStillWanted) {
169
+ do {
170
+ await sleep(MEMORY_RECHECK_MS);
171
+ if (!isStillWanted()) return false;
172
+ } while (await admitOrDescribeShortfall(kind) !== null);
173
+ return true;
174
+ }
175
+ async function waitForHeadroom(kind, { isStillWanted = () => true, onMemoryWait = () => {} } = {}) {
176
+ if (!isStillWanted()) return;
177
+ const shortfall = await admitOrDescribeShortfall(kind);
178
+ if (shortfall === null) return;
179
+ if (!isStillWanted()) return;
180
+ const waitStartedAtMs = nowMs();
181
+ warn(`[memory] holding a ${kind} start: ${toMegabytes(shortfall.headroomBytes)} MB headroom, ${toMegabytes(shortfall.heldBytes)} MB held for recent starts, ${toMegabytes(shortfall.reserveBytes)} MB reserve needed`);
182
+ onMemoryWait(true);
183
+ if (!await recheckUntilAdmitted(kind, isStillWanted).finally(() => onMemoryWait(false))) return;
184
+ warn(`[memory] admitted a ${kind} start after waiting ${Math.round((nowMs() - waitStartedAtMs) / 1e3)} s`);
185
+ }
186
+ return {
187
+ waitForHeadroom,
188
+ noteStartHeld: (isHeld) => {
189
+ heldStartCount += isHeld ? 1 : -1;
190
+ },
191
+ gateStatus: () => ({
192
+ headroomBytes: latestHeadroomBytes,
193
+ headroomReadAtMs: latestHeadroomReadAtMs,
194
+ heldStartCount
195
+ }),
196
+ describeShortfallNow: (kind) => admitOrDescribeShortfall(kind, { isDryRun: true })
197
+ };
198
+ }
199
+ function createSpawnGate({ memoryAdmission = null, kind = "session" } = {}) {
200
+ const queue = createSerialQueue();
201
+ if (!memoryAdmission) return queue;
202
+ const admission = memoryAdmission;
203
+ const queuedStarts = /* @__PURE__ */ new Set();
204
+ const flaggedStarts = /* @__PURE__ */ new Set();
205
+ let isHeadStartHeld = false;
206
+ function flagWaitingForMemory(queuedStart) {
207
+ if (flaggedStarts.has(queuedStart) || !queuedStart.isStillWanted()) return;
208
+ flaggedStarts.add(queuedStart);
209
+ admission.noteStartHeld(true);
210
+ queuedStart.onMemoryWait(true);
211
+ }
212
+ function leaveQueue(queuedStart) {
213
+ queuedStarts.delete(queuedStart);
214
+ if (!flaggedStarts.delete(queuedStart)) return;
215
+ admission.noteStartHeld(false);
216
+ queuedStart.onMemoryWait(false);
217
+ }
218
+ function noteHeadStartHeld(isHeld) {
219
+ isHeadStartHeld = isHeld;
220
+ if (!isHeld) return;
221
+ for (const queuedStart of queuedStarts) flagWaitingForMemory(queuedStart);
222
+ }
223
+ function run(fn, options = {}) {
224
+ const { isStillWanted = () => true, onMemoryWait = () => {} } = options;
225
+ const queuedStart = {
226
+ isStillWanted,
227
+ onMemoryWait
228
+ };
229
+ queuedStarts.add(queuedStart);
230
+ if (isHeadStartHeld) flagWaitingForMemory(queuedStart);
231
+ const release = () => leaveQueue(queuedStart);
232
+ const result = queue.run(() => admission.waitForHeadroom(kind, {
233
+ isStillWanted,
234
+ onMemoryWait: noteHeadStartHeld
235
+ }).finally(release).then(fn), options);
236
+ result.then(release, release);
237
+ return result;
238
+ }
239
+ return {
240
+ run,
241
+ idle: queue.idle
242
+ };
243
+ }
63
244
  //#endregion
64
245
  //#region server/json-file.ts
65
246
  function tmpPathFor(filePath) {
@@ -349,4 +530,4 @@ function createJsonStateStore({ name, filePath, fsPromises = fs.promises, parse,
349
530
  };
350
531
  }
351
532
  //#endregion
352
- export { isQueueAdmissionTimeout as _, jsonStateLoadError as a, loadedJsonValue as c, writeJsonAtomicSync as d, writeTextAtomic as f, createSpawnGate as g, createSerialQueue as h, createJsonStateWriter as i, sleepSync as l, createKeyedSerialQueue as m, appendJsonLines as n, loadJsonStateFile as o, writeTextAtomicSync as p, createJsonStateStore as r, loadJsonStateFileSync as s, appendJsonLine as t, writeJsonAtomic as u };
533
+ export { headroomFromReadings as C, parseMemAvailableBytes as D, parseCgroupV2Path as E, cgroupLimitBytes as S, parseCgroupBytes as T, createSpawnGate as _, jsonStateLoadError as a, DEFAULT_CHECK_MEMORY_RESERVE_MB as b, loadedJsonValue as c, writeJsonAtomicSync as d, writeTextAtomic as f, createSerialQueue as g, createMemoryAdmission as h, createJsonStateWriter as i, sleepSync as l, createKeyedSerialQueue as m, appendJsonLines as n, loadJsonStateFile as o, writeTextAtomicSync as p, createJsonStateStore as r, loadJsonStateFileSync as s, appendJsonLine as t, writeJsonAtomic as u, isQueueAdmissionAbandoned as v, memoryReserveBytes as w, cgroupAncestorPaths as x, isQueueAdmissionTimeout as y };
@@ -2,7 +2,7 @@ import { r as errorMessage } from "./text-DoirglWV.js";
2
2
  import { s as resolvePackageBin } from "./runtime-paths-BkeftE60.js";
3
3
  import { r as execFileSync } from "./child-process-safe-CbQnyh7D.js";
4
4
  import { n as glimmervoidHomeDir, t as decideConfigPath } from "./config-path-core-DFt-TemS.js";
5
- import { r as BrowserConfig } from "./config-BYc2z1Oc.js";
5
+ import { r as BrowserConfig } from "./config-BHBZsCBc.js";
6
6
  import fs, { closeSync, constants, existsSync, fstatSync, lstatSync, mkdirSync, openSync, readFileSync, readdirSync, realpathSync } from "node:fs";
7
7
  import path, { dirname, join, posix, resolve, win32 } from "node:path";
8
8
  import os from "node:os";
@@ -1,8 +1,8 @@
1
1
  import { a as isLoopbackHostname } from "./hook-relay-core-DA_bz2KA.js";
2
2
  import { n as decideGuardrailsProxy } from "./guardrails-proxy-core-BI3rdY-m.js";
3
- import http from "node:http";
4
3
  //#region session/loopback-post.ts
5
4
  var POST_TIMEOUT_MS = 1500;
5
+ var http = process.getBuiltinModule("node:http");
6
6
  function refusal(reason) {
7
7
  return {
8
8
  reason,