glimmervoid 0.29.1 → 0.31.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 (67) hide show
  1. package/README.md +8 -10
  2. package/dist/bin/glimmervoid.js +152 -53
  3. package/dist/chunks/{adapters-DIavI9-i.js → adapters-ClA_GbtA.js} +1 -1
  4. package/dist/chunks/{adapters-Dlvu1FVB.js → adapters-gn7ulNO4.js} +49 -20
  5. package/dist/chunks/agent-api-cli-DAA7Jx8N.js +135 -0
  6. package/dist/chunks/{agent-api-core-D6LHrpSL.js → agent-api-core-hVcT26JW.js} +10 -1
  7. package/dist/chunks/{agent-setup-cli-C1CQ8Nkk.js → agent-setup-cli-CiJSDWSo.js} +15 -30
  8. package/dist/chunks/backoff-DjVpfHk7.js +14 -0
  9. package/dist/chunks/child-process-safe-BKPZ-5qQ.js +2 -0
  10. package/dist/chunks/{child-process-safe-Cz22RwlG.js → child-process-safe-Ch-Zgxqs.js} +2 -2
  11. package/dist/chunks/coerce-NSst8oRP.js +32 -0
  12. package/dist/chunks/{contracts-JKChPhZ0.js → config-W1Sv-iPK.js} +380 -1682
  13. package/dist/chunks/{config-store-DtPUFVaO.js → config-store-BCy4FHNG.js} +595 -327
  14. package/dist/chunks/config-store-DbBp7LJZ.js +2 -0
  15. package/dist/chunks/contracts-3LkrilQX.js +2078 -0
  16. package/dist/chunks/{grok-COekzawt.js → grok-CXKeSt2z.js} +69 -36
  17. package/dist/chunks/hook-command-core-DclEoE9e.js +14 -0
  18. package/dist/chunks/{hook-relay-core-BHfYFnYV.js → hook-relay-core-DA_bz2KA.js} +10 -5
  19. package/dist/chunks/hook-tools-UX2fmt81.js +72 -0
  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-D2tt5hPn.js +1354 -0
  24. package/dist/chunks/{loopback-post-C7C22eYi.js → loopback-post-DepQfdcM.js} +40 -26
  25. package/dist/chunks/{main-BVDjy7vH.js → main-DyTCWIu2.js} +28881 -20693
  26. package/dist/chunks/{node-pty-preflight-CK1knGIR.js → node-pty-preflight-C8QIlrtU.js} +4 -6
  27. package/dist/chunks/{pair-cli-BQQnhkkc.js → pair-cli-BbCBfd6l.js} +4 -3
  28. package/dist/chunks/paths-CeJl2Vcg.js +55 -0
  29. package/dist/chunks/{remote-config-BHoDFCpo.js → remote-config-DKIH_VxM.js} +43 -43
  30. package/dist/chunks/rtk-hook-core-BmEz2aq9.js +131 -0
  31. package/dist/chunks/rtk-resolver-BGDzw5XK.js +21 -0
  32. package/dist/chunks/rtk-resolver-D4Nke1Fr.js +2 -0
  33. package/dist/chunks/{runtime-paths-CVvq20A4.js → runtime-paths-BPoxENmK.js} +28 -8
  34. package/dist/chunks/runtime-paths-DU5jBEEO.js +2 -0
  35. package/dist/chunks/{sandbox-deps-BwvbDBDl.js → sandbox-deps-BPKE-ylr.js} +16 -13
  36. package/dist/chunks/sandbox-proxy-core-hnQgKR0T.js +27 -0
  37. package/dist/chunks/{session-CJtOveHl.js → session-fc4pFbon.js} +10 -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-DUZnopGY.js → visions-cli-CT5rjiwf.js} +1 -1
  41. package/dist/chunks/{visions-setup-C_kJobsy.js → visions-setup-BmOkI-QE.js} +20 -357
  42. package/dist/client/assets/index-C6KD8lgZ.css +1 -0
  43. package/dist/client/assets/index-CThQEAEy.js +249 -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/{rtk-relay.js → hook-tool-relay.js} +32 -15
  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 +5 -1
  60. package/dist/chunks/agent-api-cli-ClOzm28U.js +0 -71
  61. package/dist/chunks/config-store-DtUGwi4-.js +0 -2
  62. package/dist/chunks/ingest-core-DWI1Mbu4.js +0 -342
  63. package/dist/chunks/rtk-hook-core-DRYrKwYP.js +0 -26
  64. package/dist/chunks/rtk-resolver-DDVVNRBT.js +0 -2
  65. package/dist/chunks/rtk-resolver-oGmO-ew7.js +0 -58
  66. package/dist/client/assets/index-BTwYgSAH.js +0 -248
  67. package/dist/client/assets/index-DgA708PE.css +0 -1
