glimmervoid 0.30.0 → 0.32.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 (68) hide show
  1. package/README.md +1 -1
  2. package/dist/bin/glimmervoid.js +144 -57
  3. package/dist/chunks/{adapters-Dho1VSY5.js → adapters-BU74M4QZ.js} +1 -1
  4. package/dist/chunks/{adapters-zPDx1Xox.js → adapters-CoC18rdt.js} +56 -31
  5. package/dist/chunks/agent-api-cli-V_BkYhBI.js +142 -0
  6. package/dist/chunks/agent-api-core-B3YI8SYs.js +192 -0
  7. package/dist/chunks/{agent-setup-cli-B5Atxr3F.js → agent-setup-cli-D4956BfN.js} +11 -28
  8. package/dist/chunks/backoff-DjVpfHk7.js +14 -0
  9. package/dist/chunks/child-process-safe-B3zcPdFM.js +2 -0
  10. package/dist/chunks/{child-process-safe-DRGsp0TE.js → child-process-safe-DDELk9XC.js} +3 -2
  11. package/dist/chunks/coerce-NSst8oRP.js +32 -0
  12. package/dist/chunks/{contracts-DGkKNh9W.js → config-CZ4H51D0.js} +374 -1684
  13. package/dist/chunks/{config-store-mm7MgzoL.js → config-store-BVtdHkDK.js} +594 -329
  14. package/dist/chunks/config-store-Cp62jN1O.js +2 -0
  15. package/dist/chunks/contracts-DXujp-Zn.js +2131 -0
  16. package/dist/chunks/git-version-CrLW4a6r.js +58 -0
  17. package/dist/chunks/{grok-DuU8xVLZ.js → grok-C4lzPFEg.js} +24 -21
  18. package/dist/chunks/{hook-relay-core-BHfYFnYV.js → hook-relay-core-DA_bz2KA.js} +10 -5
  19. package/dist/chunks/{hook-tools-pSJia7ks.js → hook-tools-UX2fmt81.js} +3 -5
  20. package/dist/chunks/{ingest-editor-core-BuI1gMF_.js → ingest-editor-core-vR6Wv6bP.js} +24 -13
  21. package/dist/chunks/json-core-dfa_7Fak.js +23 -0
  22. package/dist/chunks/json-file-oEH9vt-0.js +352 -0
  23. package/dist/chunks/knowledge-graph-cli-Bjy9_kv5.js +1354 -0
  24. package/dist/chunks/{loopback-post-C7C22eYi.js → loopback-post-DepQfdcM.js} +40 -26
  25. package/dist/chunks/{main-CuIZQPhZ.js → main-DSbpYn2Y.js} +27880 -19139
  26. package/dist/chunks/{node-pty-preflight-CK1knGIR.js → node-pty-preflight-C8QIlrtU.js} +4 -6
  27. package/dist/chunks/{pair-cli-w-gCAF-1.js → pair-cli-CKn-wUw9.js} +4 -3
  28. package/dist/chunks/paths-CeJl2Vcg.js +55 -0
  29. package/dist/chunks/{remote-config-C2ytQwrs.js → remote-config-DP44Ybt9.js} +37 -41
  30. package/dist/chunks/{rtk-hook-core-Bl6gYHPN.js → rtk-hook-core-BmEz2aq9.js} +3 -5
  31. package/dist/chunks/rtk-resolver-CIVLE_xk.js +2 -0
  32. package/dist/chunks/{rtk-resolver-CLo-gZzw.js → rtk-resolver-jJxy_Mrt.js} +2 -2
  33. package/dist/chunks/{runtime-paths-Ci_ksSkj.js → runtime-paths-BPoxENmK.js} +2 -6
  34. package/dist/chunks/runtime-paths-DU5jBEEO.js +2 -0
  35. package/dist/chunks/{sandbox-deps-Dd5-kZnf.js → sandbox-deps-DuaNFq7n.js} +16 -13
  36. package/dist/chunks/sandbox-proxy-core-hnQgKR0T.js +27 -0
  37. package/dist/chunks/{session-Cez8aIWg.js → session-B8fJb_Or.js} +25 -2
  38. package/dist/chunks/text-DoirglWV.js +21 -0
  39. package/dist/chunks/timer-deps-u2DAQLok.js +15 -0
  40. package/dist/chunks/{visions-cli-BXQFIBCX.js → visions-cli-BhFdym5n.js} +1 -1
  41. package/dist/chunks/{visions-setup-CvVnOe1r.js → visions-setup-CfgNHiG3.js} +20 -357
  42. package/dist/client/assets/index-C_XKsDFx.css +1 -0
  43. package/dist/client/assets/index-CoqWjYxP.js +254 -0
  44. package/dist/client/fonts/CommitMono-OFL.txt +92 -0
  45. package/dist/client/fonts/commit-mono-400-italic.woff2 +0 -0
  46. package/dist/client/fonts/commit-mono-400-regular.woff2 +0 -0
  47. package/dist/client/fonts/commit-mono-700-italic.woff2 +0 -0
  48. package/dist/client/fonts/commit-mono-700-regular.woff2 +0 -0
  49. package/dist/client/index.html +7 -24
  50. package/dist/client/octicons-LICENSE.txt +21 -0
  51. package/dist/scripts/postinstall-path-check.js +1 -1
  52. package/dist/server/index.js +3 -3
  53. package/dist/session/command-hook-relay.js +1 -1
  54. package/dist/session/hook-relay.js +3 -3
  55. package/dist/session/hook-tool-relay.js +2 -2
  56. package/dist/session/sandbox-open-launcher.js +79 -0
  57. package/dist/session/statusline-relay.js +8 -18
  58. package/dist/session/visions-relay.js +20 -11
  59. package/package.json +4 -1
  60. package/dist/chunks/agent-api-cli-D0MmtEdz.js +0 -71
  61. package/dist/chunks/agent-api-core-Dz0r21y9.js +0 -103
  62. package/dist/chunks/child-process-safe-DvQjXsgz.js +0 -2
  63. package/dist/chunks/config-store-CC8T3okC.js +0 -2
  64. package/dist/chunks/ingest-core-DWI1Mbu4.js +0 -342
  65. package/dist/chunks/rtk-resolver-CMQAidlI.js +0 -2
  66. package/dist/chunks/runtime-paths-JLrZ3wyi.js +0 -2
  67. package/dist/client/assets/index-B1MFijjb.css +0 -1
  68. package/dist/client/assets/index-CU1iPPdn.js +0 -249
