@cryptiklemur/lattice 5.10.0 → 5.11.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 (142) hide show
  1. package/dist/client/assets/{angular-html-BDIcxkJq.js → angular-html-BoFzmWT8.js} +1 -1
  2. package/dist/client/assets/{angular-ts-Bt22ouNH.js → angular-ts-DZnI8rKE.js} +1 -1
  3. package/dist/client/assets/{apl-p8qkxzEK.js → apl-DstVmncE.js} +1 -1
  4. package/dist/client/assets/{astro-CIaMc49M.js → astro-DTPCjzEx.js} +1 -1
  5. package/dist/client/assets/{blade-BR56EAMD.js → blade-6q42Ss3F.js} +1 -1
  6. package/dist/client/assets/{c-Dli0HzAh.js → c-BQDGJ-nQ.js} +1 -1
  7. package/dist/client/assets/{cobol-Cad15ECy.js → cobol-Dlh0WvsZ.js} +1 -1
  8. package/dist/client/assets/{coffee-DpyATEbF.js → coffee-DdQv129j.js} +1 -1
  9. package/dist/client/assets/{cpp-KN8_NFsf.js → cpp-DhbQJIv4.js} +1 -1
  10. package/dist/client/assets/{crystal-CuyGv0kh.js → crystal-C22kERUB.js} +1 -1
  11. package/dist/client/assets/{css-Cm3q4bxn.js → css-n31O5kHj.js} +1 -1
  12. package/dist/client/assets/{dist-BjxsMc4u.js → dist-D8okl7lw.js} +2 -2
  13. package/dist/client/assets/{edge-B6S7CSbx.js → edge-Cgwx-o_7.js} +1 -1
  14. package/dist/client/assets/{elixir-CNUy9H8T.js → elixir-DAGM2WKD.js} +1 -1
  15. package/dist/client/assets/{elm-CNfcWmb9.js → elm-BLw_7oO9.js} +1 -1
  16. package/dist/client/assets/{erb-DWebzDaI.js → erb-DCaNhYa7.js} +1 -1
  17. package/dist/client/assets/{git-rebase-B_Pt2ZBK.js → git-rebase-CNNhb8-g.js} +1 -1
  18. package/dist/client/assets/{glimmer-js-CVwoOd72.js → glimmer-js-BnZd88Wi.js} +1 -1
  19. package/dist/client/assets/{glimmer-ts-CjtFSxjz.js → glimmer-ts-DvFNbZu-.js} +1 -1
  20. package/dist/client/assets/{glsl-CP4rggAA.js → glsl-Dnrk_Jnx.js} +1 -1
  21. package/dist/client/assets/{graphql-Dbm6sAtp.js → graphql-DlWTPvCG.js} +1 -1
  22. package/dist/client/assets/{hack-Bj9y3SGf.js → hack-DQg1Ek33.js} +1 -1
  23. package/dist/client/assets/{haml-DRGrdf3f.js → haml-DSk45qIE.js} +1 -1
  24. package/dist/client/assets/{handlebars-CFKjcBMg.js → handlebars-DuLvATB2.js} +1 -1
  25. package/dist/client/assets/{html-Vcd4eHHg.js → html-D4DiUnLg.js} +1 -1
  26. package/dist/client/assets/{html-derivative-BF0YbD4L.js → html-derivative-CS5MZ6d9.js} +1 -1
  27. package/dist/client/assets/{http-CGVTa2NT.js → http-CkDncfer.js} +1 -1
  28. package/dist/client/assets/{hurl-B0GrsGqd.js → hurl-DU39oO3U.js} +1 -1
  29. package/dist/client/assets/{index-CX1tudsF.js → index-CHPfE1Zl.js} +129 -129
  30. package/dist/client/assets/index-DHUKmLLC.css +2 -0
  31. package/dist/client/assets/{java-BJHQqHsm.js → java-lntACKEu.js} +1 -1
  32. package/dist/client/assets/{javascript-CmuMsKrc.js → javascript-CxkFc6nV.js} +1 -1
  33. package/dist/client/assets/{jinja-JxCLeq1j.js → jinja-DolO2zO7.js} +1 -1
  34. package/dist/client/assets/{jison-BdgAUhei.js → jison-Cok5FPev.js} +1 -1
  35. package/dist/client/assets/{json-DtPissHL.js → json-BebuQPrq.js} +1 -1
  36. package/dist/client/assets/{jsx-DUAxxDkP.js → jsx-iLBaUyXr.js} +1 -1
  37. package/dist/client/assets/{julia-DxDlbL6e.js → julia-C5Dsc7cH.js} +1 -1
  38. package/dist/client/assets/{just-CVmAAx2R.js → just-DJYqq_9R.js} +1 -1
  39. package/dist/client/assets/{latex-uwxggTWA.js → latex-BTTYiKj1.js} +1 -1
  40. package/dist/client/assets/{liquid-xsETAJJy.js → liquid-DpAKCrOB.js} +1 -1
  41. package/dist/client/assets/{lua-B2Hh8PgD.js → lua-BZ6b1hko.js} +1 -1
  42. package/dist/client/assets/{marko-yDeGxD87.js → marko-D8VK6iGt.js} +1 -1
  43. package/dist/client/assets/{mdc-QMp4ieYR.js → mdc-Paa3XzwY.js} +1 -1
  44. package/dist/client/assets/{nginx-7gmRmcqz.js → nginx-C5k9mWtJ.js} +1 -1
  45. package/dist/client/assets/{nim-CA8SNY_7.js → nim-Dst6YSnE.js} +1 -1
  46. package/dist/client/assets/{perl-lx5nW4VC.js → perl-XhiCjgBp.js} +1 -1
  47. package/dist/client/assets/{php-DgHiW953.js → php-BcsPLnLU.js} +1 -1
  48. package/dist/client/assets/{pug-CbbB1vwb.js → pug-GLH9-eAJ.js} +1 -1
  49. package/dist/client/assets/{qml-COrzwCIh.js → qml-Cj_lJioE.js} +1 -1
  50. package/dist/client/assets/{r-Dv7pZJDH.js → r-B70aGYK5.js} +1 -1
  51. package/dist/client/assets/{razor-D2m8EDP5.js → razor-R3gub_zy.js} +1 -1
  52. package/dist/client/assets/{regexp-BXLT-jPc.js → regexp-itC0dIUJ.js} +1 -1
  53. package/dist/client/assets/{rst-_S6rrUYh.js → rst-DdyoV8E2.js} +1 -1
  54. package/dist/client/assets/{ruby-C3XO7tYY.js → ruby-BYBZsv66.js} +1 -1
  55. package/dist/client/assets/{sas-DP2k4iuN.js → sas-fqfqXqj1.js} +1 -1
  56. package/dist/client/assets/{scss-lhLFMXGn.js → scss-B-ELv6mu.js} +1 -1
  57. package/dist/client/assets/{shellscript-BYlBPHen.js → shellscript-BgB8TNw6.js} +1 -1
  58. package/dist/client/assets/{shellsession-CbVyQKWZ.js → shellsession-BLK2Dgkm.js} +1 -1
  59. package/dist/client/assets/{soy-Be8a0lHq.js → soy-C7_RmNrp.js} +1 -1
  60. package/dist/client/assets/{sql-2KxvU9YS.js → sql-AUgbUJq4.js} +1 -1
  61. package/dist/client/assets/{stata-BxlWftTS.js → stata-CIVqSIOr.js} +1 -1
  62. package/dist/client/assets/{surrealql-CJ-q86nR.js → surrealql-BzRQzc5S.js} +1 -1
  63. package/dist/client/assets/{svelte-Q1ml0OiY.js → svelte-BCIwEwtb.js} +1 -1
  64. package/dist/client/assets/{templ-BbfPZhtu.js → templ-C1hbwe4u.js} +1 -1
  65. package/dist/client/assets/{tex-Dcth4Gi6.js → tex-CI4tIsaP.js} +1 -1
  66. package/dist/client/assets/{ts-tags-BKhSOXI3.js → ts-tags-SUeikhEp.js} +1 -1
  67. package/dist/client/assets/{tsx-CS6iQ0XH.js → tsx-xkp7aIZs.js} +1 -1
  68. package/dist/client/assets/{twig-BHp31ZxS.js → twig-CGgBSAyc.js} +1 -1
  69. package/dist/client/assets/{typescript-16YJBTaO.js → typescript-O2YMTl_s.js} +1 -1
  70. package/dist/client/assets/{vue-CMKwTi4r.js → vue-DsNRxos1.js} +1 -1
  71. package/dist/client/assets/{vue-html-Dr8VUA2G.js → vue-html-CuY3t7bs.js} +1 -1
  72. package/dist/client/assets/{vue-vine-DZUqDerl.js → vue-vine-C6kSCKwY.js} +1 -1
  73. package/dist/client/assets/{xml-CBbBKKDC.js → xml-DafwzOLY.js} +1 -1
  74. package/dist/client/assets/{xsl-DWEX6PKX.js → xsl-1SGGZibr.js} +1 -1
  75. package/dist/client/assets/{yaml-DvKvvh3X.js → yaml-DSVhzmhr.js} +1 -1
  76. package/dist/client/index.html +2 -2
  77. package/dist/client/sw.js +1 -1
  78. package/dist/server/analytics/engine.js +241 -241
  79. package/dist/server/assets.js +4 -4
  80. package/dist/server/auth/passphrase.js +13 -13
  81. package/dist/server/config.js +7 -7
  82. package/dist/server/daemon.js +93 -93
  83. package/dist/server/features/brainstorm.js +42 -42
  84. package/dist/server/features/ralph-loop.js +33 -33
  85. package/dist/server/features/scheduler.js +53 -53
  86. package/dist/server/features/specs.js +54 -54
  87. package/dist/server/features/sticky-notes.js +17 -17
  88. package/dist/server/features/superpowers.js +24 -24
  89. package/dist/server/handlers/analytics.js +1 -1
  90. package/dist/server/handlers/attachment.js +32 -32
  91. package/dist/server/handlers/bookmarks.js +4 -4
  92. package/dist/server/handlers/brainstorm.js +4 -4
  93. package/dist/server/handlers/chat.js +54 -54
  94. package/dist/server/handlers/editor.js +13 -13
  95. package/dist/server/handlers/fs.js +51 -51
  96. package/dist/server/handlers/hooks.js +20 -20
  97. package/dist/server/handlers/loop.js +6 -6
  98. package/dist/server/handlers/memory.js +44 -44
  99. package/dist/server/handlers/mesh.js +60 -60
  100. package/dist/server/handlers/notes.js +7 -7
  101. package/dist/server/handlers/plugins.js +174 -174
  102. package/dist/server/handlers/project-settings.js +26 -26
  103. package/dist/server/handlers/scheduler.js +6 -6
  104. package/dist/server/handlers/session.js +24 -24
  105. package/dist/server/handlers/settings.js +21 -21
  106. package/dist/server/handlers/skills.js +91 -91
  107. package/dist/server/handlers/specs.js +51 -28
  108. package/dist/server/handlers/terminal.js +13 -13
  109. package/dist/server/handlers/themes.js +21 -21
  110. package/dist/server/handlers/update.js +17 -17
  111. package/dist/server/hooks/event_forward.sh +34 -0
  112. package/dist/server/hooks/post_tool_use.sh +26 -0
  113. package/dist/server/hooks/statusline.sh +26 -0
  114. package/dist/server/identity.js +6 -6
  115. package/dist/server/index.js +111 -111
  116. package/dist/server/logger.js +1 -1
  117. package/dist/server/mesh/connector.js +78 -78
  118. package/dist/server/mesh/crypto.js +20 -20
  119. package/dist/server/mesh/discovery.js +14 -14
  120. package/dist/server/mesh/pairing.js +30 -30
  121. package/dist/server/mesh/peers.js +10 -10
  122. package/dist/server/mesh/proxy.js +14 -14
  123. package/dist/server/mesh/session-sync.js +23 -23
  124. package/dist/server/project/bookmarks.js +11 -11
  125. package/dist/server/project/context-breakdown.js +70 -70
  126. package/dist/server/project/file-browser.js +17 -17
  127. package/dist/server/project/project-files.js +68 -68
  128. package/dist/server/project/registry.js +10 -10
  129. package/dist/server/project/sdk-bridge.js +157 -157
  130. package/dist/server/project/session.js +201 -199
  131. package/dist/server/project/terminal.js +15 -15
  132. package/dist/server/project/warmup.js +37 -37
  133. package/dist/server/push.js +11 -11
  134. package/dist/server/runtime.js +1 -1
  135. package/dist/server/tls.js +15 -15
  136. package/dist/server/tui.js +15 -15
  137. package/dist/server/update-checker.js +21 -21
  138. package/dist/server/ws/broadcast.js +18 -18
  139. package/dist/server/ws/router.js +17 -17
  140. package/dist/shared/constants.js +8 -8
  141. package/package.json +2 -2
  142. package/dist/client/assets/index-DlfI20Gn.css +0 -2