@@ -1,16 +1,30 @@
1
- import { o as relayPath } from "./runtime-paths-CVvq20A4.js";
2
- import { n as AGENT_URL_ENV } from "./session-CJtOveHl.js";
3
- import { t as HOOK_URL_ENV } from "./hook-relay-core-BHfYFnYV.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-fc4pFbon.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";
7
+ import { t as buildHookCommand } from "./hook-command-core-DclEoE9e.js";
4
8
  import fs from "node:fs";
5
9
  import path from "node:path";
6
10
  import os from "node:os";
7
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
+ ];
8
17
  var GLIMMERVOID_SCRUB_KEYS = [
9
18
  "GLIMMERVOID_PORT",
10
19
  "GLIMMERVOID_CONFIG",
11
20
  HOOK_URL_ENV,
12
- AGENT_URL_ENV
21
+ AGENT_URL_ENV,
22
+ RTK_PATH_ENV,
23
+ SANE_YOLO_PATH_ENV,
24
+ ...GLIMMERVOID_SECRET_KEYS
13
25
  ];
26
+ var SANE_YOLO_GUARD_KEYS = [SANE_YOLO_PATH_ENV, ...Object.keys(saneYoloEnv(""))];
27
+ var SAFETY_NET_ENV_PREFIXES = ["CC_SAFETY_NET_", "SAFETY_NET_"];
14
28
  var LAUNCHING_TERMINAL_IDENTITY_KEYS = ["TERM_PROGRAM", "TERM_PROGRAM_VERSION"];
15
29
  function normalizePathEntry(entry) {
16
30
  return entry.replace(/\\/g, "/").toLowerCase();
@@ -46,29 +60,31 @@ function prependPathDir(env, prependPathDirValue) {
46
60
  }
47
61
  env[pathKey] = `${prependPathDirValue}${path.delimiter}${existingPath}`;
48
62
  }
49
- function buildAgentEnv(baseEnv, extraEnv, profile, { prependPathDir: pathDir = null } = {}) {
63
+ function isSafetyNetKey(key) {
64
+ const upperKey = key.toUpperCase();
65
+ return SAFETY_NET_ENV_PREFIXES.some((prefix) => upperKey.startsWith(prefix));
66
+ }
67
+ function isSaneYoloGuarded(extraEnv) {
68
+ if (!extraEnv) return false;
69
+ return SANE_YOLO_GUARD_KEYS.some((key) => extraEnv[key] !== void 0);
70
+ }
71
+ function scrubInheritedSafetyNetEnv(env) {
72
+ for (const key of Object.keys(env)) if (isSafetyNetKey(key)) delete env[key];
73
+ }
74
+ function buildAgentEnv(baseEnv, extraEnv, profile, { prependPathDir: pathDir = null, prependPathDirs = [] } = {}) {
50
75
  const env = { ...baseEnv };
51
76
  for (const key of profile.scrub || []) delete env[key];
52
77
  for (const key of GLIMMERVOID_SCRUB_KEYS) delete env[key];
53
78
  for (const key of LAUNCHING_TERMINAL_IDENTITY_KEYS) delete env[key];
79
+ if (isSaneYoloGuarded(extraEnv)) scrubInheritedSafetyNetEnv(env);
54
80
  Object.assign(env, extraEnv || {});
55
81
  Object.assign(env, profile.set || {});
56
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);
57
85
  return env;
58
86
  }
59
87
  //#endregion
60
- //#region session/core/hook-command-core.ts
61
- var SAFE_PATH_RE = /^[A-Za-z0-9_.:/\\ -]+$/;
62
- var SAFE_EVENT_RE = /^[A-Za-z][A-Za-z0-9_-]{0,63}$/;
63
- function buildHookCommand(relayPath, event) {
64
- const rawPath = String(relayPath);
65
- const rawEvent = String(event);
66
- if (!SAFE_PATH_RE.test(rawPath)) return null;
67
- if (!SAFE_EVENT_RE.test(rawEvent)) return null;
68
- const forwardSlashedPath = rawPath.replace(/\\/g, "/");
69
- return `node ${/\s/.test(forwardSlashedPath) ? `"${forwardSlashedPath}"` : forwardSlashedPath} ${rawEvent}`;
70
- }
71
- //#endregion
72
88
  //#region session/core/grok-hooks-file-core.ts
