@cryptiklemur/lattice 5.5.0 → 5.6.1

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 (87) hide show
  1. package/dist/client/assets/{angular-html-Bmjy4gNc.js → angular-html-C161H-h4.js} +1 -1
  2. package/dist/client/assets/{angular-ts-10l13C4C.js → angular-ts-UejdQitf.js} +1 -1
  3. package/dist/client/assets/{apl--Bn7yH0T.js → apl-D2krRhBG.js} +1 -1
  4. package/dist/client/assets/{astro-C8P9TQkP.js → astro-DVKZfvzE.js} +1 -1
  5. package/dist/client/assets/{blade-DQiHYnIS.js → blade-Dmjp9O4d.js} +1 -1
  6. package/dist/client/assets/{c-BFny-WnE.js → c-BZ6IuiPf.js} +1 -1
  7. package/dist/client/assets/{cobol-hGEexMYH.js → cobol-BF2qiDD7.js} +1 -1
  8. package/dist/client/assets/{coffee-j3W4ZALV.js → coffee-DNKdKLDa.js} +1 -1
  9. package/dist/client/assets/{cpp-DquWJNps.js → cpp-D4I7nho0.js} +1 -1
  10. package/dist/client/assets/{crystal-CWL31dIV.js → crystal-DvbJGa3F.js} +1 -1
  11. package/dist/client/assets/{css-Di4GSq8V.js → css-k5EbtGj0.js} +1 -1
  12. package/dist/client/assets/{dist-CaJdL3Va.js → dist-J-paO_Ua.js} +2 -2
  13. package/dist/client/assets/{edge-rK4d050l.js → edge-DaXUGhsZ.js} +1 -1
  14. package/dist/client/assets/{elixir-BMFKKu5z.js → elixir-D0XiwLVl.js} +1 -1
  15. package/dist/client/assets/{elm-B0QVlW3-.js → elm-3fMSNcgt.js} +1 -1
  16. package/dist/client/assets/{erb-C9w9QbhL.js → erb-D2Fp4TPk.js} +1 -1
  17. package/dist/client/assets/{git-rebase-FaylS7Vl.js → git-rebase-BH552817.js} +1 -1
  18. package/dist/client/assets/{glimmer-js-Bi2XnbHi.js → glimmer-js-CqOUOgp8.js} +1 -1
  19. package/dist/client/assets/{glimmer-ts-DOdxK6E6.js → glimmer-ts-D68GJgFk.js} +1 -1
  20. package/dist/client/assets/{glsl-BiGDIGbZ.js → glsl-Cknt_egz.js} +1 -1
  21. package/dist/client/assets/{graphql-CZJB8KIP.js → graphql-Cb9Y6gmd.js} +1 -1
  22. package/dist/client/assets/{hack-CNGYBFqH.js → hack-BFrZLTBg.js} +1 -1
  23. package/dist/client/assets/{haml-pf3Zh5MH.js → haml-p0cxTqbc.js} +1 -1
  24. package/dist/client/assets/{handlebars-BsQwsvPC.js → handlebars-CpjLDdsz.js} +1 -1
  25. package/dist/client/assets/{html-Dj4Hvv69.js → html-CCYH7wc6.js} +1 -1
  26. package/dist/client/assets/{html-derivative-CE7dQ_mI.js → html-derivative-DEphIJN1.js} +1 -1
  27. package/dist/client/assets/{http-DjOuMI1u.js → http-2GQCPOno.js} +1 -1
  28. package/dist/client/assets/{hurl-BH_MQrQo.js → hurl-C5thponb.js} +1 -1
  29. package/dist/client/assets/{index-DA8ZBSYW.js → index-E1WCz9rn.js} +107 -106
  30. package/dist/client/assets/{java-CnpykAva.js → java-aCAp8IF1.js} +1 -1
  31. package/dist/client/assets/{javascript-BbqQ1sQM.js → javascript-CL_Iy9n4.js} +1 -1
  32. package/dist/client/assets/{jinja-DddpvWwk.js → jinja-Py1l-RL7.js} +1 -1
  33. package/dist/client/assets/{jison-Bd3G2n4x.js → jison-DH8vzrgr.js} +1 -1
  34. package/dist/client/assets/{json-F0eTFQKP.js → json-B3-MRuLs.js} +1 -1
  35. package/dist/client/assets/{jsx-B-wB5nUs.js → jsx-A_kWOEh1.js} +1 -1
  36. package/dist/client/assets/{julia-9Lfz4b5s.js → julia-D1qOHioL.js} +1 -1
  37. package/dist/client/assets/{just-BVE1sBJx.js → just-Cp2rqK4b.js} +1 -1
  38. package/dist/client/assets/{latex-SF3xMSWG.js → latex-BtOQEyF3.js} +1 -1
  39. package/dist/client/assets/{liquid-CLkbZ0ZV.js → liquid-DJbfjPLK.js} +1 -1
  40. package/dist/client/assets/{lua-DNph6TL8.js → lua-GmcXPR1B.js} +1 -1
  41. package/dist/client/assets/{marko-CGqdEtbF.js → marko-_792ZFlg.js} +1 -1
  42. package/dist/client/assets/{mdc-BLpzcq82.js → mdc-CD8aKOmr.js} +1 -1
  43. package/dist/client/assets/{nginx-s7ciyZD1.js → nginx-CbcVooTf.js} +1 -1
  44. package/dist/client/assets/{nim-C4FeZI3R.js → nim-C_9nhkxr.js} +1 -1
  45. package/dist/client/assets/{perl-GDfD5AIi.js → perl-BCX7fFX1.js} +1 -1
  46. package/dist/client/assets/{php-CusAuy6y.js → php-DD4kvY2Z.js} +1 -1
  47. package/dist/client/assets/{pug-DCKuXO7x.js → pug-Cm2QOZay.js} +1 -1
  48. package/dist/client/assets/{qml-rp1ZHoeo.js → qml-OUZ1t0j7.js} +1 -1
  49. package/dist/client/assets/{r-CwNbYaVb.js → r-DFfZp_OL.js} +1 -1
  50. package/dist/client/assets/{razor-CinY5yf4.js → razor-BuydI9-z.js} +1 -1
  51. package/dist/client/assets/{regexp-CxVI4rKV.js → regexp-BqwfzS-e.js} +1 -1
  52. package/dist/client/assets/{rst-BrBmBgUr.js → rst-CUEfE6pZ.js} +1 -1
  53. package/dist/client/assets/{ruby-BzNCpRio.js → ruby-8x8dx_pO.js} +1 -1
  54. package/dist/client/assets/{sas-B4IAap7m.js → sas-BSAoQexz.js} +1 -1
  55. package/dist/client/assets/{scss-eNAsUEA1.js → scss-Dixbfurt.js} +1 -1
  56. package/dist/client/assets/{shellscript-BwH0aChW.js → shellscript-DMo0DXSS.js} +1 -1
  57. package/dist/client/assets/{shellsession-B5ibJBbh.js → shellsession-BqlA3Xqy.js} +1 -1
  58. package/dist/client/assets/{soy-BrqReQP3.js → soy-1CvxH5kF.js} +1 -1
  59. package/dist/client/assets/{sql-KIDgTieS.js → sql-DwXIPc_O.js} +1 -1
  60. package/dist/client/assets/{stata-D6yim7Rr.js → stata-Cx86EID2.js} +1 -1
  61. package/dist/client/assets/{surrealql-C51iMPEA.js → surrealql-Cw-uWD-Y.js} +1 -1
  62. package/dist/client/assets/{svelte-DYs5QSVt.js → svelte-sEvqGFi5.js} +1 -1
  63. package/dist/client/assets/{templ-CLDdaEXl.js → templ-Bz8ry2Df.js} +1 -1
  64. package/dist/client/assets/{tex-D16HBCoj.js → tex-0h5ZXQmm.js} +1 -1
  65. package/dist/client/assets/{ts-tags-DTcB2bBd.js → ts-tags-DtGMDbRm.js} +1 -1
  66. package/dist/client/assets/{tsx-BxGfVt8a.js → tsx-CYAi0Kbl.js} +1 -1
  67. package/dist/client/assets/{twig-BUC08jwe.js → twig-DXmk5qdI.js} +1 -1
  68. package/dist/client/assets/{typescript-CuPGT2MR.js → typescript-Dxx5i3xN.js} +1 -1
  69. package/dist/client/assets/{vue-_ip8-SIk.js → vue-BOO_0xW-.js} +1 -1
  70. package/dist/client/assets/{vue-html-D-I9-U-x.js → vue-html-DzIwXjLx.js} +1 -1
  71. package/dist/client/assets/{vue-vine-7AONB1tt.js → vue-vine-BQ-DHKIR.js} +1 -1
  72. package/dist/client/assets/{xml-D2ZUDsPU.js → xml-DvKkhtkD.js} +1 -1
  73. package/dist/client/assets/{xsl-GlFKKlLy.js → xsl-DmziSW-K.js} +1 -1
  74. package/dist/client/assets/{yaml-BnuTxWck.js → yaml-ClkG7vzs.js} +1 -1
  75. package/dist/client/index.html +1 -1
  76. package/dist/client/sw.js +1 -1
  77. package/dist/server/daemon.js +60 -27
  78. package/dist/server/handlers/attachment.js +66 -29
  79. package/dist/server/handlers/fs.js +58 -72
  80. package/dist/server/handlers/memory.js +37 -52
  81. package/dist/server/handlers/mesh.js +4 -1
  82. package/dist/server/handlers/session.js +38 -57
  83. package/dist/server/mesh/connector.js +85 -1
  84. package/dist/server/project/file-browser.js +14 -14
  85. package/dist/server/project/session.js +7 -4
  86. package/dist/server/ws/broadcast.js +60 -0
  87. package/package.json +1 -1