@@ -1,8 +1,8 @@
1
1
  import { join, dirname } from "node:path";
2
2
  import { fileURLToPath } from "node:url";
3
3
  import { existsSync } from "node:fs";
4
- var __dirname_local = dirname(fileURLToPath(import.meta.url));
5
- var CONTENT_TYPES = {
4
+ const __dirname_local = dirname(fileURLToPath(import.meta.url));
5
+ const CONTENT_TYPES = {
6
6
  ".html": "text/html; charset=utf-8",
7
7
  ".js": "application/javascript",
8
8
  ".css": "text/css",
@@ -28,12 +28,12 @@ export function hasEmbeddedAssets() {
28
28
  return false;
29
29
  }
30
30
  export function getClientDir() {
31
- var distPath = join(__dirname_local, "../../dist/client");
31
+ const distPath = join(__dirname_local, "../../dist/client");
32
32
  if (existsSync(distPath))
33
33
  return distPath;
34
34
  return join(__dirname_local, "../../dist/client");
35
35
  }
36
36
  export function guessContentType(path) {
37
- var ext = path.slice(path.lastIndexOf("."));
37
+ const ext = path.slice(path.lastIndexOf("."));
38
38
  return CONTENT_TYPES[ext] || "application/octet-stream";
39
39
  }
@@ -9,24 +9,24 @@ function scryptAsync(password, salt, keylen) {
9
9
  });
10
10
  });
