@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
@@ -2,13 +2,13 @@ import { randomUUID } from "node:crypto";
2
2
  import { spawn } from "node:child_process";
3
3
  import { join, dirname } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
- var __dirname_local = dirname(fileURLToPath(import.meta.url));
6
- var terminals = new Map();
7
- var WORKER_PATH = join(__dirname_local, "pty-worker.cjs");
8
- var NODE_MODULES_PATH = (function () {
5
+ const __dirname_local = dirname(fileURLToPath(import.meta.url));
6
+ const terminals = new Map();
7
+ const WORKER_PATH = join(__dirname_local, "pty-worker.cjs");
8
+ const NODE_MODULES_PATH = (function () {
9
9
  try {
10
- var resolved = require.resolve("node-pty");
11
- var parts = resolved.split("/node_modules/");
10
+ const resolved = require.resolve("node-pty");
11
+ const parts = resolved.split("/node_modules/");
12
12
  parts.pop();
13
13
  return parts.join("/node_modules/") + "/node_modules";
14
14
  }
@@ -17,23 +17,23 @@ var NODE_MODULES_PATH = (function () {
17
17
  }
18
18
  })();
19
19
  export function createTerminal(cwd, onData, onExit) {
20
- var termId = randomUUID();
21
- var child = spawn("node", [WORKER_PATH], {
20
+ const termId = randomUUID();
21
+ const child = spawn("node", [WORKER_PATH], {
22
22
  stdio: ["pipe", "pipe", "ignore"],
23
23
  cwd: cwd,
24
24
  env: { ...process.env, NODE_PATH: NODE_MODULES_PATH },
25
25
  });
26
- var buffer = "";
26
+ let buffer = "";
27
27
  child.stdout.setEncoding("utf-8");
28
28
  child.stdout.on("data", function (chunk) {
29
29
  buffer += chunk;
30
- var lines = buffer.split("\n");
30
+ const lines = buffer.split("\n");
31
31
  buffer = lines.pop() || "";
32
- for (var i = 0; i < lines.length; i++) {
32
+ for (let i = 0; i < lines.length; i++) {
33
33
  if (!lines[i].trim())
34
34
  continue;
35
35
  try {
36
- var msg = JSON.parse(lines[i]);
36
+ const msg = JSON.parse(lines[i]);
37
37
  if (msg.type === "data") {
38
38
  onData(msg.data);
39
39
  }
@@ -64,19 +64,19 @@ export function createTerminal(cwd, onData, onExit) {
64
64
  return termId;
65
65
  }
66
66
  export function writeToTerminal(termId, data) {
67
- var worker = terminals.get(termId);
67
+ const worker = terminals.get(termId);
68
68
  if (worker) {
69
69
  worker.send({ type: "input", data: data });
70
70
  }
71
71
  }
72
72
  export function resizeTerminal(termId, cols, rows) {
73
- var worker = terminals.get(termId);
73
+ const worker = terminals.get(termId);
74
74
  if (worker) {
75
75
  worker.send({ type: "resize", cols: cols, rows: rows });
76
76
  }
77
77
  }
78
78
  export function destroyTerminal(termId) {
79
- var worker = terminals.get(termId);
79
+ const worker = terminals.get(termId);
80
80
  if (worker) {
81
81
  worker.send({ type: "kill" });
82
82
  terminals.delete(termId);
@@ -7,7 +7,7 @@ import { execSync } from "node:child_process";
7
7
  import { existsSync, unlinkSync, rmSync } from "node:fs";
8
8
  import { join } from "node:path";
9
9
  import { homedir } from "node:os";
10
- var claudeExePath = null;
10
+ let claudeExePath = null;
11
11
  function getClaudeExecutablePath() {
12
12
  if (claudeExePath)
13
13
  return claudeExePath;
@@ -19,24 +19,24 @@ function getClaudeExecutablePath() {
19
19
  }
20
20
  return claudeExePath;
21
21
  }
22
- var KNOWN_MODELS = [
22
+ const KNOWN_MODELS = [
23
23
  { value: "default", displayName: "Default" },
24
24
  { value: "opus", displayName: "Opus" },
25
25
  { value: "sonnet", displayName: "Sonnet" },
26
26
  { value: "haiku", displayName: "Haiku" },
27
27
  ];
28
- var warmupModels = [];
29
- var warmupSlashCommands = [];
30
- var warmupAccountInfo = null;
31
- var warmupComplete = false;
32
- var warmupRateLimits = new Map();
28
+ let warmupModels = [];
29
+ let warmupSlashCommands = [];
30
+ let warmupAccountInfo = null;
31
+ let warmupComplete = false;
32
+ const warmupRateLimits = new Map();
33
33
  function ensureKnownModels(sdkModels) {
34
- var seen = new Set();
35
- for (var i = 0; i < sdkModels.length; i++) {
34
+ const seen = new Set();
35
+ for (let i = 0; i < sdkModels.length; i++) {
36
36
  seen.add(sdkModels[i].value);
37
37
  }
38
- var result = sdkModels.slice();
39
- for (var j = 0; j < KNOWN_MODELS.length; j++) {
38
+ const result = sdkModels.slice();
39
+ for (let j = 0; j < KNOWN_MODELS.length; j++) {
40
40
  if (!seen.has(KNOWN_MODELS[j].value)) {
41
41
  result.push(KNOWN_MODELS[j]);
42
42
  }
@@ -47,10 +47,10 @@ function deleteWarmupSession(cwd, sessionId) {
47
47
  if (!sessionId)
48
48
  return;
49
49
  try {
50
- var hash = cwd.replace(/\//g, "-");
51
- var projectDir = join(homedir(), ".claude", "projects", hash);
52
- var jsonlPath = join(projectDir, sessionId + ".jsonl");
53
- var dirPath = join(projectDir, sessionId);
50
+ const hash = cwd.replace(/\//g, "-");
51
+ const projectDir = join(homedir(), ".claude", "projects", hash);
52
+ const jsonlPath = join(projectDir, sessionId + ".jsonl");
53
+ const dirPath = join(projectDir, sessionId);
54
54
  if (existsSync(jsonlPath)) {
55
55
  unlinkSync(jsonlPath);
56
56
  log.server("Deleted warmup session file: %s", sessionId);
@@ -66,10 +66,10 @@ function deleteWarmupSession(cwd, sessionId) {
66
66
  export async function runWarmup(cwd) {
67
67
  log.server("SDK warmup starting (cwd: %s)...", cwd);
68
68
  try {
69
- var ac = new AbortController();
70
- var ended = false;
71
- var WARMUP_SESSION_ID = "lattice-warmup";
72
- var mq = {
69
+ const ac = new AbortController();
70
+ let ended = false;
71
+ const WARMUP_SESSION_ID = "lattice-warmup";
72
+ const mq = {
73
73
  [Symbol.asyncIterator]: function () {
74
74
  return {
75
75
  next: function () {
@@ -89,7 +89,7 @@ export async function runWarmup(cwd) {
89
89
  };
90
90
  },
91
91
  };
92
- var stream = query({
92
+ const stream = query({
93
93
  prompt: mq,
94
94
  options: {
95
95
  cwd,
@@ -103,15 +103,15 @@ export async function runWarmup(cwd) {
103
103
  },
104
104
  },
105
105
  });
106
- for await (var msg of stream) {
106
+ for await (const msg of stream) {
107
107
  if (msg.type === "system") {
108
- var sysMsg = msg;
108
+ const sysMsg = msg;
109
109
  if (sysMsg.subtype === "init") {
110
110
  if (sysMsg.slash_commands) {
111
111
  warmupSlashCommands = sysMsg.slash_commands;
112
112
  }
113
113
  try {
114
- var models = await stream.supportedModels();
114
+ const models = await stream.supportedModels();
115
115
  warmupModels = ensureKnownModels((models || []));
116
116
  }
117
117
  catch {
@@ -126,9 +126,9 @@ export async function runWarmup(cwd) {
126
126
  }
127
127
  }
128
128
  if (msg.type === "rate_limit_event") {
129
- var rlMsg = msg;
130
- var rli = rlMsg.rate_limit_info;
131
- var cacheKey = rli.rateLimitType || "default";
129
+ const rlMsg = msg;
130
+ const rli = rlMsg.rate_limit_info;
131
+ const cacheKey = rli.rateLimitType || "default";
132
132
  warmupRateLimits.set(cacheKey, {
133
133
  status: rli.status,
134
134
  utilization: rli.utilization,
@@ -182,17 +182,17 @@ export async function runWarmup(cwd) {
182
182
  }
183
183
  }
184
184
  async function warmupProjectData() {
185
- var t0 = Date.now();
186
- var config = loadConfig();
187
- var projects = config.projects;
185
+ const t0 = Date.now();
186
+ const config = loadConfig();
187
+ const projects = config.projects;
188
188
  if (projects.length === 0)
189
189
  return;
190
190
  log.server("Data warmup: pre-caching %d project(s)...", projects.length);
191
- var totalSessions = 0;
192
- var recentSessionIds = [];
193
- for (var i = 0; i < projects.length; i++) {
191
+ let totalSessions = 0;
192
+ const recentSessionIds = [];
193
+ for (let i = 0; i < projects.length; i++) {
194
194
  try {
195
- var result = await listSessions(projects[i].slug, { limit: 40 });
195
+ const result = await listSessions(projects[i].slug, { limit: 40 });
196
196
  totalSessions += result.sessions.length;
197
197
  broadcast({
198
198
  type: "session:list",
@@ -200,8 +200,8 @@ async function warmupProjectData() {
200
200
  sessions: result.sessions,
201
201
  totalCount: result.totalCount,
202
202
  });
203
- var preWarmCount = Math.min(5, result.sessions.length);
204
- for (var k = 0; k < preWarmCount; k++) {
203
+ const preWarmCount = Math.min(5, result.sessions.length);
204
+ for (let k = 0; k < preWarmCount; k++) {
205
205
  recentSessionIds.push({
206
206
  projectSlug: projects[i].slug,
207
207
  sessionId: result.sessions[k].id,
@@ -211,7 +211,7 @@ async function warmupProjectData() {
211
211
  catch { }
212
212
  }
213
213
  log.server("Data warmup: cached %d sessions across %d projects (%dms)", totalSessions, projects.length, Date.now() - t0);
214
- for (var j = 0; j < recentSessionIds.length; j++) {
214
+ for (let j = 0; j < recentSessionIds.length; j++) {
215
215
  try {
216
216
  await loadSessionHistory(recentSessionIds[j].projectSlug, recentSessionIds[j].sessionId);
217
217
  }
@@ -234,7 +234,7 @@ export function getWarmupRateLimits() {
234
234
  return Array.from(warmupRateLimits.values());
235
235
  }
236
236
  export function cacheRateLimitEntry(entry) {
237
- var key = entry.rateLimitType || "default";
237
+ const key = entry.rateLimitType || "default";
238
238
  warmupRateLimits.set(key, entry);
239
239
  }
240
240
  export function isWarmupComplete() {
@@ -3,8 +3,8 @@ import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
3
3
  import { join } from "node:path";
4
4
  import { getLatticeHome } from "./config.js";
5
5
  import { log } from "./logger.js";
6
- var vapidKeys = null;
7
- var subscriptions = new Map();
6
+ let vapidKeys = null;
7
+ const subscriptions = new Map();
8
8
  function getVapidPath() {
9
9
  return join(getLatticeHome(), "vapid.json");
10
10
  }
@@ -14,7 +14,7 @@ function getSubscriptionsPath() {
14
14
  function ensureVapidKeys() {
15
15
  if (vapidKeys)
16
16
  return vapidKeys;
17
- var vapidPath = getVapidPath();
17
+ const vapidPath = getVapidPath();
18
18
  if (existsSync(vapidPath)) {
19
19
  try {
20
20
  vapidKeys = JSON.parse(readFileSync(vapidPath, "utf-8"));
@@ -23,12 +23,12 @@ function ensureVapidKeys() {
23
23
  }
24
24
  catch { }
25
25
  }
26
- var generated = webpush.generateVAPIDKeys();
26
+ const generated = webpush.generateVAPIDKeys();
27
27
  vapidKeys = {
28
28
  publicKey: generated.publicKey,
29
29
  privateKey: generated.privateKey,
30
30
  };
31
- var dir = getLatticeHome();
31
+ const dir = getLatticeHome();
32
32
  if (!existsSync(dir)) {
33
33
  mkdirSync(dir, { recursive: true });
34
34
  }
@@ -37,26 +37,26 @@ function ensureVapidKeys() {
37
37
  return vapidKeys;
38
38
  }
39
39
  function loadSubscriptions() {
40
- var subsPath = getSubscriptionsPath();
40
+ const subsPath = getSubscriptionsPath();
41
41
  if (!existsSync(subsPath))
42
42
  return;
43
43
  try {
44
- var data = JSON.parse(readFileSync(subsPath, "utf-8"));
45
- for (var i = 0; i < data.length; i++) {
44
+ const data = JSON.parse(readFileSync(subsPath, "utf-8"));
45
+ for (let i = 0; i < data.length; i++) {
46
46
  subscriptions.set(data[i].endpoint, data[i]);
47
47
  }
48
48
  }
49
49
  catch { }
50
50
  }
51
51
  function saveSubscriptions() {
52
- var arr = [];
52
+ const arr = [];
53
53
  subscriptions.forEach(function (sub) {
54
54
  arr.push(sub);
55
55
  });
56
56
  writeFileSync(getSubscriptionsPath(), JSON.stringify(arr), "utf-8");
57
57
  }
58
58
  export function initPush() {
59
- var keys = ensureVapidKeys();
59
+ const keys = ensureVapidKeys();
60
60
  webpush.setVapidDetails("mailto:lattice@localhost", keys.publicKey, keys.privateKey);
61
61
  loadSubscriptions();
62
62
  log.server("Push notifications ready (%d subscription(s))", subscriptions.size);
@@ -75,7 +75,7 @@ export function removePushSubscription(endpoint) {
75
75
  export function sendPush(payload) {
76
76
  if (subscriptions.size === 0)
77
77
  return;
78
- var json = JSON.stringify(payload);
78
+ const json = JSON.stringify(payload);
79
79
  subscriptions.forEach(function (sub, endpoint) {
80
80
  webpush.sendNotification(sub, json).catch(function (err) {
81
81
  if (err.statusCode === 410 || err.statusCode === 404 || err.statusCode === 403) {
@@ -1 +1 @@
1
- export var IS_NPM = true;
1
+ export const IS_NPM = true;
@@ -4,7 +4,7 @@ import { spawnSync } from "node:child_process";
4
4
  import { networkInterfaces } from "node:os";
5
5
  import { getLatticeHome } from "./config.js";
6
6
  export function getCertsDir() {
7
- var certsDir = join(getLatticeHome(), "certs");
7
+ const certsDir = join(getLatticeHome(), "certs");
8
8
  if (!existsSync(certsDir)) {
9
9
  mkdirSync(certsDir, { recursive: true });
10
10
  }
@@ -12,14 +12,14 @@ export function getCertsDir() {
12
12
  }
13
13
  function isCertExpiringSoon(certPath) {
14
14
  try {
15
- var result = spawnSync("openssl", ["x509", "-enddate", "-noout", "-in", certPath], { encoding: "utf-8" });
15
+ const result = spawnSync("openssl", ["x509", "-enddate", "-noout", "-in", certPath], { encoding: "utf-8" });
16
16
  if (result.status !== 0)
17
17
  return true;
18
- var match = result.stdout.match(/notAfter=(.+)/);
18
+ const match = result.stdout.match(/notAfter=(.+)/);
19
19
  if (!match)
20
20
  return true;
21
- var expiryDate = new Date(match[1]);
22
- var daysLeft = (expiryDate.getTime() - Date.now()) / (1000 * 60 * 60 * 24);
21
+ const expiryDate = new Date(match[1]);
22
+ const daysLeft = (expiryDate.getTime() - Date.now()) / (1000 * 60 * 60 * 24);
23
23
  return daysLeft < 30;
24
24
  }
25
25
  catch {
@@ -27,28 +27,28 @@ function isCertExpiringSoon(certPath) {
27
27
  }
28
28
  }
29
29
  export function ensureCerts() {
30
- var certsDir = getCertsDir();
31
- var certPath = join(certsDir, "cert.pem");
32
- var keyPath = join(certsDir, "key.pem");
30
+ const certsDir = getCertsDir();
31
+ const certPath = join(certsDir, "cert.pem");
32
+ const keyPath = join(certsDir, "key.pem");
33
33
  if (existsSync(certPath) && existsSync(keyPath) && !isCertExpiringSoon(certPath)) {
34
34
  return { cert: certPath, key: keyPath };
35
35
  }
36
36
  console.log("[lattice] Generating self-signed TLS certificate...");
37
- var sans = ["DNS:lattice", "DNS:localhost", "IP:127.0.0.1", "IP:::1"];
38
- var ifaces = networkInterfaces();
39
- for (var name in ifaces) {
40
- var addrs = ifaces[name];
37
+ const sans = ["DNS:lattice", "DNS:localhost", "IP:127.0.0.1", "IP:::1"];
38
+ const ifaces = networkInterfaces();
39
+ for (const name in ifaces) {
40
+ const addrs = ifaces[name];
41
41
  if (!addrs)
42
42
  continue;
43
- for (var i = 0; i < addrs.length; i++) {
43
+ for (let i = 0; i < addrs.length; i++) {
44
44
  if (!addrs[i].internal) {
45
45
  sans.push("IP:" + addrs[i].address);
46
46
  }
47
47
  }
48
48
  }
49
- var extFile = join(certsDir, "openssl-san.cnf");
49
+ const extFile = join(certsDir, "openssl-san.cnf");
50
50
  writeFileSync(extFile, "[req]\ndistinguished_name=dn\nx509_extensions=v3\nprompt=no\n[dn]\nCN=lattice\n[v3]\nsubjectAltName=" + sans.join(",") + "\n");
51
- var result = spawnSync("openssl", [
51
+ const result = spawnSync("openssl", [
52
52
  "req", "-x509",
53
53
  "-newkey", "rsa:2048",
54
54
  "-keyout", keyPath,
@@ -3,7 +3,7 @@ import { existsSync } from "node:fs";
3
3
  import { join } from "node:path";
4
4
  import { getLatticeHome, loadConfig, saveConfig } from "./config.js";
5
5
  import { DEFAULT_PORT } from "#shared";
6
- var BANNER = `
6
+ const BANNER = `
7
7
  \x1b[36m██╗\x1b[0m \x1b[36m█████╗\x1b[0m \x1b[36m████████╗████████╗██╗\x1b[0m \x1b[36m██████╗\x1b[0m \x1b[36m███████╗\x1b[0m
8
8
  \x1b[36m██║\x1b[0m \x1b[36m██╔══██╗\x1b[0m\x1b[2m╚══\x1b[0m\x1b[36m██\x1b[0m\x1b[2m╔══╝╚══\x1b[0m\x1b[36m██\x1b[0m\x1b[2m╔══╝\x1b[0m\x1b[36m██║\x1b[0m\x1b[36m██╔════╝\x1b[0m\x1b[36m██╔════╝\x1b[0m
9
9
  \x1b[36m██║\x1b[0m \x1b[36m███████║\x1b[0m \x1b[36m██║\x1b[0m \x1b[36m██║\x1b[0m \x1b[36m██║██║\x1b[0m \x1b[36m█████╗\x1b[0m
@@ -15,9 +15,9 @@ export function printBanner() {
15
15
  console.log(BANNER);
16
16
  }
17
17
  export function printStatus(config, version, projectCount, sessionCount, tailscaleUrl) {
18
- var protocol = config.tls ? "https" : "http";
19
- var url = protocol + "://localhost:" + config.port;
20
- var lines = "lattice v" + version + " — " + url + "\n";
18
+ const protocol = config.tls ? "https" : "http";
19
+ const url = protocol + "://localhost:" + config.port;
20
+ let lines = "lattice v" + version + " — " + url + "\n";
21
21
  if (tailscaleUrl) {
22
22
  lines += tailscaleUrl + "\n";
23
23
  }
@@ -30,8 +30,8 @@ export function printStatus(config, version, projectCount, sessionCount, tailsca
30
30
  }
31
31
  export async function printQrCode(url) {
32
32
  try {
33
- var qrcode = await import("qrcode");
34
- var qr = await qrcode.toString(url, {
33
+ const qrcode = await import("qrcode");
34
+ const qr = await qrcode.toString(url, {
35
35
  type: "terminal",
36
36
  small: true,
37
37
  });
@@ -45,22 +45,22 @@ export async function printQrCode(url) {
45
45
  }
46
46
  }
47
47
  export async function runOnboarding() {
48
- var configPath = join(getLatticeHome(), "config.json");
49
- var isFirstRun = !existsSync(configPath);
48
+ const configPath = join(getLatticeHome(), "config.json");
49
+ const isFirstRun = !existsSync(configPath);
50
50
  if (!isFirstRun) {
51
- var config = loadConfig();
51
+ const config = loadConfig();
52
52
  return { port: config.port, passphrase: null };
53
53
  }
54
54
  printBanner();
55
55
  p.intro("Welcome to Lattice");
56
56
  p.note("Anyone with the URL gets full Claude Code access to this machine.\n" +
57
57
  "Use a private network (Tailscale, VPN) or set a passphrase.", "Security");
58
- var portResult = await p.text({
58
+ const portResult = await p.text({
59
59
  message: "Port",
60
60
  placeholder: String(DEFAULT_PORT),
61
61
  defaultValue: String(DEFAULT_PORT),
62
62
  validate: function (val) {
63
- var n = parseInt(val || "", 10);
63
+ const n = parseInt(val || "", 10);
64
64
  if (isNaN(n) || n < 1 || n > 65535)
65
65
  return "Enter a valid port (1-65535)";
66
66
  return undefined;
@@ -70,17 +70,17 @@ export async function runOnboarding() {
70
70
  p.cancel("Setup cancelled");
71
71
  process.exit(0);
72
72
  }
73
- var port = parseInt(portResult, 10);
74
- var passphraseResult = await p.password({
73
+ const port = parseInt(portResult, 10);
74
+ const passphraseResult = await p.password({
75
75
  message: "Passphrase (optional, press Enter to skip)",
76
76
  });
77
77
  if (p.isCancel(passphraseResult)) {
78
78
  p.cancel("Setup cancelled");
79
79
  process.exit(0);
80
80
  }
81
- var passphrase = passphraseResult || null;
81
+ const passphrase = passphraseResult || null;
82
82
  p.outro("Setup complete");
83
- var config = loadConfig();
83
+ const config = loadConfig();
84
84
  config.port = port;
85
85
  saveConfig(config);
86
86
  return { port, passphrase };
@@ -2,17 +2,17 @@ import { readFileSync } from "node:fs";
2
2
  import { join, dirname } from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
4
  import { log } from "./logger.js";
5
- var __dirname_local = dirname(fileURLToPath(import.meta.url));
6
- var PKG_NAME = "@cryptiklemur/lattice";
7
- var GITHUB_REPO = "cryptiklemur/lattice";
8
- var CHECK_INTERVAL_MS = 3600000;
9
- var cached = null;
10
- var checking = false;
5
+ const __dirname_local = dirname(fileURLToPath(import.meta.url));
6
+ const PKG_NAME = "@cryptiklemur/lattice";
7
+ const GITHUB_REPO = "cryptiklemur/lattice";
8
+ const CHECK_INTERVAL_MS = 3600000;
9
+ let cached = null;
10
+ let checking = false;
11
11
  function getCurrentVersion() {
12
12
  if (process.env.LATTICE_VERSION)
13
13
  return process.env.LATTICE_VERSION;
14
14
  try {
15
- var pkg = JSON.parse(readFileSync(join(__dirname_local, "../../package.json"), "utf-8"));
15
+ const pkg = JSON.parse(readFileSync(join(__dirname_local, "../../package.json"), "utf-8"));
16
16
  return pkg.version || "0.0.0";
17
17
  }
18
18
  catch {
@@ -22,11 +22,11 @@ function getCurrentVersion() {
22
22
  function compareVersions(a, b) {
23
23
  if (!a || !b || typeof a !== "string" || typeof b !== "string")
24
24
  return 0;
25
- var pa = a.replace(/^v/, "").split(".").map(Number);
26
- var pb = b.replace(/^v/, "").split(".").map(Number);
27
- for (var i = 0; i < 3; i++) {
28
- var va = pa[i] || 0;
29
- var vb = pb[i] || 0;
25
+ const pa = a.replace(/^v/, "").split(".").map(Number);
26
+ const pb = b.replace(/^v/, "").split(".").map(Number);
27
+ for (let i = 0; i < 3; i++) {
28
+ const va = pa[i] || 0;
29
+ const vb = pb[i] || 0;
30
30
  if (va !== vb)
31
31
  return va - vb;
32
32
  }
@@ -36,7 +36,7 @@ export function getInstallMode() {
36
36
  return "npm";
37
37
  }
38
38
  async function checkGitHub(currentVersion) {
39
- var res = await fetch("https://api.github.com/repos/" + GITHUB_REPO + "/releases/latest", {
39
+ const res = await fetch("https://api.github.com/repos/" + GITHUB_REPO + "/releases/latest", {
40
40
  headers: { "Accept": "application/vnd.github.v3+json" },
41
41
  signal: AbortSignal.timeout(10000),
42
42
  });
@@ -44,9 +44,9 @@ async function checkGitHub(currentVersion) {
44
44
  console.error("[lattice] GitHub update check failed: HTTP " + res.status);
45
45
  return { currentVersion, latestVersion: null, updateAvailable: false, lastCheckedAt: Date.now(), releaseUrl: null, installMode: "binary" };
46
46
  }
47
- var data = await res.json();
48
- var latestVersion = data.tag_name ? data.tag_name.replace(/^v/, "") : null;
49
- var updateAvailable = latestVersion !== null && compareVersions(latestVersion, currentVersion) > 0;
47
+ const data = await res.json();
48
+ const latestVersion = data.tag_name ? data.tag_name.replace(/^v/, "") : null;
49
+ const updateAvailable = latestVersion !== null && compareVersions(latestVersion, currentVersion) > 0;
50
50
  return {
51
51
  currentVersion,
52
52
  latestVersion,
@@ -57,7 +57,7 @@ async function checkGitHub(currentVersion) {
57
57
  };
58
58
  }
59
59
  async function checkNpm(currentVersion) {
60
- var res = await fetch("https://registry.npmjs.org/" + PKG_NAME + "/latest", {
60
+ const res = await fetch("https://registry.npmjs.org/" + PKG_NAME + "/latest", {
61
61
  headers: { "Accept": "application/json" },
62
62
  signal: AbortSignal.timeout(10000),
63
63
  });
@@ -65,9 +65,9 @@ async function checkNpm(currentVersion) {
65
65
  console.error("[lattice] npm update check failed: HTTP " + res.status);
66
66
  return { currentVersion, latestVersion: null, updateAvailable: false, lastCheckedAt: Date.now(), releaseUrl: null, installMode: "npm" };
67
67
  }
68
- var data = await res.json();
69
- var latestVersion = data.version ?? null;
70
- var updateAvailable = latestVersion !== null && compareVersions(latestVersion, currentVersion) > 0;
68
+ const data = await res.json();
69
+ const latestVersion = data.version ?? null;
70
+ const updateAvailable = latestVersion !== null && compareVersions(latestVersion, currentVersion) > 0;
71
71
  return {
72
72
  currentVersion,
73
73
  latestVersion,
@@ -78,7 +78,7 @@ async function checkNpm(currentVersion) {
78
78
  };
79
79
  }
80
80
  export async function checkForUpdate(force = false) {
81
- var currentVersion = getCurrentVersion();
81
+ const currentVersion = getCurrentVersion();
82
82
  if (!force && cached && Date.now() - cached.lastCheckedAt < CHECK_INTERVAL_MS) {
83
83
  return cached;
84
84
  }
@@ -1,8 +1,8 @@
1
1
  import { log } from "../logger.js";
2
- var clients = new Map();
3
- var clientAlive = new Map();
4
- var clientProjects = new Map();
5
- var virtualSendHandlers = new Map();
2
+ const clients = new Map();
3
+ const clientAlive = new Map();
4
+ const clientProjects = new Map();
5
+ const virtualSendHandlers = new Map();
6
6
  export function registerVirtualClient(id, handler) {
7
7
  virtualSendHandlers.set(id, handler);
8
8
  }
@@ -22,7 +22,7 @@ export function markClientAlive(id) {
22
22
  clientAlive.set(id, true);
23
23
  }
24
24
  export function subscribeClientToProject(clientId, projectSlug) {
25
- var projects = clientProjects.get(clientId);
25
+ let projects = clientProjects.get(clientId);
26
26
  if (!projects) {
27
27
  projects = new Set();
28
28
  clientProjects.set(clientId, projects);
@@ -30,10 +30,10 @@ export function subscribeClientToProject(clientId, projectSlug) {
30
30
  projects.add(projectSlug);
31
31
  }
32
32
  export function broadcastToProject(projectSlug, message, excludeId) {
33
- var text = JSON.stringify(message);
34
- for (var [id, ws] of clients) {
33
+ const text = JSON.stringify(message);
34
+ for (const [id, ws] of clients) {
35
35
  if (id !== excludeId && ws.readyState === ws.OPEN) {
36
- var projects = clientProjects.get(id);
36
+ const projects = clientProjects.get(id);
37
37
  if (projects && projects.has(projectSlug)) {
38
38
  ws.send(text);
39
39
  }
@@ -41,20 +41,20 @@ export function broadcastToProject(projectSlug, message, excludeId) {
41
41
  }
42
42
  }
43
43
  export function broadcast(message, excludeId) {
44
- var text = JSON.stringify(message);
45
- for (var [id, ws] of clients) {
44
+ const text = JSON.stringify(message);
45
+ for (const [id, ws] of clients) {
46
46
  if (id !== excludeId && ws.readyState === ws.OPEN) {
47
47
  ws.send(text);
48
48
  }
49
49
  }
50
50
  }
51
51
  export function sendTo(id, message) {
52
- var ws = clients.get(id);
52
+ const ws = clients.get(id);
53
53
  if (ws && ws.readyState === ws.OPEN) {
54
54
  ws.send(JSON.stringify(message));
55
55
  return;
56
56
  }
57
- var virtualHandler = virtualSendHandlers.get(id);
57
+ const virtualHandler = virtualSendHandlers.get(id);
58
58
  if (virtualHandler) {
59
59
  virtualHandler(message);
60
60
  return;
@@ -70,21 +70,21 @@ export function getClientCount() {
70
70
  return clients.size;
71
71
  }
72
72
  export function closeAllClients() {
73
- for (var [, ws] of clients) {
73
+ for (const [, ws] of clients) {
74
74
  ws.close();
75
75
  }
76
76
  clients.clear();
77
77
  clientAlive.clear();
78
78
  clientProjects.clear();
79
79
  }
80
- var HEARTBEAT_INTERVAL_MS = 30000;
81
- var heartbeatTimer = null;
80
+ const HEARTBEAT_INTERVAL_MS = 30000;
81
+ let heartbeatTimer = null;
82
82
  export function startHeartbeat(onDead) {
83
83
  if (heartbeatTimer)
84
84
  return;
85
85
  heartbeatTimer = setInterval(function () {
86
- var dead = [];
87
- for (var [id, ws] of clients) {
86
+ const dead = [];
87
+ for (const [id, ws] of clients) {
88
88
  if (!clientAlive.get(id)) {
89
89
  dead.push([id, ws]);
90
90
  continue;
@@ -94,7 +94,7 @@ export function startHeartbeat(onDead) {
94
94
  ws.ping();
95
95
  }
96
96
  }
97
- for (var i = 0; i < dead.length; i++) {
97
+ for (let i = 0; i < dead.length; i++) {
98
98
  log.ws("Heartbeat: client %s unresponsive, terminating", dead[i][0].slice(0, 8));
99
99
  onDead(dead[i][0], dead[i][1]);
100
100
  dead[i][1].terminate();