73
89
  function hookGroup(command) {
74
90
  return [{ hooks: [{
@@ -76,30 +92,38 @@ function hookGroup(command) {
76
92
  command
77
93
  }] }];
78
94
  }
79
- function renderGrokHooksFile({ relayPath, events }) {
95
+ function renderGrokHooksFile({ relayPath, events, hookToolRelayPath }) {
80
96
  const hooks = {};
81
97
  for (const event of events) {
82
98
  const command = buildHookCommand(relayPath, event);
83
99
  if (!command) return null;
84
100
  hooks[event] = hookGroup(command);
85
101
  }
102
+ if (hookToolRelayPath) {
103
+ const command = buildHookCommand(hookToolRelayPath, "saneYolo");
104
+ if (!command) return null;
105
+ hooks.PreToolUse = hookGroup(command);
106
+ }
86
107
  return `${JSON.stringify({ hooks }, null, 2)}\n`;
87
108
  }
88
109
  function hasOnlyKeys(value, expectedKeys) {
89
- if (!value || typeof value !== "object" || Array.isArray(value)) return false;
110
+ if (!isRecord(value)) return false;
90
111
  const actualKeys = Object.keys(value).sort();
91
112
  const sortedExpectedKeys = [...expectedKeys].sort();
92
113
  return actualKeys.length === sortedExpectedKeys.length && actualKeys.every((key, index) => key === sortedExpectedKeys[index]);
93
114
  }
94
- var MANAGED_RELAY_RE = /(?:^|\/)hook-relay\.(?:js|ts)$/;
115
+ var MANAGED_RELAY_RE = /(?:^|\/)(hook-relay|hook-tool-relay)\.(?:js|ts)$/;
95
116
  function isManagedCommand(command, event) {
96
117
  if (typeof command !== "string") return false;
97
118
  const match = command.match(/^node (?:(?:"([^"\r\n]+)")|([^\s"']+)) ([A-Za-z][A-Za-z0-9_-]{0,63})$/);
98
119
  if (!match) return false;
99
120
  const relayPath = match[1] || match[2];
100
- if (match[3] !== event) return false;
101
- if (!MANAGED_RELAY_RE.test(relayPath)) return false;
102
- return buildHookCommand(relayPath, event) === command;
121
+ const relayMatch = relayPath.match(MANAGED_RELAY_RE);
122
+ if (!relayMatch) return false;
123
+ const expectedRelay = event === "PreToolUse" ? "hook-tool-relay" : "hook-relay";
124
+ const expectedToken = event === "PreToolUse" ? "saneYolo" : event;
125
+ if (relayMatch[1] !== expectedRelay || match[3] !== expectedToken) return false;
126
+ return buildHookCommand(relayPath, expectedToken) === command;
103
127
  }
104
128
  function isManagedHookGroup(group, event) {
105
129
  if (!Array.isArray(group) || group.length !== 1) return false;
@@ -111,8 +135,13 @@ function isManagedHookGroup(group, event) {
111
135
  if (handler.type !== "command") return false;
112
136
  return isManagedCommand(handler.command, event);
113
137
  }
114
- function classifyGrokHooksFile(contents, { relayPath, events, managedEventSets = [] }) {
138
+ function classifyGrokHooksFile(contents, { relayPath, events, managedEventSets = [], hookToolRelayPath }) {
115
139
  if (contents == null) return "absent";
140
+ if (contents === renderGrokHooksFile({
141
+ relayPath,
142
+ events,
143
+ hookToolRelayPath
144
+ })) return "current";
116
145
  if (contents === renderGrokHooksFile({
117
146
  relayPath,
118
147
  events
@@ -126,11 +155,11 @@ function classifyGrokHooksFile(contents, { relayPath, events, managedEventSets =
126
155
  if (!hasOnlyKeys(parsed, ["hooks"])) return "foreign";
127
156
  const hooksValue = parsed.hooks;
128
157
  if (hooksValue === null || hooksValue === void 0) throw new TypeError("hooks must be an object");
129
- if (typeof hooksValue !== "object" || Array.isArray(hooksValue)) return "foreign";
158
+ if (!isRecord(hooksValue)) return "foreign";
130
159
  const actualEvents = Object.keys(hooksValue);
131
160
  if (!hasOnlyKeys(hooksValue, actualEvents)) return "foreign";
132
161
  const hooks = hooksValue;
133
- if (!(hasOnlyKeys(hooks, events) || managedEventSets.some((managedEvents) => hasOnlyKeys(hooks, managedEvents)))) return "foreign";
162
+ if (![events, ...managedEventSets].some((managedEvents) => hasOnlyKeys(hooks, managedEvents) || hasOnlyKeys(hooks, [...managedEvents, "PreToolUse"]))) return "foreign";
134
163
  for (const event of actualEvents) if (!isManagedHookGroup(hooks[event], event)) return "foreign";
135
164
  return "managed-stale";
136
165
  }
@@ -174,6 +203,7 @@ function classifyAgentTitle(title, { cwdBasename = null }, vocabulary) {
174
203
  var ID = "grok";
175
204
  var COMMAND_NAME = "grok";
176
205
  var RELAY_PATH = relayPath("hook-relay");
206
+ var HOOK_TOOL_RELAY_PATH = relayPath("hook-tool-relay");
177
207
  var HOOK_EVENTS = [
178
208
  "UserPromptSubmit",
179
209
  "Stop",
@@ -210,15 +240,14 @@ function isMainSessionPayload(payload) {
210
240
  return !payload?.subagentType && !payload?.subagent_type;
211
241
  }
212
242
  function mapBackgroundTask(task) {
213
- if (!task || typeof task !== "object" || Array.isArray(task)) return task;
214
- const entry = task;
243
+ if (!isRecord(task)) return task;
215
244
  return {
216
- ...entry,
217
- ...typeof entry.agentType === "string" ? { agent_type: entry.agentType } : {}
245
+ ...task,
246
+ ...typeof task.agentType === "string" ? { agent_type: task.agentType } : {}
218
247
  };
219
248
  }
220
249
  function mapHookPayload(_event, payload) {
221
- if (!payload || typeof payload !== "object" || Array.isArray(payload)) return payload;
250
+ if (!isRecord(payload)) return payload;
222
251
  return {
223
252
  ...payload,
224
253
  ...typeof payload.subagentId === "string" ? { agent_id: payload.subagentId } : {},
@@ -234,7 +263,7 @@ function mayContributeHooks(configText) {
234
263
  } catch {
235
264
  return true;
236
265
  }
237
- if (!settings || typeof settings !== "object" || Array.isArray(settings)) return false;
266
+ if (!isRecord(settings)) return false;
238
267
  return Object.hasOwn(settings, "hooks");
239
268
  }
240
269
  function mapHookToSignal(event, payload) {
@@ -312,7 +341,7 @@ function resolveCommand({ platform = process.platform, env = process.env, homedi
312
341
  kind: "exe"
313
342
  };
314
343
  } catch (error) {
315
- 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)}`);
316
345
  return {
317
346
  path: null,
318
347
  kind: "unresolved"
@@ -359,12 +388,14 @@ var grok = {
359
388
  filePath: hooksFilePath,
360
389
  expectedContents: () => renderGrokHooksFile({
361
390
  relayPath: RELAY_PATH,
362
- events: HOOK_EVENTS
391
+ events: HOOK_EVENTS,
392
+ hookToolRelayPath: HOOK_TOOL_RELAY_PATH
363
393
  }),
364
394
  classifyContents: (contents) => classifyGrokHooksFile(contents, {
365
395
  relayPath: RELAY_PATH,
366
396
  events: HOOK_EVENTS,
367
- managedEventSets: MANAGED_HOOK_EVENT_SETS
397
+ managedEventSets: MANAGED_HOOK_EVENT_SETS,
398
+ hookToolRelayPath: HOOK_TOOL_RELAY_PATH
368
399
  }),
369
400
  projectConfigCandidates: PROJECT_CONFIG_CANDIDATES,
370
401
  mayContributeHooks
@@ -386,6 +417,7 @@ var grok = {
386
417
  mayContributeHooks,
387
418
  PROJECT_CONFIG_CANDIDATES,
388
419
  CLAUDE_COMPAT_HOOKS_ENV,
420
+ HOOK_TOOL_RELAY_PATH,
389
421
  HOOK_EVENTS,
390
422
  MANAGED_HOOK_EVENT_SETS,
391
423
  RELAY_PATH,
@@ -397,6 +429,7 @@ var grok = {
397
429
  resume: true,
398
430
  statusLine: false,
399
431
  rtk: false,
432
+ saneYolo: true,
400
433
  antiSlop: false,
401
434
  compactQuiet: false,
402
435
  skipPermissionsFlag: true,
@@ -404,4 +437,4 @@ var grok = {
404
437
  }
405
438
  };
406
439
  //#endregion
407
- export { classifyGrokHooksFile as a, buildAgentEnv as c, isSpinnerChar as i, classifyAgentTitle as n, renderGrokHooksFile as o, isBrailleChar as r, buildHookCommand as s, grok as t };
440
+ 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 };
@@ -0,0 +1,14 @@
1
+ //#region session/core/hook-command-core.ts
2
+ var SAFE_PATH_RE = /^[A-Za-z0-9_.:/\\ -]+$/;
3
+ var SAFE_EVENT_RE = /^[A-Za-z][A-Za-z0-9_-]{0,63}$/;
4
+ function buildHookCommand(relayPath, event, argvTail = []) {
5
+ const rawPath = String(relayPath);
6
+ const rawEvent = String(event);
7
+ if (!SAFE_PATH_RE.test(rawPath)) return null;
8
+ if (!SAFE_EVENT_RE.test(rawEvent)) return null;
9
+ if (argvTail.some((argument) => !/^[A-Za-z0-9_-]+$/.test(argument))) return null;
10
+ const forwardSlashedPath = rawPath.replace(/\\/g, "/");
11
+ return `node ${/\s/.test(forwardSlashedPath) ? `"${forwardSlashedPath}"` : forwardSlashedPath} ${rawEvent}${argvTail.length ? ` ${argvTail.join(" ")}` : ""}`;
12
+ }
13
+ //#endregion
14
+ export { buildHookCommand 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 };
@@ -0,0 +1,72 @@
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-BmEz2aq9.js";
3
+ import { t as buildHookCommand } from "./hook-command-core-DclEoE9e.js";
4
+ import path from "node:path";
5
+ //#region session/core/hook-tools.ts
6
+ function firstExistingFile(candidates, fsApi) {
7
+ for (const candidate of candidates) try {
8
+ if (fsApi.statSync(candidate).isFile()) return path.resolve(candidate);
9
+ } catch {}
10
+ return null;
11
+ }
12
+ function resolveRtkPath({ glimmervoidHome, platform, exec, fsApi }) {
13
+ const bundled = firstExistingFile([path.join(glimmervoidHome, "bin", "rtk.exe"), path.join(glimmervoidHome, "bin", "rtk")], fsApi);
14
+ if (bundled) return bundled;
15
+ const firstMatch = resolvePathCommandMatches("rtk", {
16
+ platform,
17
+ exec
18
+ })[0];
19
+ if (!firstMatch) return null;
20
+ return path.resolve(firstMatch);
21
+ }
22
+ function quoteCommandPath(commandPath) {
23
+ if (!/\s/.test(commandPath)) return commandPath;
24
+ return `"${commandPath}"`;
25
+ }
26
+ function toForwardSlashes(commandPath) {
27
+ return commandPath.replace(/\\/g, "/");
28
+ }
29
+ function buildRtkHookEntry(rtkPath) {
30
+ return {
31
+ matcher: "Bash",
32
+ hooks: [{
33
+ type: "command",
34
+ command: `${quoteCommandPath(toForwardSlashes(rtkPath))} hook claude`
35
+ }]
36
+ };
37
+ }
38
+ function codexGroup(command) {
39
+ if (!command) return null;
40
+ return `{matcher='Bash',hooks=[{type='command',command='${command}'}]}`;
41
+ }
42
+ var HOOK_TOOLS = {
43
+ rtk: {
44
+ capability: "rtk",
45
+ purpose: "rtk command rewriting",
46
+ env: (tool) => ({ [RTK_PATH_ENV]: tool.binPath }),
47
+ claudeEntry: (tool) => buildRtkHookEntry(tool.binPath),
48
+ codexGroup: (_tool, relayPath) => codexGroup(buildHookCommand(relayPath, "rtk"))
49
+ },
50
+ saneYolo: {
51
+ capability: "saneYolo",
52
+ purpose: "Sane YOLO catastrophic command protection",
53
+ env: (tool, homeDir) => ({
54
+ [SANE_YOLO_PATH_ENV]: tool.binPath,
55
+ ...saneYoloEnv(homeDir)
56
+ }),
57
+ claudeEntry: (tool) => ({
58
+ matcher: "Bash|PowerShell|Monitor",
59
+ hooks: [{
60
+ type: "command",
61
+ command: `node "${toForwardSlashes(tool.binPath)}" hook --coding-cli`
62
+ }]
63
+ }),
64
+ codexGroup: (tool) => codexGroup(buildHookCommand(tool.binPath, "hook", ["--codex"]))
65
+ }
66
+ };
67
+ function mergeCodexPreToolUse(groups) {
68
+ if (groups.length === 0) return [];
69
+ return ["-c", `hooks.PreToolUse=[${groups.join(",")}]`];
70
+ }
71
+ //#endregion
72
+ export { mergeCodexPreToolUse as n, resolveRtkPath as r, HOOK_TOOLS as t };
@@ -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 };