11
11
  }
12
- var TOKEN_TTL = 86400000;
13
- var CLEANUP_INTERVAL = 600000;
14
- var activeSessions = new Map();
12
+ const TOKEN_TTL = 86400000;
13
+ const CLEANUP_INTERVAL = 600000;
14
+ const activeSessions = new Map();
15
15
  export async function hashPassphrase(passphrase) {
16
- var salt = randomBytes(16).toString("hex");
17
- var hash = (await scryptAsync(passphrase, salt, 64)).toString("hex");
16
+ const salt = randomBytes(16).toString("hex");
17
+ const hash = (await scryptAsync(passphrase, salt, 64)).toString("hex");
18
18
  return salt + ":" + hash;
19
19
  }
20
20
  export async function verifyPassphrase(passphrase, storedHash) {
21
- var parts = storedHash.split(":");
21
+ const parts = storedHash.split(":");
22
22
  if (parts.length !== 2) {
23
23
  return false;
24
24
  }
25
- var salt = parts[0];
26
- var hash = parts[1];
25
+ const salt = parts[0];
26
+ const hash = parts[1];
27
27
  try {
28
- var derived = await scryptAsync(passphrase, salt, 64);
29
- var expected = Buffer.from(hash, "hex");
28
+ const derived = await scryptAsync(passphrase, salt, 64);
29
+ const expected = Buffer.from(hash, "hex");
30
30
  if (derived.length !== expected.length) {
31
31
  return false;
32
32
  }
@@ -46,7 +46,7 @@ export function removeSession(token) {
46
46
  activeSessions.delete(token);
47
47
  }
48
48
  export function isValidSession(token) {
49
- var createdAt = activeSessions.get(token);
49
+ const createdAt = activeSessions.get(token);
50
50
  if (createdAt === undefined) {
51
51
  return false;
52
52
  }
@@ -59,8 +59,8 @@ export function isValidSession(token) {
59
59
  export function clearSessions() {
60
60
  activeSessions.clear();
61
61
  }
62
- var cleanupInterval = setInterval(function () {
63
- var now = Date.now();
62
+ const cleanupInterval = setInterval(function () {
63
+ const now = Date.now();
64
64
  activeSessions.forEach(function (createdAt, token) {
65
65
  if (now - createdAt > TOKEN_TTL) {
66
66
  activeSessions.delete(token);
@@ -2,8 +2,8 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
2
  import { homedir, hostname } from "node:os";
3
3
  import { join } from "node:path";
4
4
  import { DEFAULT_PORT, LATTICE_HOME_DIR } from "#shared";
5
- var home = process.env.LATTICE_HOME || join(homedir(), LATTICE_HOME_DIR);
6
- var cachedConfig = null;
5
+ const home = process.env.LATTICE_HOME || join(homedir(), LATTICE_HOME_DIR);
6
+ let cachedConfig = null;
7
7
  export function getLatticeHome() {
8
8
  if (!existsSync(home)) {
9
9
  mkdirSync(home, { recursive: true });
@@ -17,12 +17,12 @@ export function loadConfig() {
17
17
  if (cachedConfig) {
18
18
  return cachedConfig;
19
19
  }
20
- var configPath = getConfigPath();
20
+ const configPath = getConfigPath();
21
21
  if (!existsSync(configPath)) {
22
22
  return createDefaultConfig();
23
23
  }
24
- var raw = readFileSync(configPath, "utf-8");
25
- var parsed = JSON.parse(raw);
24
+ const raw = readFileSync(configPath, "utf-8");
25
+ const parsed = JSON.parse(raw);
26
26
  cachedConfig = {
27
27
  port: parsed.port ?? DEFAULT_PORT,
28
28
  name: parsed.name ?? hostname(),
@@ -35,7 +35,7 @@ export function loadConfig() {
35
35
  return cachedConfig;
36
36
  }
37
37
  export function saveConfig(config) {
38
- var configPath = getConfigPath();
38
+ const configPath = getConfigPath();
39
39
  writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
40
40
  cachedConfig = config;
41
41
  }
@@ -43,7 +43,7 @@ export function invalidateConfigCache() {
43
43
  cachedConfig = null;
44
44
  }
45
45
  function createDefaultConfig() {
46
- var config = {
46
+ const config = {
47
47
  port: DEFAULT_PORT,
48
48
  name: hostname(),
49
49
  tls: false,
@@ -58,21 +58,21 @@ import { initSuperpowers } from "./features/superpowers.js";
58
58
  import { cleanupClientTerminals } from "./handlers/terminal.js";
59
59
  import { cleanupClient as cleanupClientAttachments } from "./handlers/attachment.js";
60
60
  import { initPush, getVapidPublicKey, addPushSubscription } from "./push.js";
61
- var RATE_LIMIT_WINDOW = 10000;
62
- var RATE_LIMIT_MAX = 100;
63
- var clientRateLimits = new Map();
64
- var wsClientIds = new WeakMap();
61
+ const RATE_LIMIT_WINDOW = 10000;
62
+ const RATE_LIMIT_MAX = 100;
63
+ const clientRateLimits = new Map();
64
+ const wsClientIds = new WeakMap();
65
65
  function parseCookies(cookieHeader) {
66
- var map = new Map();
67
- var parts = cookieHeader.split(";");
68
- for (var i = 0; i < parts.length; i++) {
69
- var part = parts[i].trim();
70
- var eqIdx = part.indexOf("=");
66
+ const map = new Map();
67
+ const parts = cookieHeader.split(";");
68
+ for (let i = 0; i < parts.length; i++) {
69
+ const part = parts[i].trim();
70
+ const eqIdx = part.indexOf("=");
71
71
  if (eqIdx === -1) {
72
72
  continue;
73
73
  }
74
- var key = part.slice(0, eqIdx).trim();
75
- var value = part.slice(eqIdx + 1).trim();
74
+ const key = part.slice(0, eqIdx).trim();
75
+ const value = part.slice(eqIdx + 1).trim();
76
76
  map.set(key, value);
77
77
  }
78
78
  return map;
@@ -81,9 +81,9 @@ function isAuthenticatedReq(req, passphraseHash) {
81
81
  if (!passphraseHash) {
82
82
  return true;
83
83
  }
84
- var cookieHeader = req.headers.cookie || "";
85
- var cookies = parseCookies(cookieHeader);
86
- var token = cookies.get("lattice_auth");
84
+ const cookieHeader = req.headers.cookie || "";
85
+ const cookies = parseCookies(cookieHeader);
86
+ const token = cookies.get("lattice_auth");
87
87
  if (!token) {
88
88
  return false;
89
89
  }
@@ -182,9 +182,9 @@ function buildLoginPage() {
182
182
  <script>
183
183
  document.getElementById('form').addEventListener('submit', async function(e) {
184
184
  e.preventDefault();
185
- var passphrase = document.getElementById('passphrase').value;
185
+ const passphrase = document.getElementById('passphrase').value;
186
186
  try {
187
- var res = await fetch('/auth', {
187
+ const res = await fetch('/auth', {
188
188
  method: 'POST',
189
189
  headers: { 'Content-Type': 'application/json' },
190
190
  body: JSON.stringify({ passphrase: passphrase })
@@ -203,8 +203,8 @@ function buildLoginPage() {
203
203
  </html>`;
204
204
  }
205
205
  function getMimeType(filePath) {
206
- var ext = filePath.split(".").pop() || "";
207
- var mimeTypes = {
206
+ const ext = filePath.split(".").pop() || "";
207
+ const mimeTypes = {
208
208
  html: "text/html; charset=utf-8",
209
209
  js: "application/javascript",
210
210
  css: "text/css",
@@ -226,19 +226,19 @@ function handleWsOpen(ws, clientId) {
226
226
  addClient(clientId, ws);
227
227
  log.ws("Client connected: %s", clientId);
228
228
  sendTo(clientId, { type: "mesh:nodes", nodes: buildNodesMessage() });
229
- var connectConfig = loadConfig();
230
- var connectIdentity = loadOrCreateIdentity();
231
- var localProjects = connectConfig.projects.map(function (p) {
229
+ const connectConfig = loadConfig();
230
+ const connectIdentity = loadOrCreateIdentity();
231
+ const localProjects = connectConfig.projects.map(function (p) {
232
232
  return { slug: p.slug, path: p.path, title: p.title, nodeId: connectIdentity.id, nodeName: connectConfig.name, isRemote: false, ideProjectName: detectIdeProjectName(p.path), activeSessions: getActiveStreamCountForProject(p.slug) };
233
233
  });
234
- var connectRemoteProjects = getAllRemoteProjects(connectIdentity.id);
234
+ const connectRemoteProjects = getAllRemoteProjects(connectIdentity.id);
235
235
  sendTo(clientId, {
236
236
  type: "projects:list",
237
237
  projects: localProjects.concat(connectRemoteProjects),
238
238
  });
239
239
  if (isWarmupComplete()) {
240
240
  sendTo(clientId, { type: "warmup:models", models: getWarmupModels() });
241
- var accountInfo = getWarmupAccountInfo();
241
+ const accountInfo = getWarmupAccountInfo();
242
242
  if (accountInfo) {
243
243
  sendTo(clientId, {
244
244
  type: "warmup:account",
@@ -249,9 +249,9 @@ function handleWsOpen(ws, clientId) {
249
249
  apiProvider: accountInfo.apiProvider,
250
250
  });
251
251
  }
252
- var cachedRateLimits = getWarmupRateLimits();
253
- for (var rli = 0; rli < cachedRateLimits.length; rli++) {
254
- var rl = cachedRateLimits[rli];
252
+ const cachedRateLimits = getWarmupRateLimits();
253
+ for (let rli = 0; rli < cachedRateLimits.length; rli++) {
254
+ const rl = cachedRateLimits[rli];
255
255
  sendTo(clientId, {
256
256
  type: "chat:rate_limit",
257
257
  status: rl.status,
@@ -264,8 +264,8 @@ function handleWsOpen(ws, clientId) {
264
264
  });
265
265
  }
266
266
  }
267
- for (var pi = 0; pi < connectConfig.projects.length; pi++) {
268
- var proj = connectConfig.projects[pi];
267
+ for (let pi = 0; pi < connectConfig.projects.length; pi++) {
268
+ const proj = connectConfig.projects[pi];
269
269
  subscribeClientToProject(clientId, proj.slug);
270
270
  void listSessions(proj.slug, { limit: 40 }).then(function (result) {
271
271
  sendTo(clientId, {
@@ -281,11 +281,11 @@ function handleWsOpen(ws, clientId) {
281
281
  }
282
282
  }
283
283
  function handleWsMessage(ws, data) {
284
- var clientId = wsClientIds.get(ws);
284
+ const clientId = wsClientIds.get(ws);
285
285
  if (!clientId)
286
286
  return;
287
- var now = Date.now();
288
- var limit = clientRateLimits.get(clientId);
287
+ const now = Date.now();
288
+ let limit = clientRateLimits.get(clientId);
289
289
  if (!limit || now - limit.windowStart > RATE_LIMIT_WINDOW) {
290
290
  limit = { count: 0, windowStart: now };
291
291
  clientRateLimits.set(clientId, limit);
@@ -295,9 +295,9 @@ function handleWsMessage(ws, data) {
295
295
  sendTo(clientId, { type: "chat:error", message: "Rate limit exceeded, please slow down" });
296
296
  return;
297
297
  }
298
- var text = typeof data === "string" ? data : Buffer.isBuffer(data) ? data.toString() : Buffer.from(data).toString();
298
+ const text = typeof data === "string" ? data : Buffer.isBuffer(data) ? data.toString() : Buffer.from(data).toString();
299
299
  try {
300
- var msg = JSON.parse(text);
300
+ const msg = JSON.parse(text);
301
301
  routeMessage(clientId, msg);
302
302
  }
303
303
  catch (err) {
@@ -305,7 +305,7 @@ function handleWsMessage(ws, data) {
305
305
  }
306
306
  }
307
307
  function handleWsClose(ws) {
308
- var clientId = wsClientIds.get(ws);
308
+ const clientId = wsClientIds.get(ws);
309
309
  if (!clientId)
310
310
  return;
311
311
  clearActiveSession(clientId);
@@ -321,24 +321,24 @@ function handleWsClose(ws) {
321
321
  log.ws("Client disconnected: %s", clientId);
322
322
  }
323
323
  export async function startDaemon(portOverride, tlsOverride) {
324
- var config = loadConfig();
325
- var effectivePort = (portOverride && !isNaN(portOverride)) ? portOverride : config.port;
324
+ const config = loadConfig();
325
+ const effectivePort = (portOverride && !isNaN(portOverride)) ? portOverride : config.port;
326
326
  if (tlsOverride !== null && tlsOverride !== undefined) {
327
327
  config.tls = tlsOverride;
328
328
  }
329
- var identity = loadOrCreateIdentity();
329
+ const identity = loadOrCreateIdentity();
330
330
  log.server("Node: %s (%s)", config.name, identity.id);
331
331
  log.server("Home: %s", getLatticeHome());
332
- var clientDir = getClientDir();
333
- var app = express();
332
+ const clientDir = getClientDir();
333
+ const app = express();
334
334
  app.use(express.json());
335
- var authAttempts = new Map();
336
- var AUTH_RATE_LIMIT = 5;
337
- var AUTH_RATE_WINDOW = 60000;
335
+ const authAttempts = new Map();
336
+ const AUTH_RATE_LIMIT = 5;
337
+ const AUTH_RATE_WINDOW = 60000;
338
338
  app.post("/auth", async function (req, res) {
339
- var ip = req.ip || req.socket.remoteAddress || "unknown";
340
- var now = Date.now();
341
- var attempts = authAttempts.get(ip) || [];
339
+ const ip = req.ip || req.socket.remoteAddress || "unknown";
340
+ const now = Date.now();
341
+ let attempts = authAttempts.get(ip) || [];
342
342
  attempts = attempts.filter(function (t) { return now - t < AUTH_RATE_WINDOW; });
343
343
  if (attempts.length >= AUTH_RATE_LIMIT) {
344
344
  res.status(429).json({ ok: false, error: "Too many attempts. Try again later." });
@@ -346,9 +346,9 @@ export async function startDaemon(portOverride, tlsOverride) {
346
346
  }
347
347
  attempts.push(now);
348
348
  authAttempts.set(ip, attempts);
349
- var passphrase = req.body.passphrase || "";
350
- if (!config.passphraseHash || await verifyPassphrase(passphrase, config.passphraseHash)) {
351
- var token = generateSessionToken();
349
+ const passphrase = req.body.passphrase || "";
350
+ if (!config.passphraseHash || (await verifyPassphrase(passphrase, config.passphraseHash))) {
351
+ const token = generateSessionToken();
352
352
  addSession(token);
353
353
  res.setHeader("Set-Cookie", "lattice_auth=" + token + "; HttpOnly; Path=/; SameSite=Strict");
354
354
  res.json({ ok: true });
@@ -374,7 +374,7 @@ export async function startDaemon(portOverride, tlsOverride) {
374
374
  });
375
375
  app.post("/api/push-subscribe", function (req, res) {
376
376
  try {
377
- var pushBody = req.body;
377
+ const pushBody = req.body;
378
378
  addPushSubscription(pushBody);
379
379
  res.json({ ok: true });
380
380
  }
@@ -407,15 +407,15 @@ export async function startDaemon(portOverride, tlsOverride) {
407
407
  res.json(session);
408
408
  });
409
409
  app.get("/api/file", async function (req, res) {
410
- var reqFilePath = req.query.path;
410
+ const reqFilePath = req.query.path;
411
411
  if (!reqFilePath) {
412
412
  res.status(400).send("Missing path parameter");
413
413
  return;
414
414
  }
415
- var resolved = null;
416
- for (var pi = 0; pi < config.projects.length; pi++) {
417
- var projectPath = resolve(config.projects[pi].path);
418
- var candidate = resolve(projectPath, reqFilePath);
415
+ let resolved = null;
416
+ for (let pi = 0; pi < config.projects.length; pi++) {
417
+ const projectPath = resolve(config.projects[pi].path);
418
+ const candidate = resolve(projectPath, reqFilePath);
419
419
  if (candidate.startsWith(projectPath + "/") && existsSync(candidate)) {
420
420
  resolved = candidate;
421
421
  break;
@@ -425,16 +425,16 @@ export async function startDaemon(portOverride, tlsOverride) {
425
425
  res.status(404).send("File not found");
426
426
  return;
427
427
  }
428
- var fileStat = await fsStat(resolved);
428
+ const fileStat = await fsStat(resolved);
429
429
  res.setHeader("Content-Type", getMimeType(resolved));
430
430
  res.setHeader("Content-Length", fileStat.size);
431
431
  createReadStream(resolved).pipe(res);
432
432
  });
433
- var tlsOptions;
433
+ let tlsOptions;
434
434
  if (config.tls) {
435
- var certsDir = join(getLatticeHome(), "certs");
436
- var certPath = join(certsDir, "cert.pem");
437
- var keyPath = join(certsDir, "key.pem");
435
+ const certsDir = join(getLatticeHome(), "certs");
436
+ const certPath = join(certsDir, "cert.pem");
437
+ const keyPath = join(certsDir, "key.pem");
438
438
  if (existsSync(certPath) && existsSync(keyPath)) {
439
439
  try {
440
440
  tlsOptions = {
@@ -456,15 +456,15 @@ export async function startDaemon(portOverride, tlsOverride) {
456
456
  console.error("[lattice] TLS enabled but no certs found. Run 'lattice setup-tls' to generate them.");
457
457
  }
458
458
  }
459
- var protocol = tlsOptions ? "https" : "http";
460
- var httpServer = tlsOptions
459
+ const protocol = tlsOptions ? "https" : "http";
460
+ const httpServer = tlsOptions
461
461
  ? createHttpsServer(tlsOptions, app)
462
462
  : createHttpServer(app);
463
- var isDev = process.env.NODE_ENV === "development";
464
- var { loadAllThemes } = await import("./handlers/themes.js");
463
+ const isDev = process.env.NODE_ENV === "development";
464
+ const { loadAllThemes } = await import("./handlers/themes.js");
465
465
  async function getThemeInjectionScript() {
466
466
  try {
467
- var customThemes = await loadAllThemes();
467
+ const customThemes = await loadAllThemes();
468
468
  if (customThemes.length === 0)
469
469
  return "";
470
470
  return "<script>window.__LATTICE_CUSTOM_THEMES__=" + JSON.stringify(customThemes) + "</script>";
@@ -474,8 +474,8 @@ export async function startDaemon(portOverride, tlsOverride) {
474
474
  }
475
475
  }
476
476
  if (isDev) {
477
- var { createServer: createViteServer } = await import("vite");
478
- var vite = await createViteServer({
477
+ const { createServer: createViteServer } = await import("vite");
478
+ const vite = await createViteServer({
479
479
  server: {
480
480
  middlewareMode: true,
481
481
  hmr: { server: httpServer },
@@ -486,7 +486,7 @@ export async function startDaemon(portOverride, tlsOverride) {
486
486
  transformIndexHtml: {
487
487
  order: "post",
488
488
  handler: async function () {
489
- var script = await getThemeInjectionScript();
489
+ const script = await getThemeInjectionScript();
490
490
  if (!script)
491
491
  return [];
492
492
  return [{ tag: "script", attrs: {}, children: "window.__LATTICE_CUSTOM_THEMES__=" + JSON.stringify(await loadAllThemes()), injectTo: "head" }];
@@ -500,10 +500,10 @@ export async function startDaemon(portOverride, tlsOverride) {
500
500
  else if (clientDir && existsSync(clientDir)) {
501
501
  app.use(express.static(clientDir, { dotfiles: "allow" }));
502
502
  app.get("/{*path}", async function (_req, res) {
503
- var indexPath = join(clientDir, "index.html");
503
+ const indexPath = join(clientDir, "index.html");
504
504
  if (existsSync(indexPath)) {
505
- var html = readFileSync(indexPath, "utf-8");
506
- var injection = await getThemeInjectionScript();
505
+ let html = readFileSync(indexPath, "utf-8");
506
+ const injection = await getThemeInjectionScript();
507
507
  if (injection) {
508
508
  html = html.replace("</head>", injection + "</head>");
509
509
  }
@@ -515,7 +515,7 @@ export async function startDaemon(portOverride, tlsOverride) {
515
515
  }
516
516
  });
517
517
  }
518
- var wss = new WebSocketServer({
518
+ const wss = new WebSocketServer({
519
519
  noServer: true,
520
520
  perMessageDeflate: {
521
521
  zlibDeflateOptions: { level: 1 },
@@ -523,7 +523,7 @@ export async function startDaemon(portOverride, tlsOverride) {
523
523
  },
524
524
  });
525
525
  httpServer.on("upgrade", function (req, socket, head) {
526
- var url = new URL(req.url || "/", "http://localhost");
526
+ const url = new URL(req.url || "/", "http://localhost");
527
527
  if (url.pathname !== "/ws") {
528
528
  return;
529
529
  }
@@ -532,15 +532,15 @@ export async function startDaemon(portOverride, tlsOverride) {
532
532
  return;
533
533
  }
534
534
  wss.handleUpgrade(req, socket, head, function (ws) {
535
- var clientId = crypto.randomUUID();
535
+ const clientId = crypto.randomUUID();
536
536
  handleWsOpen(ws, clientId);
537
537
  ws.on("pong", function () { markClientAlive(clientId); });
538
538
  ws.on("message", function (data) { handleWsMessage(ws, data); });
539
539
  ws.on("close", function () { handleWsClose(ws); });
540
540
  });
541
541
  });
542
- var maxRetries = 10;
543
- for (var attempt = 0; attempt < maxRetries; attempt++) {
542
+ const maxRetries = 10;
543
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
544
544
  try {
545
545
  await new Promise(function (resolveP, reject) {
546
546
  httpServer.once("error", function (err) {
@@ -585,9 +585,9 @@ export async function startDaemon(portOverride, tlsOverride) {
585
585
  loadSessionHistory();
586
586
  loadSpecs();
587
587
  onSpecsReloaded(function () {
588
- var allSpecs = listSpecs();
589
- var slugs = new Set(allSpecs.map(function (s) { return s.projectSlug; }));
590
- for (var slug of slugs) {
588
+ const allSpecs = listSpecs();
589
+ const slugs = new Set(allSpecs.map(function (s) { return s.projectSlug; }));
590
+ for (const slug of slugs) {
591
591
  broadcastToProject(slug, { type: "specs:list_result", specs: listSpecs(slug) });
592
592
  }
593
593
  });
@@ -595,7 +595,7 @@ export async function startDaemon(portOverride, tlsOverride) {
595
595
  startBrainstormWatchers();
596
596
  initSuperpowers();
597
597
  startPeriodicUpdateCheck();
598
- var hookResult = installHooks();
598
+ const hookResult = installHooks();
599
599
  if (hookResult.success) {
600
600
  log.server("Claude Code hooks installed/updated");
601
601
  }
@@ -604,14 +604,14 @@ export async function startDaemon(portOverride, tlsOverride) {
604
604
  }
605
605
  loadInterruptedSessions();
606
606
  initPush();
607
- var firstProject = config.projects[0];
607
+ const firstProject = config.projects[0];
608
608
  if (firstProject) {
609
609
  void runWarmup(firstProject.path);
610
610
  }
611
- var meshDirty = true;
612
- var lastNodesJson = "";
613
- var lastProjectsJson = "";
614
- var broadcastTick = 0;
611
+ let meshDirty = true;
612
+ let lastNodesJson = "";
613
+ let lastProjectsJson = "";
614
+ let broadcastTick = 0;
615
615
  onPeerConnected(function (nodeId) {
616
616
  meshDirty = true;
617
617
  broadcast({ type: "mesh:node_online", nodeId: nodeId });
@@ -633,28 +633,28 @@ export async function startDaemon(portOverride, tlsOverride) {
633
633
  setInterval(function () {
634
634
  broadcastTick++;
635
635
  if (meshDirty) {
636
- var nodesPayload = buildNodesMessage();
637
- var nodesJson = JSON.stringify(nodesPayload);
636
+ const nodesPayload = buildNodesMessage();
637
+ const nodesJson = JSON.stringify(nodesPayload);
638
638
  if (nodesJson !== lastNodesJson) {
639
639
  lastNodesJson = nodesJson;
640
640
  broadcast({ type: "mesh:nodes", nodes: nodesPayload });
641
641
  }
642
642
  meshDirty = false;
643
643
  }
644
- var currentConfig = loadConfig();
645
- var currentIdentity = loadOrCreateIdentity();
646
- var localProjects = currentConfig.projects.map(function (p) {
644
+ const currentConfig = loadConfig();
645
+ const currentIdentity = loadOrCreateIdentity();
646
+ const localProjects = currentConfig.projects.map(function (p) {
647
647
  return { slug: p.slug, path: p.path, title: p.title, nodeId: currentIdentity.id, nodeName: currentConfig.name, isRemote: false, ideProjectName: detectIdeProjectName(p.path), activeSessions: getActiveStreamCountForProject(p.slug) };
648
648
  });
649
- var remoteProjects = getAllRemoteProjects(currentIdentity.id);
650
- var allProjects = localProjects.concat(remoteProjects);
651
- var projectsJson = JSON.stringify(allProjects);
649
+ const remoteProjects = getAllRemoteProjects(currentIdentity.id);
650
+ const allProjects = localProjects.concat(remoteProjects);
651
+ const projectsJson = JSON.stringify(allProjects);
652
652
  if (projectsJson !== lastProjectsJson) {
653
653
  lastProjectsJson = projectsJson;
654
654
  broadcast({ type: "projects:list", projects: allProjects });
655
655
  }
656
656
  if (broadcastTick % 3 === 0) {
657
- var updateInfo = getCachedUpdateInfo();
657
+ const updateInfo = getCachedUpdateInfo();
658
658
  if (updateInfo && updateInfo.updateAvailable) {
659
659
  broadcast({
660
660
  type: "update:status",