@@ -0,0 +1,58 @@
1
+ import { r as execFileSync } from "./child-process-safe-DDELk9XC.js";
2
+ //#region server/core/git-version-core.ts
3
+ var NEW_WORK_ISOLATION_FLOOR = Object.freeze({
4
+ major: 2,
5
+ minor: 48
6
+ });
7
+ var NEW_WORK_ISOLATION_FLOOR_LABEL = `${NEW_WORK_ISOLATION_FLOOR.major}.${NEW_WORK_ISOLATION_FLOOR.minor}`;
8
+ var WHOLE_RANGE_CONSEQUENCE = "a team re-review cannot single out the author's new work and reviews the whole pull request range";
9
+ var GIT_UPDATE_HINT = `Update git to ${NEW_WORK_ISOLATION_FLOOR_LABEL} or newer`;
10
+ var UNKNOWN_GIT_VERSION = Object.freeze({
11
+ version: null,
12
+ isTooOldToIsolateNewWork: false
13
+ });
14
+ function gitVersionReport(versionOutput) {
15
+ const match = /^git version (\d+)\.(\d+)(?:\.(\d+))?/.exec(versionOutput?.trim() ?? "");
16
+ if (!match) return UNKNOWN_GIT_VERSION;
17
+ const [, major = "", minor = "", patch] = match;
18
+ const isBelowFloorMajor = Number(major) < NEW_WORK_ISOLATION_FLOOR.major;
19
+ const isBelowFloorMinor = Number(major) === NEW_WORK_ISOLATION_FLOOR.major && Number(minor) < NEW_WORK_ISOLATION_FLOOR.minor;
20
+ return {
21
+ version: [
22
+ major,
23
+ minor,
24
+ patch
25
+ ].filter((part) => part !== void 0).join("."),
26
+ isTooOldToIsolateNewWork: isBelowFloorMajor || isBelowFloorMinor
27
+ };
28
+ }
29
+ function gitBootWarning(report) {
30
+ if (!report.isTooOldToIsolateNewWork) return null;
31
+ return `[git] git ${report.version} is older than ${NEW_WORK_ISOLATION_FLOOR_LABEL}, so ${WHOLE_RANGE_CONSEQUENCE}. ${GIT_UPDATE_HINT}.`;
32
+ }
33
+ function gitDoctorRows(report) {
34
+ const versionRow = ["git", report.version ?? "unknown"];
35
+ if (!report.isTooOldToIsolateNewWork) return [versionRow];
36
+ return [versionRow, ["hint", `${GIT_UPDATE_HINT}: on an older one ${WHOLE_RANGE_CONSEQUENCE}`]];
37
+ }
38
+ //#endregion
39
+ //#region server/git-version.ts
40
+ function readGitVersionOutput() {
41
+ return execFileSync("git", ["--version"], {
42
+ encoding: "utf8",
43
+ timeout: 3e3
44
+ });
45
+ }
46
+ function probeGitVersion({ readVersionOutput = readGitVersionOutput } = {}) {
47
+ try {
48
+ return gitVersionReport(readVersionOutput());
49
+ } catch {
50
+ return gitVersionReport(null);
51
+ }
52
+ }
53
+ function warnWhenGitIsTooOld({ probe = probeGitVersion, log = console } = {}) {
54
+ const warning = gitBootWarning(probe());
55
+ if (warning !== null) log.warn(warning);
56
+ }
57
+ //#endregion
58
+ export { warnWhenGitIsTooOld as n, gitDoctorRows as r, probeGitVersion as t };
@@ -1,12 +1,19 @@
1
- import { o as relayPath } from "./runtime-paths-Ci_ksSkj.js";
2
- import { n as AGENT_URL_ENV } from "./session-Cez8aIWg.js";
3
- import { t as HOOK_URL_ENV } from "./hook-relay-core-BHfYFnYV.js";
4
- import { a as SANE_YOLO_PATH_ENV, n as RTK_PATH_ENV, o as saneYoloEnv } from "./rtk-hook-core-Bl6gYHPN.js";
1
+ import { r as errorMessage } from "./text-DoirglWV.js";
2
+ import { o as relayPath } from "./runtime-paths-BPoxENmK.js";
3
+ import { n as AGENT_URL_ENV } from "./session-B8fJb_Or.js";
4
+ import { t as HOOK_URL_ENV } from "./hook-relay-core-DA_bz2KA.js";
5
+ import { n as isRecord } from "./coerce-NSst8oRP.js";
6
+ import { a as SANE_YOLO_PATH_ENV, n as RTK_PATH_ENV, o as saneYoloEnv } from "./rtk-hook-core-BmEz2aq9.js";
5
7
  import { t as buildHookCommand } from "./hook-command-core-DclEoE9e.js";