@@ -1,14 +1,16 @@
1
1
  import { registerHandler } from "../ws/router.js";
2
- import { sendTo, broadcast } from "../ws/broadcast.js";
2
+ import { sendTo, subscribeClientToProject, broadcastToProject } from "../ws/broadcast.js";
3
3
  import { getProjectBySlug } from "../project/registry.js";
4
4
  import { listDirectory, readFile, writeFile } from "../project/file-browser.js";
5
- import { readdirSync, existsSync, readFileSync, statSync } from "node:fs";
5
+ import { readdir, readFile as fsReadFile, stat } from "node:fs/promises";
6
+ import { existsSync } from "node:fs";
6
7
  import { join } from "node:path";
7
8
  import { homedir } from "node:os";
8
9
  import { loadConfig } from "../config.js";
9
10
  var activeProjectByClient = new Map();
10
11
  export function setActiveProject(clientId, projectSlug) {
11
12
  activeProjectByClient.set(clientId, projectSlug);
13
+ subscribeClientToProject(clientId, projectSlug);
12
14
  }
13
15
  export function clearActiveProject(clientId) {
14
16
  activeProjectByClient.delete(clientId);
@@ -16,7 +18,7 @@ export function clearActiveProject(clientId) {
16
18
  export function getActiveProjectForClient(clientId) {
17
19
  return activeProjectByClient.get(clientId);
18
20
  }
19
- registerHandler("fs", function (clientId, message) {
21
+ registerHandler("fs", async function (clientId, message) {
20
22
  if (message.type === "fs:list") {
21
23
  var listMsg = message;
22
24
  var projectSlug = activeProjectByClient.get(clientId) || listMsg.projectSlug;
@@ -33,7 +35,7 @@ registerHandler("fs", function (clientId, message) {
33
35
  sendTo(clientId, { type: "chat:error", message: "Project not found: " + projectSlug });
34
36
  return;
35
37
  }
36
- var entries = listDirectory(project.path, listMsg.path);
38
+ var entries = await listDirectory(project.path, listMsg.path);
37
39
  sendTo(clientId, { type: "fs:list_result", path: listMsg.path, entries });
38
40
  return;
39
41
  }
@@ -53,7 +55,7 @@ registerHandler("fs", function (clientId, message) {
53
55
  sendTo(clientId, { type: "chat:error", message: "Project not found: " + projectSlugRead });
54
56
  return;
55
57
  }
56
- var content = readFile(projectRead.path, readMsg.path);
58
+ var content = await readFile(projectRead.path, readMsg.path);
57
59
  if (content === null) {
58
60
  sendTo(clientId, { type: "chat:error", message: "Cannot read file: " + readMsg.path });
59
61
  return;
@@ -73,12 +75,12 @@ registerHandler("fs", function (clientId, message) {
73
75
  sendTo(clientId, { type: "chat:error", message: "Project not found: " + projectSlugWrite });
74
76
  return;
75
77
  }
76
- var ok = writeFile(projectWrite.path, writeMsg.path, writeMsg.content);
78
+ var ok = await writeFile(projectWrite.path, writeMsg.path, writeMsg.content);
77
79
  if (!ok) {
78
80
  sendTo(clientId, { type: "chat:error", message: "Cannot write file: " + writeMsg.path });
79
81
  return;
80
82
  }
81
- broadcast({ type: "fs:changed", path: writeMsg.path });
83
+ broadcastToProject(projectSlugWrite, { type: "fs:changed", path: writeMsg.path });
82
84
  return;
83
85
  }
84
86
  });
@@ -89,59 +91,49 @@ function resolvePath(path) {
89
91
  return join(homedir(), path.slice(2));
90
92
  return path;
91
93
  }
92
- function detectProjectName(dirPath) {
94
+ async function detectProjectName(dirPath) {
93
95
  try {
94
96
  var pkgPath = join(dirPath, "package.json");
95
- if (existsSync(pkgPath)) {
96
- var pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
97
- if (pkg.name)
98
- return pkg.name;
99
- }
97
+ var pkg = JSON.parse(await fsReadFile(pkgPath, "utf-8"));
98
+ if (pkg.name)
99
+ return pkg.name;
100
100
  }
101
101
  catch { }
102
102
  try {
103
103
  var cargoPath = join(dirPath, "Cargo.toml");
104
- if (existsSync(cargoPath)) {
105
- var cargo = readFileSync(cargoPath, "utf-8");
106
- var cargoMatch = cargo.match(/\[package\][\s\S]*?name\s*=\s*"([^"]+)"/);
107
- if (cargoMatch)
108
- return cargoMatch[1];
109
- }
104
+ var cargo = await fsReadFile(cargoPath, "utf-8");
105
+ var cargoMatch = cargo.match(/\[package\][\s\S]*?name\s*=\s*"([^"]+)"/);
106
+ if (cargoMatch)
107
+ return cargoMatch[1];
110
108
  }
111
109
  catch { }
112
110
  try {
113
111
  var composerPath = join(dirPath, "composer.json");
114
- if (existsSync(composerPath)) {
115
- var composer = JSON.parse(readFileSync(composerPath, "utf-8"));
116
- if (composer.name)
117
- return composer.name;
118
- }
112
+ var composer = JSON.parse(await fsReadFile(composerPath, "utf-8"));
113
+ if (composer.name)
114
+ return composer.name;
119
115
  }
120
116
  catch { }
121
117
  try {
122
118
  var pyprojectPath = join(dirPath, "pyproject.toml");
123
- if (existsSync(pyprojectPath)) {
124
- var pyproject = readFileSync(pyprojectPath, "utf-8");
125
- var pyMatch = pyproject.match(/\[project\][\s\S]*?name\s*=\s*"([^"]+)"/);
126
- if (pyMatch)
127
- return pyMatch[1];
128
- }
119
+ var pyproject = await fsReadFile(pyprojectPath, "utf-8");
120
+ var pyMatch = pyproject.match(/\[project\][\s\S]*?name\s*=\s*"([^"]+)"/);
121
+ if (pyMatch)
122
+ return pyMatch[1];
129
123
  }
130
124
  catch { }
131
125
  try {
132
126
  var goModPath = join(dirPath, "go.mod");
133
- if (existsSync(goModPath)) {
134
- var goMod = readFileSync(goModPath, "utf-8");
135
- var goMatch = goMod.match(/^module\s+(\S+)/m);
136
- if (goMatch) {
137
- var parts = goMatch[1].split("/");
138
- return parts[parts.length - 1];
139
- }
127
+ var goMod = await fsReadFile(goModPath, "utf-8");
128
+ var goMatch = goMod.match(/^module\s+(\S+)/m);
129
+ if (goMatch) {
130
+ var parts = goMatch[1].split("/");
131
+ return parts[parts.length - 1];
140
132
  }
141
133
  }
142
134
  catch { }
143
135
  try {
144
- var entries = readdirSync(dirPath);
136
+ var entries = await readdir(dirPath);
145
137
  for (var i = 0; i < entries.length; i++) {
146
138
  if (entries[i].endsWith(".sln") || entries[i].endsWith(".csproj")) {
147
139
  return entries[i].replace(/\.[^.]+$/, "");
@@ -151,18 +143,14 @@ function detectProjectName(dirPath) {
151
143
  catch { }
152
144
  return null;
153
145
  }
154
- registerHandler("browse", function (clientId, message) {
146
+ registerHandler("browse", async function (clientId, message) {
155
147
  if (message.type === "browse:list") {
156
148
  var browseMsg = message;
157
149
  var resolvedPath = resolvePath(browseMsg.path);
158
150
  var home = homedir();
159
- if (!existsSync(resolvedPath)) {
160
- sendTo(clientId, { type: "browse:list_result", path: resolvedPath, homedir: home, entries: [] });
161
- return;
162
- }
163
151
  try {
164
- var stat = statSync(resolvedPath);
165
- if (!stat.isDirectory()) {
152
+ var pathStat = await stat(resolvedPath);
153
+ if (!pathStat.isDirectory()) {
166
154
  sendTo(clientId, { type: "browse:list_result", path: resolvedPath, homedir: home, entries: [] });
167
155
  return;
168
156
  }
@@ -172,7 +160,7 @@ registerHandler("browse", function (clientId, message) {
172
160
  return;
173
161
  }
174
162
  try {
175
- var dirEntries = readdirSync(resolvedPath, { withFileTypes: true });
163
+ var dirEntries = await readdir(resolvedPath, { withFileTypes: true });
176
164
  var results = [];
177
165
  for (var i = 0; i < dirEntries.length; i++) {
178
166
  var entry = dirEntries[i];
@@ -180,7 +168,7 @@ registerHandler("browse", function (clientId, message) {
180
168
  continue;
181
169
  var entryPath = join(resolvedPath, entry.name);
182
170
  var hasClaudeMd = existsSync(join(entryPath, "CLAUDE.md"));
183
- var projectName = detectProjectName(entryPath);
171
+ var projectName = await detectProjectName(entryPath);
184
172
  results.push({
185
173
  name: entry.name,
186
174
  path: entryPath,
@@ -201,35 +189,33 @@ registerHandler("browse", function (clientId, message) {
201
189
  var config = loadConfig();
202
190
  var existingPaths = new Set(config.projects.map(function (p) { return p.path; }));
203
191
  var suggestions = [];
204
- if (existsSync(claudeProjectsDir)) {
205
- try {
206
- var hashDirs = readdirSync(claudeProjectsDir);
207
- for (var i = 0; i < hashDirs.length; i++) {
208
- var hashDir = hashDirs[i];
209
- var candidatePath = "/" + hashDir.slice(1).replace(/-/g, "/");
210
- if (!existsSync(candidatePath))
211
- continue;
212
- if (existingPaths.has(candidatePath))
213
- continue;
214
- try {
215
- var stat = statSync(candidatePath);
216
- if (!stat.isDirectory())
217
- continue;
218
- }
219
- catch {
192
+ try {
193
+ var hashDirs = await readdir(claudeProjectsDir);
194
+ for (var i = 0; i < hashDirs.length; i++) {
195
+ var hashDir = hashDirs[i];
196
+ var candidatePath = "/" + hashDir.slice(1).replace(/-/g, "/");
197
+ if (!existsSync(candidatePath))
198
+ continue;
199
+ if (existingPaths.has(candidatePath))
200
+ continue;
201
+ try {
202
+ var candidateStat = await stat(candidatePath);
203
+ if (!candidateStat.isDirectory())
220
204
  continue;
221
- }
222
- var hasClaudeMd = existsSync(join(candidatePath, "CLAUDE.md"));
223
- var name = candidatePath.split("/").pop() || hashDir;
224
- suggestions.push({
225
- path: candidatePath,
226
- name: name,
227
- hasClaudeMd: hasClaudeMd,
228
- });
229
205
  }
206
+ catch {
207
+ continue;
208
+ }
209
+ var hasClaudeMd = existsSync(join(candidatePath, "CLAUDE.md"));
210
+ var name = candidatePath.split("/").pop() || hashDir;
211
+ suggestions.push({
212
+ path: candidatePath,
213
+ name: name,
214
+ hasClaudeMd: hasClaudeMd,
215
+ });
230
216
  }
231
- catch { }
232
217
  }
218
+ catch { }
233
219
  suggestions.sort(function (a, b) { return a.name.localeCompare(b.name); });
234
220
  sendTo(clientId, { type: "browse:suggestions_result", suggestions: suggestions });
235
221
  return;
@@ -1,4 +1,5 @@
1
- import { existsSync, readFileSync, writeFileSync, readdirSync, unlinkSync, mkdirSync } from "node:fs";
1
+ import { readdir, readFile, writeFile, unlink, mkdir } from "node:fs/promises";
2
+ import { existsSync } from "node:fs";
2
3
  import { join } from "node:path";
3
4
  import { homedir } from "node:os";
4
5
  import { registerHandler } from "../ws/router.js";
@@ -38,16 +39,16 @@ function parseFrontmatter(content) {
38
39
  }
39
40
  return { name, description, type };
40
41
  }
41
- function regenerateIndex(memoryDir) {
42
+ async function regenerateIndex(memoryDir) {
42
43
  if (!existsSync(memoryDir))
43
44
  return;
44
- var files = readdirSync(memoryDir).filter(function (f) {
45
+ var files = (await readdir(memoryDir)).filter(function (f) {
45
46
  return f.endsWith(".md") && f !== "MEMORY.md";
46
47
  });
47
48
  var grouped = {};
48
49
  for (var i = 0; i < files.length; i++) {
49
50
  try {
50
- var content = readFileSync(join(memoryDir, files[i]), "utf-8");
51
+ var content = await readFile(join(memoryDir, files[i]), "utf-8");
51
52
  var meta = parseFrontmatter(content);
52
53
  var type = meta.type || "other";
53
54
  if (!grouped[type])
@@ -67,9 +68,30 @@ function regenerateIndex(memoryDir) {
67
68
  }
68
69
  lines.push("");
69
70
  }
70
- writeFileSync(join(memoryDir, "MEMORY.md"), lines.join("\n"), "utf-8");
71
+ await writeFile(join(memoryDir, "MEMORY.md"), lines.join("\n"), "utf-8");
71
72
  }
72
- registerHandler("memory", function (clientId, message) {
73
+ async function listMemoryFiles(memDir) {
74
+ var files = (await readdir(memDir)).filter(function (f) {
75
+ return f.endsWith(".md") && f !== "MEMORY.md";
76
+ });
77
+ var memories = [];
78
+ for (var i = 0; i < files.length; i++) {
79
+ try {
80
+ var content = await readFile(join(memDir, files[i]), "utf-8");
81
+ var meta = parseFrontmatter(content);
82
+ memories.push({
83
+ filename: files[i],
84
+ name: meta.name || files[i].replace(/\.md$/, ""),
85
+ description: meta.description,
86
+ type: meta.type || "other",
87
+ });
88
+ }
89
+ catch { }
90
+ }
91
+ memories.sort(function (a, b) { return a.name.localeCompare(b.name); });
92
+ return memories;
93
+ }
94
+ registerHandler("memory", async function (clientId, message) {
73
95
  if (message.type === "memory:list") {
74
96
  var listMsg = message;
75
97
  var memDir = getMemoryDir(listMsg.projectSlug);
@@ -77,24 +99,7 @@ registerHandler("memory", function (clientId, message) {
77
99
  sendTo(clientId, { type: "memory:list_result", projectSlug: listMsg.projectSlug, memories: [] });
78
100
  return;
79
101
  }
80
- var files = readdirSync(memDir).filter(function (f) {
81
- return f.endsWith(".md") && f !== "MEMORY.md";
82
- });
83
- var memories = [];
84
- for (var i = 0; i < files.length; i++) {
85
- try {
86
- var content = readFileSync(join(memDir, files[i]), "utf-8");
87
- var meta = parseFrontmatter(content);
88
- memories.push({
89
- filename: files[i],
90
- name: meta.name || files[i].replace(/\.md$/, ""),
91
- description: meta.description,
92
- type: meta.type || "other",
93
- });
94
- }
95
- catch { }
96
- }
97
- memories.sort(function (a, b) { return a.name.localeCompare(b.name); });
102
+ var memories = await listMemoryFiles(memDir);
98
103
  sendTo(clientId, { type: "memory:list_result", projectSlug: listMsg.projectSlug, memories: memories });
99
104
  return;
100
105
  }
@@ -106,7 +111,7 @@ registerHandler("memory", function (clientId, message) {
106
111
  return;
107
112
  }
108
113
  try {
109
- var viewContent = readFileSync(join(viewDir, viewMsg.filename), "utf-8");
114
+ var viewContent = await readFile(join(viewDir, viewMsg.filename), "utf-8");
110
115
  sendTo(clientId, { type: "memory:view_result", filename: viewMsg.filename, content: viewContent });
111
116
  }
112
117
  catch {
@@ -122,21 +127,11 @@ registerHandler("memory", function (clientId, message) {
122
127
  return;
123
128
  }
124
129
  try {
125
- mkdirSync(saveDir, { recursive: true });
126
- writeFileSync(join(saveDir, saveMsg.filename), saveMsg.content, "utf-8");
127
- regenerateIndex(saveDir);
130
+ await mkdir(saveDir, { recursive: true });
131
+ await writeFile(join(saveDir, saveMsg.filename), saveMsg.content, "utf-8");
132
+ await regenerateIndex(saveDir);
128
133
  sendTo(clientId, { type: "memory:save_result", success: true });
129
- var updatedFiles = readdirSync(saveDir).filter(function (f) { return f.endsWith(".md") && f !== "MEMORY.md"; });
130
- var updatedMemories = [];
131
- for (var j = 0; j < updatedFiles.length; j++) {
132
- try {
133
- var c = readFileSync(join(saveDir, updatedFiles[j]), "utf-8");
134
- var m = parseFrontmatter(c);
135
- updatedMemories.push({ filename: updatedFiles[j], name: m.name || updatedFiles[j].replace(/\.md$/, ""), description: m.description, type: m.type || "other" });
136
- }
137
- catch { }
138
- }
139
- updatedMemories.sort(function (a, b) { return a.name.localeCompare(b.name); });
134
+ var updatedMemories = await listMemoryFiles(saveDir);
140
135
  sendTo(clientId, { type: "memory:list_result", projectSlug: saveMsg.projectSlug, memories: updatedMemories });
141
136
  }
142
137
  catch (err) {
@@ -157,20 +152,10 @@ registerHandler("memory", function (clientId, message) {
157
152
  sendTo(clientId, { type: "memory:delete_result", success: false, message: "Memory not found." });
158
153
  return;
159
154
  }
160
- unlinkSync(filePath);
161
- regenerateIndex(delDir);
155
+ await unlink(filePath);
156
+ await regenerateIndex(delDir);
162
157
  sendTo(clientId, { type: "memory:delete_result", success: true });
163
- var remainingFiles = readdirSync(delDir).filter(function (f) { return f.endsWith(".md") && f !== "MEMORY.md"; });
164
- var remainingMemories = [];
165
- for (var k = 0; k < remainingFiles.length; k++) {
166
- try {
167
- var rc = readFileSync(join(delDir, remainingFiles[k]), "utf-8");
168
- var rm = parseFrontmatter(rc);
169
- remainingMemories.push({ filename: remainingFiles[k], name: rm.name || remainingFiles[k].replace(/\.md$/, ""), description: rm.description, type: rm.type || "other" });
170
- }
171
- catch { }
172
- }
173
- remainingMemories.sort(function (a, b) { return a.name.localeCompare(b.name); });
158
+ var remainingMemories = await listMemoryFiles(delDir);
174
159
  sendTo(clientId, { type: "memory:list_result", projectSlug: delMsg.projectSlug, memories: remainingMemories });
175
160
  }
176
161
  catch (err) {
@@ -6,7 +6,7 @@ import { loadConfig } from "../config.js";
6
6
  import { loadOrCreateIdentity } from "../identity.js";
7
7
  import { generateInviteCode, parseInviteCode, validatePairingToken, consumePairingToken } from "../mesh/pairing.js";
8
8
  import { addPeer, removePeer, loadPeers, getPeer } from "../mesh/peers.js";
9
- import { getConnectedPeerIds, connectToPeer, reconnectPeer, getPeerConnection, disconnectPeer, getConnectedPeerProjects, registerInboundPeer } from "../mesh/connector.js";
9
+ import { getConnectedPeerIds, connectToPeer, reconnectPeer, getPeerConnection, disconnectPeer, getConnectedPeerProjects, registerInboundPeer, getPeerHealth } from "../mesh/connector.js";
10
10
  import { getClientWebSocket, registerVirtualClient, removeVirtualClient } from "../ws/broadcast.js";
11
11
  import { networkInterfaces } from "node:os";
12
12
  import { existsSync, readFileSync } from "node:fs";
@@ -97,6 +97,7 @@ export function buildNodesMessage() {
97
97
  };
98
98
  var remotes = peers.map(function (peer) {
99
99
  var peerProjects = getConnectedPeerProjects(peer.id);
100
+ var health = getPeerHealth(peer.id);
100
101
  return {
101
102
  id: peer.id,
102
103
  name: peer.name,
@@ -108,6 +109,8 @@ export function buildNodesMessage() {
108
109
  projects: peerProjects.map(function (p) {
109
110
  return { slug: p.slug, path: "", title: p.title, nodeId: peer.id };
110
111
  }),
112
+ latencyMs: health?.latencyMs,
113
+ healthy: health?.healthy,
111
114
  };
112
115
  });
113
116
  return [local, ...remotes];
@@ -1,5 +1,5 @@
1
1
  import { registerHandler } from "../ws/router.js";
2
- import { sendTo, broadcast } from "../ws/broadcast.js";
2
+ import { sendTo, broadcastToProject } from "../ws/broadcast.js";
3
3
  import { loadConfig } from "../config.js";
4
4
  import { createSession, deleteSession, findProjectSlugForSession, getSessionPreview, getSessionTitle, getSessionUsage, listSessions, invalidateSessionCache, invalidateHistoryCache, getSessionHistoryPage, loadSessionHistory, renameSession, getSessionFileSizeBytes, updateSessionInIndex, removeSessionFromIndex, } from "../project/session.js";
5
5
  import { getContextBreakdown } from "../project/context-breakdown.js";
@@ -7,7 +7,7 @@ import { setActiveSession, getActiveSession } from "./chat.js";
7
7
  import { setActiveProject } from "./fs.js";
8
8
  import { wasSessionInterrupted, clearInterruptedFlag } from "../project/sdk-bridge.js";
9
9
  import { log } from "../logger.js";
10
- registerHandler("session", function (clientId, message) {
10
+ registerHandler("session", async function (clientId, message) {
11
11
  if (message.type === "session:list_request") {
12
12
  var listReqMsg = message;
13
13
  var offset = listReqMsg.offset || 0;
@@ -73,7 +73,7 @@ registerHandler("session", function (clientId, message) {
73
73
  var session = createSession(createMsg.projectSlug);
74
74
  updateSessionInIndex(createMsg.projectSlug, session);
75
75
  sendTo(clientId, { type: "session:created", session });
76
- broadcast({
76
+ broadcastToProject(createMsg.projectSlug, {
77
77
  type: "session:list",
78
78
  projectSlug: createMsg.projectSlug,
79
79
  sessions: [session],
@@ -87,12 +87,20 @@ registerHandler("session", function (clientId, message) {
87
87
  setActiveSession(clientId, activateMsg.projectSlug, activateMsg.sessionId);
88
88
  setActiveProject(clientId, activateMsg.projectSlug);
89
89
  invalidateHistoryCache(activateMsg.sessionId);
90
- var fileSize = getSessionFileSizeBytes(activateMsg.projectSlug, activateMsg.sessionId);
90
+ var fileSize = await getSessionFileSizeBytes(activateMsg.projectSlug, activateMsg.sessionId);
91
91
  sendTo(clientId, { type: "session:loading_progress", sessionId: activateMsg.sessionId, fileSize });
92
92
  var activateT0 = Date.now();
93
- void loadSessionHistory(activateMsg.projectSlug, activateMsg.sessionId).then(function (historyResult) {
94
- log.session("session:activate history: %dms", Date.now() - activateT0);
95
- var title = null;
93
+ void Promise.all([
94
+ loadSessionHistory(activateMsg.projectSlug, activateMsg.sessionId),
95
+ getSessionTitle(activateMsg.projectSlug, activateMsg.sessionId).catch(function () { return null; }),
96
+ getSessionUsage(activateMsg.projectSlug, activateMsg.sessionId).catch(function () { return null; }),
97
+ getContextBreakdown(activateMsg.projectSlug, activateMsg.sessionId).catch(function () { return null; }),
98
+ ]).then(function (results) {
99
+ var historyResult = results[0];
100
+ var sessionTitle = results[1];
101
+ var usage = results[2];
102
+ var breakdown = results[3];
103
+ log.session("session:activate: %dms", Date.now() - activateT0);
96
104
  var interrupted = wasSessionInterrupted(activateMsg.sessionId);
97
105
  if (interrupted) {
98
106
  clearInterruptedFlag(activateMsg.sessionId);
@@ -102,60 +110,33 @@ registerHandler("session", function (clientId, message) {
102
110
  projectSlug: activateMsg.projectSlug,
103
111
  sessionId: activateMsg.sessionId,
104
112
  messages: historyResult.messages,
105
- title: title,
113
+ title: sessionTitle,
106
114
  interrupted: interrupted || undefined,
107
115
  totalMessages: historyResult.totalMessages,
108
116
  hasMore: historyResult.hasMore,
109
117
  });
118
+ if (usage) {
119
+ sendTo(clientId, {
120
+ type: "chat:context_usage",
121
+ inputTokens: usage.inputTokens,
122
+ outputTokens: usage.outputTokens,
123
+ cacheReadTokens: usage.cacheReadTokens,
124
+ cacheCreationTokens: usage.cacheCreationTokens,
125
+ contextWindow: usage.contextWindow,
126
+ });
127
+ }
128
+ if (breakdown) {
129
+ sendTo(clientId, {
130
+ type: "chat:context_breakdown",
131
+ segments: breakdown.segments,
132
+ contextWindow: breakdown.contextWindow,
133
+ autocompactAt: breakdown.autocompactAt,
134
+ });
135
+ }
110
136
  }).catch(function (err) {
111
- log.session("Error sending session history: %O", err);
112
- sendTo(clientId, { type: "chat:error", message: "Failed to load session history" });
137
+ log.session("Failed to activate session: %O", err);
138
+ sendTo(clientId, { type: "chat:error", message: "Failed to load session" });
113
139
  });
114
- setTimeout(function () {
115
- void getSessionTitle(activateMsg.projectSlug, activateMsg.sessionId).then(function (sessionTitle) {
116
- if (sessionTitle) {
117
- sendTo(clientId, { type: "session:history", projectSlug: activateMsg.projectSlug, sessionId: activateMsg.sessionId, messages: [], title: sessionTitle });
118
- }
119
- }).catch(function () { });
120
- void Promise.all([
121
- getSessionUsage(activateMsg.projectSlug, activateMsg.sessionId).catch(function () { return null; }),
122
- getContextBreakdown(activateMsg.projectSlug, activateMsg.sessionId).catch(function () { return null; }),
123
- ]).then(function (results) {
124
- try {
125
- var usage = results[0];
126
- if (usage) {
127
- sendTo(clientId, {
128
- type: "chat:context_usage",
129
- inputTokens: usage.inputTokens,
130
- outputTokens: usage.outputTokens,
131
- cacheReadTokens: usage.cacheReadTokens,
132
- cacheCreationTokens: usage.cacheCreationTokens,
133
- contextWindow: usage.contextWindow,
134
- });
135
- }
136
- }
137
- catch (err) {
138
- log.session("Error sending context usage: %O", err);
139
- }
140
- try {
141
- var breakdown = results[1];
142
- if (breakdown) {
143
- sendTo(clientId, {
144
- type: "chat:context_breakdown",
145
- segments: breakdown.segments,
146
- contextWindow: breakdown.contextWindow,
147
- autocompactAt: breakdown.autocompactAt,
148
- });
149
- }
150
- }
151
- catch (err) {
152
- log.session("Error sending context breakdown: %O", err);
153
- }
154
- }).catch(function (err) {
155
- log.session("Failed to activate session: %O", err);
156
- sendTo(clientId, { type: "chat:error", message: "Failed to activate session" });
157
- });
158
- }, 50);
159
140
  return;
160
141
  }
161
142
  if (message.type === "session:rename") {
@@ -168,7 +149,7 @@ registerHandler("session", function (clientId, message) {
168
149
  void renameSession(projectSlug, renameMsg.sessionId, renameMsg.title).then(function () {
169
150
  invalidateSessionCache(projectSlug);
170
151
  void listSessions(projectSlug, { limit: 40 }).then(function (result) {
171
- broadcast({
152
+ broadcastToProject(projectSlug, {
172
153
  type: "session:list",
173
154
  projectSlug,
174
155
  sessions: result.sessions,
@@ -189,7 +170,7 @@ registerHandler("session", function (clientId, message) {
189
170
  void deleteSession(deleteProjectSlug, deleteMsg.sessionId).then(function () {
190
171
  removeSessionFromIndex(deleteProjectSlug, deleteMsg.sessionId);
191
172
  void listSessions(deleteProjectSlug, { limit: 40 }).then(function (result) {
192
- broadcast({
173
+ broadcastToProject(deleteProjectSlug, {
193
174
  type: "session:list",
194
175
  projectSlug: deleteProjectSlug,
195
176
  sessions: result.sessions,