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.
- package/README.md +1 -1
- package/dist/bin/glimmervoid.js +144 -57
- package/dist/chunks/{adapters-Dho1VSY5.js → adapters-BU74M4QZ.js} +1 -1
- package/dist/chunks/{adapters-zPDx1Xox.js → adapters-CoC18rdt.js} +56 -31
- package/dist/chunks/agent-api-cli-V_BkYhBI.js +142 -0
- package/dist/chunks/agent-api-core-B3YI8SYs.js +192 -0
- package/dist/chunks/{agent-setup-cli-B5Atxr3F.js → agent-setup-cli-D4956BfN.js} +11 -28
- package/dist/chunks/backoff-DjVpfHk7.js +14 -0
- package/dist/chunks/child-process-safe-B3zcPdFM.js +2 -0
- package/dist/chunks/{child-process-safe-DRGsp0TE.js → child-process-safe-DDELk9XC.js} +3 -2
- package/dist/chunks/coerce-NSst8oRP.js +32 -0
- package/dist/chunks/{contracts-DGkKNh9W.js → config-CZ4H51D0.js} +374 -1684
- package/dist/chunks/{config-store-mm7MgzoL.js → config-store-BVtdHkDK.js} +594 -329
- package/dist/chunks/config-store-Cp62jN1O.js +2 -0
- package/dist/chunks/contracts-DXujp-Zn.js +2131 -0
- package/dist/chunks/git-version-CrLW4a6r.js +58 -0
- package/dist/chunks/{grok-DuU8xVLZ.js → grok-C4lzPFEg.js} +24 -21
- package/dist/chunks/{hook-relay-core-BHfYFnYV.js → hook-relay-core-DA_bz2KA.js} +10 -5
- package/dist/chunks/{hook-tools-pSJia7ks.js → hook-tools-UX2fmt81.js} +3 -5
- package/dist/chunks/{ingest-editor-core-BuI1gMF_.js → ingest-editor-core-vR6Wv6bP.js} +24 -13
- package/dist/chunks/json-core-dfa_7Fak.js +23 -0
- package/dist/chunks/json-file-oEH9vt-0.js +352 -0
- package/dist/chunks/knowledge-graph-cli-Bjy9_kv5.js +1354 -0
- package/dist/chunks/{loopback-post-C7C22eYi.js → loopback-post-DepQfdcM.js} +40 -26
- package/dist/chunks/{main-CuIZQPhZ.js → main-DSbpYn2Y.js} +27880 -19139
- package/dist/chunks/{node-pty-preflight-CK1knGIR.js → node-pty-preflight-C8QIlrtU.js} +4 -6
- package/dist/chunks/{pair-cli-w-gCAF-1.js → pair-cli-CKn-wUw9.js} +4 -3
- package/dist/chunks/paths-CeJl2Vcg.js +55 -0
- package/dist/chunks/{remote-config-C2ytQwrs.js → remote-config-DP44Ybt9.js} +37 -41
- package/dist/chunks/{rtk-hook-core-Bl6gYHPN.js → rtk-hook-core-BmEz2aq9.js} +3 -5
- package/dist/chunks/rtk-resolver-CIVLE_xk.js +2 -0
- package/dist/chunks/{rtk-resolver-CLo-gZzw.js → rtk-resolver-jJxy_Mrt.js} +2 -2
- package/dist/chunks/{runtime-paths-Ci_ksSkj.js → runtime-paths-BPoxENmK.js} +2 -6
- package/dist/chunks/runtime-paths-DU5jBEEO.js +2 -0
- package/dist/chunks/{sandbox-deps-Dd5-kZnf.js → sandbox-deps-DuaNFq7n.js} +16 -13
- package/dist/chunks/sandbox-proxy-core-hnQgKR0T.js +27 -0
- package/dist/chunks/{session-Cez8aIWg.js → session-B8fJb_Or.js} +25 -2
- package/dist/chunks/text-DoirglWV.js +21 -0
- package/dist/chunks/timer-deps-u2DAQLok.js +15 -0
- package/dist/chunks/{visions-cli-BXQFIBCX.js → visions-cli-BhFdym5n.js} +1 -1
- package/dist/chunks/{visions-setup-CvVnOe1r.js → visions-setup-CfgNHiG3.js} +20 -357
- package/dist/client/assets/index-C_XKsDFx.css +1 -0
- package/dist/client/assets/index-CoqWjYxP.js +254 -0
- package/dist/client/fonts/CommitMono-OFL.txt +92 -0
- package/dist/client/fonts/commit-mono-400-italic.woff2 +0 -0
- package/dist/client/fonts/commit-mono-400-regular.woff2 +0 -0
- package/dist/client/fonts/commit-mono-700-italic.woff2 +0 -0
- package/dist/client/fonts/commit-mono-700-regular.woff2 +0 -0
- package/dist/client/index.html +7 -24
- package/dist/client/octicons-LICENSE.txt +21 -0
- package/dist/scripts/postinstall-path-check.js +1 -1
- package/dist/server/index.js +3 -3
- package/dist/session/command-hook-relay.js +1 -1
- package/dist/session/hook-relay.js +3 -3
- package/dist/session/hook-tool-relay.js +2 -2
- package/dist/session/sandbox-open-launcher.js +79 -0
- package/dist/session/statusline-relay.js +8 -18
- package/dist/session/visions-relay.js +20 -11
- package/package.json +4 -1
- package/dist/chunks/agent-api-cli-D0MmtEdz.js +0 -71
- package/dist/chunks/agent-api-core-Dz0r21y9.js +0 -103
- package/dist/chunks/child-process-safe-DvQjXsgz.js +0 -2
- package/dist/chunks/config-store-CC8T3okC.js +0 -2
- package/dist/chunks/ingest-core-DWI1Mbu4.js +0 -342
- package/dist/chunks/rtk-resolver-CMQAidlI.js +0 -2
- package/dist/chunks/runtime-paths-JLrZ3wyi.js +0 -2
- package/dist/client/assets/index-B1MFijjb.css +0 -1
- 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 {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
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 (!
|
|
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 (
|
|
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 (!
|
|
239
|
-
const entry = task;
|
|
243
|
+
if (!isRecord(task)) return task;
|
|
240
244
|
return {
|
|
241
|
-
...
|
|
242
|
-
...typeof
|
|
245
|
+
...task,
|
|
246
|
+
...typeof task.agentType === "string" ? { agent_type: task.agentType } : {}
|
|
243
247
|
};
|
|
244
248
|
}
|
|
245
249
|
function mapHookPayload(_event, payload) {
|
|
246
|
-
if (!
|
|
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 (!
|
|
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}: ${
|
|
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,
|
|
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
|
|
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 (!
|
|
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-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
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 {
|
|
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 };
|