6
8
  import fs from "node:fs";
7
9
  import path from "node:path";
8
10
  import os from "node:os";
9
11
  //#region session/core/spawn-env.ts
12
+ var GLIMMERVOID_SECRET_KEYS = [
13
+ "GLIMMERVOID_POSTHOG_API_KEY",
14
+ "GLIMMERVOID_TELEGRAM_BOT_TOKEN",
15
+ "GLIMMERVOID_CLAUDE_OAUTH_TOKEN"
16
+ ];
10
17
  var GLIMMERVOID_SCRUB_KEYS = [
11
18
  "GLIMMERVOID_PORT",
12
19
  "GLIMMERVOID_CONFIG",
@@ -14,11 +21,7 @@ var GLIMMERVOID_SCRUB_KEYS = [
14
21
  AGENT_URL_ENV,
15
22
  RTK_PATH_ENV,
16
23
  SANE_YOLO_PATH_ENV,
17
- ...[
18
- "GLIMMERVOID_POSTHOG_API_KEY",
19
- "GLIMMERVOID_TELEGRAM_BOT_TOKEN",
20
- "GLIMMERVOID_CLAUDE_OAUTH_TOKEN"
21
- ]
24
+ ...GLIMMERVOID_SECRET_KEYS
22
25
  ];
23
26
  var SANE_YOLO_GUARD_KEYS = [SANE_YOLO_PATH_ENV, ...Object.keys(saneYoloEnv(""))];
24
27
  var SAFETY_NET_ENV_PREFIXES = ["CC_SAFETY_NET_", "SAFETY_NET_"];
@@ -68,7 +71,7 @@ function isSaneYoloGuarded(extraEnv) {
68
71
  function scrubInheritedSafetyNetEnv(env) {
69
72
  for (const key of Object.keys(env)) if (isSafetyNetKey(key)) delete env[key];
70
73
  }
71
- function buildAgentEnv(baseEnv, extraEnv, profile, { prependPathDir: pathDir = null } = {}) {
74
+ function buildAgentEnv(baseEnv, extraEnv, profile, { prependPathDir: pathDir = null, prependPathDirs = [] } = {}) {
72
75
  const env = { ...baseEnv };
73
76
  for (const key of profile.scrub || []) delete env[key];
74
77
  for (const key of GLIMMERVOID_SCRUB_KEYS) delete env[key];
@@ -77,6 +80,8 @@ function buildAgentEnv(baseEnv, extraEnv, profile, { prependPathDir: pathDir = n
77
80
  Object.assign(env, extraEnv || {});
78
81
  Object.assign(env, profile.set || {});
79
82
  prependPathDir(env, pathDir);
83
+ const uniquePathDirs = prependPathDirs.filter((directory, index) => prependPathDirs.findIndex((candidate) => normalizePathEntry(candidate) === normalizePathEntry(directory)) === index);
84
+ for (const directory of uniquePathDirs.reverse()) prependPathDir(env, directory);
80
85
  return env;
81
86
  }
82
87
  //#endregion
@@ -102,7 +107,7 @@ function renderGrokHooksFile({ relayPath, events, hookToolRelayPath }) {
102
107
  return `${JSON.stringify({ hooks }, null, 2)}\n`;
103
108
  }
104
109
  function hasOnlyKeys(value, expectedKeys) {
105
- if (!value || typeof value !== "object" || Array.isArray(value)) return false;
110
+ if (!isRecord(value)) return false;
106
111
  const actualKeys = Object.keys(value).sort();
107
112
  const sortedExpectedKeys = [...expectedKeys].sort();
108
113
  return actualKeys.length === sortedExpectedKeys.length && actualKeys.every((key, index) => key === sortedExpectedKeys[index]);
@@ -150,7 +155,7 @@ function classifyGrokHooksFile(contents, { relayPath, events, managedEventSets =
150
155
  if (!hasOnlyKeys(parsed, ["hooks"])) return "foreign";
151
156
  const hooksValue = parsed.hooks;
152
157
  if (hooksValue === null || hooksValue === void 0) throw new TypeError("hooks must be an object");
153
- if (typeof hooksValue !== "object" || Array.isArray(hooksValue)) return "foreign";
158
+ if (!isRecord(hooksValue)) return "foreign";
154
159
  const actualEvents = Object.keys(hooksValue);
155
160
  if (!hasOnlyKeys(hooksValue, actualEvents)) return "foreign";
156
161
  const hooks = hooksValue;
@@ -235,15 +240,14 @@ function isMainSessionPayload(payload) {
235
240
  return !payload?.subagentType && !payload?.subagent_type;
236
241
  }
237
242
  function mapBackgroundTask(task) {
238
- if (!task || typeof task !== "object" || Array.isArray(task)) return task;
239
- const entry = task;
243
+ if (!isRecord(task)) return task;
240
244
  return {
241
- ...entry,
242
- ...typeof entry.agentType === "string" ? { agent_type: entry.agentType } : {}
245
+ ...task,
246
+ ...typeof task.agentType === "string" ? { agent_type: task.agentType } : {}
243
247
  };
244
248
  }
245
249
  function mapHookPayload(_event, payload) {
246
- if (!payload || typeof payload !== "object" || Array.isArray(payload)) return payload;
250
+ if (!isRecord(payload)) return payload;
247
251
  return {
248
252
  ...payload,
249
253
  ...typeof payload.subagentId === "string" ? { agent_id: payload.subagentId } : {},
@@ -259,7 +263,7 @@ function mayContributeHooks(configText) {
259
263
  } catch {
260
264
  return true;
261
265
  }
262
- if (!settings || typeof settings !== "object" || Array.isArray(settings)) return false;
266
+ if (!isRecord(settings)) return false;
263
267
  return Object.hasOwn(settings, "hooks");
264
268
  }
265
269
  function mapHookToSignal(event, payload) {
@@ -337,7 +341,7 @@ function resolveCommand({ platform = process.platform, env = process.env, homedi
337
341
  kind: "exe"
338
342
  };
339
343
  } catch (error) {
340
- warn(`[glimmervoid] could not resolve the native 'grok' binary at ${candidate}: ${error instanceof Error ? error.message : String(error)}`);
344
+ warn(`[glimmervoid] could not resolve the native 'grok' binary at ${candidate}: ${errorMessage(error)}`);
341
345
  return {
342
346
  path: null,
343
347
  kind: "unresolved"
@@ -426,11 +430,10 @@ var grok = {
426
430
  statusLine: false,
427
431
  rtk: false,
428
432
  saneYolo: true,
429
- antiSlop: false,
430
433
  compactQuiet: false,
431
434
  skipPermissionsFlag: true,
432
435
  headless: true
433
436
  }
434
437
  };
435
438
  //#endregion
436
- export { classifyGrokHooksFile as a, isSpinnerChar as i, classifyAgentTitle as n, renderGrokHooksFile as o, isBrailleChar as r, buildAgentEnv as s, grok as t };
439
+ export { classifyGrokHooksFile as a, buildAgentEnv as c, isSpinnerChar as i, classifyAgentTitle as n, renderGrokHooksFile as o, isBrailleChar as r, GLIMMERVOID_SECRET_KEYS as s, grok as t };
@@ -1,12 +1,17 @@
1
- //#region session/core/hook-relay-core.ts
2
- var HOOK_URL_ENV = "GLIMMERVOID_HOOK_URL";
3
- var MAX_RESPONSE_BYTES = 65536;
1
+ //#region shared/loopback-hosts.ts
4
2
  var LOOPBACK_HOSTS = /* @__PURE__ */ new Set([
5
3
  "127.0.0.1",
6
4
  "::1",
7
5
  "[::1]",
8
6
  "localhost"
9
7
  ]);
8
+ function isLoopbackHostname(hostname) {
9
+ return LOOPBACK_HOSTS.has(hostname);
10
+ }
11
+ //#endregion
12
+ //#region session/core/hook-relay-core.ts
13
+ var HOOK_URL_ENV = "GLIMMERVOID_HOOK_URL";
14
+ var MAX_RESPONSE_BYTES = 65536;
10
15
  var EVENT_RE = /^[a-zA-Z][a-zA-Z0-9_-]{0,63}$/;
11
16
  var HOOK_PATH_PREFIX = "/hook/";
12
17
  function readHookUrl(env) {
@@ -34,7 +39,7 @@ function resolveHookTarget(baseUrl, event, pathPrefix = HOOK_PATH_PREFIX) {
34
39
  url: null,
35
40
  reason: "not-http"
36
41
  };
37
- if (!LOOPBACK_HOSTS.has(target.hostname)) return {
42
+ if (!isLoopbackHostname(target.hostname)) return {
38
43
  url: null,
39
44
  reason: "not-loopback"
40
45
  };
@@ -85,4 +90,4 @@ function decideRelayPost({ env = {}, event = null, payloadBytes = 0 } = {}) {
85
90
  };
86
91
  }
87
92
  //#endregion
88
- export { resolveHookTarget as i, MAX_RESPONSE_BYTES as n, decideRelayPost as r, HOOK_URL_ENV as t };
93
+ export { isLoopbackHostname as a, resolveHookTarget as i, MAX_RESPONSE_BYTES as n, decideRelayPost as r, HOOK_URL_ENV as t };
@@ -1,5 +1,5 @@
1
1
  import { r as resolvePathCommandMatches } from "./spawn-command-Cc40FiZI.js";
2
- import { a as SANE_YOLO_PATH_ENV, n as RTK_PATH_ENV, o as saneYoloEnv } from "./rtk-hook-core-Bl6gYHPN.js";
2
+ import { a as SANE_YOLO_PATH_ENV, n as RTK_PATH_ENV, o as saneYoloEnv } from "./rtk-hook-core-BmEz2aq9.js";
3
3
  import { t as buildHookCommand } from "./hook-command-core-DclEoE9e.js";
4
4
  import path from "node:path";
5
5
  //#region session/core/hook-tools.ts
@@ -12,12 +12,10 @@ function firstExistingFile(candidates, fsApi) {
12
12
  function resolveRtkPath({ glimmervoidHome, platform, exec, fsApi }) {
13
13
  const bundled = firstExistingFile([path.join(glimmervoidHome, "bin", "rtk.exe"), path.join(glimmervoidHome, "bin", "rtk")], fsApi);
14
14
  if (bundled) return bundled;
15
- const matches = resolvePathCommandMatches("rtk", {
15
+ const firstMatch = resolvePathCommandMatches("rtk", {
16
16
  platform,
17
17
  exec
18
- });
19
- if (matches.length === 0) return null;
20
- const firstMatch = matches[0];
18
+ })[0];
21
19
  if (!firstMatch) return null;
22
20
  return path.resolve(firstMatch);
23
21
  }
@@ -1,3 +1,4 @@
1
+ import { a as isPathInside } from "./paths-CeJl2Vcg.js";
1
2
  //#region server/core/visions-buffer-core.ts
2
3
  function createDocStore() {
3
4
  return { docsByUri: Object.create(null) };
@@ -317,12 +318,7 @@ function pathOfFileUri(uri) {
317
318
  return normalizeShapePath(pathname);
318
319
  }
319
320
  function isWithin(scopePath, uriPath, foldCase = false) {
320
- if (!scopePath || !uriPath) return false;
321
- const scopeKey = foldCase ? scopePath.toLowerCase() : scopePath;
322
- const uriKey = foldCase ? uriPath.toLowerCase() : uriPath;
323
- if (uriKey === scopeKey) return true;
324
- const prefix = scopeKey.endsWith("/") ? scopeKey : `${scopeKey}/`;
325
- return uriKey.startsWith(prefix);
321
+ return isPathInside(scopePath, uriPath, { foldCase });
326
322
  }
327
323
  function isUriInProjects(uri, normalizedProjectPaths, foldCase = false) {
328
324
  const uriPath = pathOfFileUri(uri);
@@ -361,23 +357,38 @@ function scopePathsOf(scopeProjects) {
361
357
  return paths;
362
358
  }
363
359
  function resolveVisionsScopeProjects({ configuredIds, projects, warn }) {
360
+ const ids = Array.isArray(configuredIds) ? configuredIds.filter((id) => typeof id === "string" && id !== "") : [];
361
+ const wanted = new Set(ids);
364
362
  const usable = [];
363
+ const usableIds = /* @__PURE__ */ new Set();
365
364
  const seenPaths = /* @__PURE__ */ new Set();
366
365
  for (const project of Array.isArray(projects) ? projects : []) {
367
366
  if (!project || typeof project.id !== "string" || project.id === "") continue;
367
+ if (wanted.size > 0 && !wanted.has(project.id)) continue;
368
368
  const normalizedPath = normalizeShapePath(project.path);
369
- if (!normalizedPath || seenPaths.has(normalizedPath)) continue;
369
+ if (!normalizedPath) continue;
370
+ usableIds.add(project.id);
371
+ if (seenPaths.has(normalizedPath)) continue;
370
372
  seenPaths.add(normalizedPath);
371
373
  usable.push({
372
374
  id: project.id,
373
375
  path: normalizedPath
374
376
  });
375
377
  }
376
- const ids = Array.isArray(configuredIds) ? configuredIds.filter((id) => typeof id === "string" && id !== "") : [];
377
- if (ids.length === 0) return usable;
378
- const wanted = new Set(ids);
379
- for (const id of ids) if (!usable.some((project) => project.id === id)) warn(`[visions] configured project id not found or has no usable path: ${id}`);
380
- return usable.filter((project) => wanted.has(project.id));
378
+ for (const id of ids) if (!usableIds.has(id)) warn(`[visions] configured project id not found or has no usable path: ${id}`);
379
+ return usable;
380
+ }
381
+ function visionsLaneReloadSignature(ingest, visions, projects) {
382
+ const scopeProjects = visions.enabled ? resolveVisionsScopeProjects({
383
+ configuredIds: visions.projects,
384
+ projects,
385
+ warn: () => {}
386
+ }) : [];
387
+ return JSON.stringify({
388
+ ingest,
389
+ visions,
390
+ scopeProjects
391
+ });
381
392
  }
382
393
  //#endregion
383
394
  //#region server/core/ingest-editor-core.ts
@@ -442,4 +453,4 @@ function applyEditorNotification(state, { method, uri, roots = [], foldCase = fa
442
453
  };
443
454
  }
444
455
  //#endregion
445
- export { listDocs as _, projectForUri as a, uriOfParams as b, applyDidChange as c, createDocStore as d, detectBlankLineBoundary as f, lineStartOffsets as g, lineOfOffset as h, isUriInProjects as i, applyDidClose as l, getDoc as m, applyEditorNotification as n, resolveVisionsScopeProjects as o, formatRange as p, createEditorState as r, scopePathsOf as s, ACTIVITY_METHOD as t, applyDidOpen as u, offsetOfPosition as v, replacedSpanOfWholeTextChange as y };
456
+ export { lineStartOffsets as _, projectForUri as a, replacedSpanOfWholeTextChange as b, visionsLaneReloadSignature as c, applyDidOpen as d, createDocStore as f, lineOfOffset as g, getDoc as h, isUriInProjects as i, applyDidChange as l, formatRange as m, applyEditorNotification as n, resolveVisionsScopeProjects as o, detectBlankLineBoundary as p, createEditorState as r, scopePathsOf as s, ACTIVITY_METHOD as t, applyDidClose as u, listDocs as v, uriOfParams as x, offsetOfPosition as y };
@@ -0,0 +1,23 @@
1
+ import { n as isRecord } from "./coerce-NSst8oRP.js";
2
+ //#region server/core/json-core.ts
3
+ function jsonSourceText(text) {
4
+ if (typeof text === "string") return text;
5
+ if (Buffer.isBuffer(text)) return text.toString("utf8");
6
+ return null;
7
+ }
8
+ function parseJsonOrNull(text) {
9
+ const source = jsonSourceText(text);
10
+ if (source === null) return null;
11
+ try {
12
+ return JSON.parse(source);
13
+ } catch {
14
+ return null;
15
+ }
16
+ }
17
+ function parseJsonRecord(text, { admitArrays = false } = {}) {
18
+ const parsed = parseJsonOrNull(text);
19
+ if (admitArrays) return parsed !== null && typeof parsed === "object" ? parsed : null;
20
+ return isRecord(parsed) ? parsed : null;
21
+ }
22
+ //#endregion
23
+ export { parseJsonRecord as n, parseJsonOrNull as t };
@@ -0,0 +1,352 @@
1
+ import { a as isMissingFileError, r as errorMessage } from "./text-DoirglWV.js";
2
+ import { r as nextBackoffMs } from "./backoff-DjVpfHk7.js";
3
+ import fs from "node:fs";
4
+ import path from "node:path";
5
+ import crypto from "node:crypto";
6
+ //#region server/spawn-gate.ts
7
+ var QUEUE_ADMISSION_TIMED_OUT = "serial-queue-admission-timed-out";
8
+ function isQueueAdmissionTimeout(error) {
9
+ return error instanceof Error && error.message === "serial-queue-admission-timed-out";
10
+ }
11
+ function createSerialQueue() {
12
+ let tail = Promise.resolve();
13
+ function run(fn, options = {}) {
14
+ let abandoned = false;
15
+ let started = false;
16
+ const result = tail.then(() => {
17
+ if (abandoned) throw new Error(QUEUE_ADMISSION_TIMED_OUT);
18
+ started = true;
19
+ return fn();
20
+ });
21
+ tail = result.then(() => void 0, () => void 0);
22
+ const admissionTimeoutMs = options.admissionTimeoutMs;
23
+ if (admissionTimeoutMs === void 0) return result;
24
+ return new Promise((resolve, reject) => {
25
+ const admissionTimer = setTimeout(() => {
26
+ if (started) return;
27
+ abandoned = true;
28
+ reject(/* @__PURE__ */ new Error(QUEUE_ADMISSION_TIMED_OUT));
29
+ }, admissionTimeoutMs);
30
+ result.then((value) => {
31
+ clearTimeout(admissionTimer);
32
+ resolve(value);
33
+ }, (error) => {
34
+ clearTimeout(admissionTimer);
35
+ reject(error);
36
+ });
37
+ });
38
+ }
39
+ return {
40
+ run,
41
+ idle: () => tail
42
+ };
43
+ }
44
+ function createKeyedSerialQueue() {
45
+ const queuesByKey = /* @__PURE__ */ new Map();
46
+ function run(key, fn) {
47
+ const entry = queuesByKey.get(key) ?? {
48
+ queue: createSerialQueue(),
49
+ pendingCount: 0
50
+ };
51
+ queuesByKey.set(key, entry);
52
+ entry.pendingCount += 1;
53
+ const result = entry.queue.run(fn);
54
+ result.then(() => void 0, () => void 0).then(() => {
55
+ entry.pendingCount -= 1;
56
+ if (entry.pendingCount === 0 && queuesByKey.get(key) === entry) queuesByKey.delete(key);
57
+ });
58
+ return result;
59
+ }
60
+ return { run };
61
+ }
62
+ var createSpawnGate = createSerialQueue;
63
+ //#endregion
64
+ //#region server/json-file.ts
65
+ function tmpPathFor(filePath) {
66
+ return `${filePath}.${process.pid}.${crypto.randomBytes(8).toString("hex")}.tmp`;
67
+ }
68
+ function writeOptions(mode, encoding, exclusive) {
69
+ return {
70
+ encoding,
71
+ ...mode == null ? {} : { mode },
72
+ ...exclusive ? { flag: "wx" } : {}
73
+ };
74
+ }
75
+ var RENAME_RETRY_CODES = /* @__PURE__ */ new Set([
76
+ "EPERM",
77
+ "EACCES",
78
+ "EBUSY"
79
+ ]);
80
+ var RENAME_RETRY_BASE_MS = 10;
81
+ var RENAME_RETRY_MAX_MS = 50;
82
+ function renameRetryDelayMs(attempt) {
83
+ return nextBackoffMs({
84
+ attempt: attempt + 1,
85
+ baseMs: RENAME_RETRY_BASE_MS,
86
+ maxMs: RENAME_RETRY_MAX_MS,
87
+ jitter: "none"
88
+ });
89
+ }
90
+ function isRetryableRename(error, attempt) {
91
+ if (attempt >= 4) return false;
92
+ const code = error?.code;
93
+ return typeof code === "string" && RENAME_RETRY_CODES.has(code);
94
+ }
95
+ function sleepSync(ms) {
96
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
97
+ }
98
+ function renameRetryPlan(error, attempt) {
99
+ if (!isRetryableRename(error, attempt)) return null;
100
+ return renameRetryDelayMs(attempt);
101
+ }
102
+ function decodeJsonState(text, parse) {
103
+ try {
104
+ const value = parse(JSON.parse(text));
105
+ if (value !== null) return { value };
106
+ return { error: /* @__PURE__ */ new Error("the parser rejected the file content") };
107
+ } catch (error) {
108
+ return { error };
109
+ }
110
+ }
111
+ async function loadJsonStateFile({ filePath, fsPromises = fs.promises, parse, nowMs = Date.now, quarantine = true, includeNotDir = true }) {
112
+ let text;
113
+ try {
114
+ text = await fsPromises.readFile(filePath, "utf8");
115
+ } catch (error) {
116
+ if (isMissingFileError(error, { includeNotDir })) return { status: "missing" };
117
+ return {
118
+ status: "unreadable",
119
+ error
120
+ };
121
+ }
122
+ const decoded = decodeJsonState(text, parse);
123
+ if ("value" in decoded) return {
124
+ status: "loaded",
125
+ value: decoded.value
126
+ };
127
+ if (!quarantine || !fsPromises.rename) return {
128
+ status: "corrupt",
129
+ error: decoded.error
130
+ };
131
+ const movedTo = `${filePath}.corrupt-${nowMs()}`;
132
+ try {
133
+ await fsPromises.rename(filePath, movedTo);
134
+ } catch (error) {
135
+ return {
136
+ status: "unreadable",
137
+ error
138
+ };
139
+ }
140
+ return {
141
+ status: "quarantined",
142
+ movedTo
143
+ };
144
+ }
145
+ function loadJsonStateFileSync({ filePath, fsSync = fs, parse, nowMs = Date.now, quarantine = true, includeNotDir = true }) {
146
+ let text;
147
+ try {
148
+ text = fsSync.readFileSync(filePath, "utf8");
149
+ } catch (error) {
150
+ if (isMissingFileError(error, { includeNotDir })) return { status: "missing" };
151
+ return {
152
+ status: "unreadable",
153
+ error
154
+ };
155
+ }
156
+ const decoded = decodeJsonState(text, parse);
157
+ if ("value" in decoded) return {
158
+ status: "loaded",
159
+ value: decoded.value
160
+ };
161
+ if (!quarantine || !fsSync.renameSync) return {
162
+ status: "corrupt",
163
+ error: decoded.error
164
+ };
165
+ const movedTo = `${filePath}.corrupt-${nowMs()}`;
166
+ try {
167
+ fsSync.renameSync(filePath, movedTo);
168
+ } catch (error) {
169
+ return {
170
+ status: "unreadable",
171
+ error
172
+ };
173
+ }
174
+ return {
175
+ status: "quarantined",
176
+ movedTo
177
+ };
178
+ }
179
+ function loadedJsonValue(outcome) {
180
+ return outcome.status === "loaded" ? outcome.value : null;
181
+ }
182
+ function jsonStateLoadError(outcome) {
183
+ if ("error" in outcome) return outcome.error;
184
+ return /* @__PURE__ */ new Error(`the state file is ${outcome.status}`);
185
+ }
186
+ function renameWithRetrySync(fsSync, tmpPath, filePath) {
187
+ for (let attempt = 0;; attempt += 1) try {
188
+ fsSync.renameSync(tmpPath, filePath);
189
+ return;
190
+ } catch (error) {
191
+ const delayMs = renameRetryPlan(error, attempt);
192
+ if (delayMs === null) throw error;
193
+ sleepSync(delayMs);
194
+ }
195
+ }
196
+ async function renameWithRetry(fsPromises, tmpPath, filePath) {
197
+ for (let attempt = 0;; attempt += 1) try {
198
+ await fsPromises.rename(tmpPath, filePath);
199
+ return;
200
+ } catch (error) {
201
+ const delayMs = renameRetryPlan(error, attempt);
202
+ if (delayMs === null) throw error;
203
+ await new Promise((resolve) => {
204
+ setTimeout(resolve, delayMs);
205
+ });
206
+ }
207
+ }
208
+ function mkdirSyncOf(fsSync) {
209
+ if (!fsSync.mkdirSync) throw new Error("the file system cannot create directories");
210
+ return fsSync.mkdirSync;
211
+ }
212
+ function mkdirOf(fsPromises) {
213
+ if (!fsPromises.mkdir) throw new Error("the file system cannot create directories");
214
+ return fsPromises.mkdir;
215
+ }
216
+ function appendFileOf(fsPromises) {
217
+ if (!fsPromises.appendFile) throw new Error("the file system cannot append to files");
218
+ return fsPromises.appendFile;
219
+ }
220
+ function writeTextAtomicSync(filePath, content, { mode, encoding = "utf8", mkdir = false, exclusive = false, enforceMode = false, fsSync = fs } = {}) {
221
+ if (mkdir) mkdirSyncOf(fsSync)(path.dirname(filePath), { recursive: true });
222
+ const tmpPath = tmpPathFor(filePath);
223
+ try {
224
+ fsSync.writeFileSync(tmpPath, content, writeOptions(mode, encoding, exclusive));
225
+ renameWithRetrySync(fsSync, tmpPath, filePath);
226
+ } catch (error) {
227
+ try {
228
+ fsSync.rmSync(tmpPath, { force: true });
229
+ } catch {}
230
+ throw error;
231
+ }
232
+ if (!enforceMode || mode == null || !fsSync.chmodSync) return;
233
+ try {
234
+ fsSync.chmodSync(filePath, mode);
235
+ } catch {}
236
+ }
237
+ function writeJsonAtomicSync(filePath, value, options) {
238
+ writeTextAtomicSync(filePath, JSON.stringify(value, null, 2), options);
239
+ }
240
+ async function writeTextAtomic(filePath, content, { mode, encoding = "utf8", mkdir = false, exclusive = false, enforceMode = false, fsPromises = fs.promises } = {}) {
241
+ if (mkdir) await mkdirOf(fsPromises)(path.dirname(filePath), { recursive: true });
242
+ const tmpPath = tmpPathFor(filePath);
243
+ try {
244
+ await fsPromises.writeFile(tmpPath, content, writeOptions(mode, encoding, exclusive));
245
+ await renameWithRetry(fsPromises, tmpPath, filePath);
246
+ } catch (error) {
247
+ try {
248
+ await fsPromises.rm(tmpPath, { force: true });
249
+ } catch {}
250
+ throw error;
251
+ }
252
+ if (!enforceMode || mode == null || !fsPromises.chmod) return;
253
+ try {
254
+ await fsPromises.chmod(filePath, mode);
255
+ } catch {}
256
+ }
257
+ async function writeJsonAtomic(filePath, value, options) {
258
+ await writeTextAtomic(filePath, JSON.stringify(value, null, 2), options);
259
+ }
260
+ var appendQueue = createKeyedSerialQueue();
261
+ function appendChained(filePath, payload, { fsPromises = fs.promises, mkdir = false, encoding = "utf8", mode } = {}) {
262
+ return appendQueue.run(filePath, async () => {
263
+ if (mkdir) await mkdirOf(fsPromises)(path.dirname(filePath), { recursive: true });
264
+ await appendFileOf(fsPromises)(filePath, payload, writeOptions(mode, encoding, false));
265
+ });
266
+ }
267
+ function appendJsonLine(filePath, value, options) {
268
+ return appendChained(filePath, `${JSON.stringify(value)}\n`, options);
269
+ }
270
+ function appendJsonLines(filePath, values, options) {
271
+ if (values.length === 0) return Promise.resolve();
272
+ return appendChained(filePath, values.map((value) => `${JSON.stringify(value)}\n`).join(""), options);
273
+ }
274
+ function createJsonStateWriter({ filePath, fsPromises = fs.promises, warn = () => {} }) {
275
+ let signature = null;
276
+ const writeQueue = createSerialQueue();
277
+ async function commit(payload) {
278
+ try {
279
+ await writeTextAtomic(filePath, payload, {
280
+ fsPromises,
281
+ mkdir: true
282
+ });
283
+ } catch (error) {
284
+ warn(error);
285
+ signature = null;
286
+ }
287
+ }
288
+ async function write(subject, buildPayload) {
289
+ const next = JSON.stringify(subject);
290
+ if (next === signature) return;
291
+ signature = next;
292
+ await writeQueue.run(() => commit(buildPayload())).catch(() => {});
293
+ }
294
+ function reset() {
295
+ signature = null;
296
+ }
297
+ return {
298
+ write,
299
+ reset,
300
+ idle: () => writeQueue.idle()
301
+ };
302
+ }
303
+ function createJsonStateStore({ name, filePath, fsPromises = fs.promises, parse, adopt, nowMs = Date.now, warn = () => {} }) {
304
+ const writer = filePath ? createJsonStateWriter({
305
+ filePath,
306
+ fsPromises,
307
+ warn: (error) => warn(`${name} write failed`, { error: errorMessage(error) })
308
+ }) : null;
309
+ let isFileReadable = true;
310
+ let loadPromise = null;
311
+ function load() {
312
+ const statePath = filePath;
313
+ if (!statePath) return Promise.resolve();
314
+ if (loadPromise) return loadPromise;
315
+ loadPromise = (async () => {
316
+ const outcome = await loadJsonStateFile({
317
+ filePath: statePath,
318
+ fsPromises,
319
+ parse,
320
+ nowMs
321
+ });
322
+ if (outcome.status === "unreadable" || outcome.status === "corrupt") {
323
+ isFileReadable = false;
324
+ loadPromise = null;
325
+ warn(`${name} unreadable`, {
326
+ path: statePath,
327
+ error: errorMessage(outcome.error)
328
+ });
329
+ return;
330
+ }
331
+ if (outcome.status === "quarantined") warn(`${name} quarantined`, {
332
+ path: statePath,
333
+ movedTo: outcome.movedTo
334
+ });
335
+ isFileReadable = true;
336
+ adopt(loadedJsonValue(outcome));
337
+ writer?.reset();
338
+ })();
339
+ return loadPromise;
340
+ }
341
+ async function write(subject, buildPayload) {
342
+ if (!writer || !isFileReadable) return;
343
+ await writer.write(subject, buildPayload);
344
+ }
345
+ return {
346
+ load,
347
+ write,
348
+ idle: () => writer ? writer.idle() : Promise.resolve()
349
+ };
350
+ }
351
+ //#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 };