@cryptiklemur/lattice 0.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/release.yml +4 -4
- package/.releaserc.json +2 -1
- package/client/src/components/auth/PassphrasePrompt.tsx +70 -70
- package/client/src/components/mesh/NodeBadge.tsx +24 -24
- package/client/src/components/mesh/PairingDialog.tsx +281 -281
- package/client/src/components/panels/FileBrowser.tsx +241 -241
- package/client/src/components/panels/StickyNotes.tsx +187 -187
- package/client/src/components/project-settings/ProjectMemory.tsx +471 -0
- package/client/src/components/project-settings/ProjectSettingsView.tsx +6 -0
- package/client/src/components/settings/Appearance.tsx +151 -151
- package/client/src/components/settings/MeshStatus.tsx +145 -145
- package/client/src/components/settings/SettingsView.tsx +57 -57
- package/client/src/components/setup/SetupWizard.tsx +750 -750
- package/client/src/components/sidebar/AddProjectModal.tsx +432 -0
- package/client/src/components/sidebar/ProjectRail.tsx +8 -4
- package/client/src/components/sidebar/SettingsSidebar.tsx +2 -1
- package/client/src/components/ui/ErrorBoundary.tsx +56 -56
- package/client/src/hooks/useSidebar.ts +16 -0
- package/client/src/router.tsx +453 -391
- package/client/src/stores/sidebar.ts +28 -0
- package/client/vite.config.ts +20 -20
- package/package.json +1 -1
- package/server/src/daemon.ts +1 -0
- package/server/src/handlers/chat.ts +194 -194
- package/server/src/handlers/fs.ts +159 -0
- package/server/src/handlers/memory.ts +179 -0
- package/server/src/handlers/settings.ts +114 -109
- package/shared/src/messages.ts +97 -2
- package/shared/src/project-settings.ts +1 -1
- package/themes/amoled.json +20 -20
- package/themes/ayu-light.json +9 -9
- package/themes/catppuccin-latte.json +9 -9
- package/themes/catppuccin-mocha.json +9 -9
- package/themes/clay-light.json +10 -10
- package/themes/clay.json +10 -10
- package/themes/dracula.json +9 -9
- package/themes/everforest-light.json +9 -9
- package/themes/everforest.json +9 -9
- package/themes/github-light.json +9 -9
- package/themes/gruvbox-dark.json +9 -9
- package/themes/gruvbox-light.json +9 -9
- package/themes/monokai.json +9 -9
- package/themes/nord-light.json +9 -9
- package/themes/nord.json +9 -9
- package/themes/one-dark.json +9 -9
- package/themes/one-light.json +9 -9
- package/themes/rose-pine-dawn.json +9 -9
- package/themes/rose-pine.json +9 -9
- package/themes/solarized-dark.json +9 -9
- package/themes/solarized-light.json +9 -9
- package/themes/tokyo-night-light.json +9 -9
- package/themes/tokyo-night.json +9 -9
- package/.serena/project.yml +0 -138
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync, readdirSync, unlinkSync, mkdirSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import type { ClientMessage } from "@lattice/shared";
|
|
5
|
+
import { registerHandler } from "../ws/router";
|
|
6
|
+
import { sendTo } from "../ws/broadcast";
|
|
7
|
+
import { loadConfig } from "../config";
|
|
8
|
+
|
|
9
|
+
function getMemoryDir(projectSlug: string): string | null {
|
|
10
|
+
var config = loadConfig();
|
|
11
|
+
var project = config.projects.find(function (p) { return p.slug === projectSlug; });
|
|
12
|
+
if (!project) return null;
|
|
13
|
+
var hash = "-" + project.path.replace(/\//g, "-").replace(/^-/, "");
|
|
14
|
+
return join(homedir(), ".claude", "projects", hash, "memory");
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function parseFrontmatter(content: string): { name: string; description: string; type: string } {
|
|
18
|
+
var match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
19
|
+
if (!match) return { name: "", description: "", type: "" };
|
|
20
|
+
var yaml = match[1];
|
|
21
|
+
var name = "";
|
|
22
|
+
var description = "";
|
|
23
|
+
var type = "";
|
|
24
|
+
var lines = yaml.split(/\r?\n/);
|
|
25
|
+
for (var i = 0; i < lines.length; i++) {
|
|
26
|
+
var line = lines[i];
|
|
27
|
+
var nameMatch = line.match(/^name:\s*(.+)/);
|
|
28
|
+
if (nameMatch) name = nameMatch[1].trim().replace(/^["']|["']$/g, "");
|
|
29
|
+
var descMatch = line.match(/^description:\s*(.+)/);
|
|
30
|
+
if (descMatch) description = descMatch[1].trim().replace(/^["']|["']$/g, "");
|
|
31
|
+
var typeMatch = line.match(/^type:\s*(.+)/);
|
|
32
|
+
if (typeMatch) type = typeMatch[1].trim().replace(/^["']|["']$/g, "");
|
|
33
|
+
}
|
|
34
|
+
return { name, description, type };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function regenerateIndex(memoryDir: string): void {
|
|
38
|
+
if (!existsSync(memoryDir)) return;
|
|
39
|
+
var files = readdirSync(memoryDir).filter(function (f) {
|
|
40
|
+
return f.endsWith(".md") && f !== "MEMORY.md";
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
var grouped: Record<string, Array<{ filename: string; name: string; description: string }>> = {};
|
|
44
|
+
|
|
45
|
+
for (var i = 0; i < files.length; i++) {
|
|
46
|
+
try {
|
|
47
|
+
var content = readFileSync(join(memoryDir, files[i]), "utf-8");
|
|
48
|
+
var meta = parseFrontmatter(content);
|
|
49
|
+
var type = meta.type || "other";
|
|
50
|
+
if (!grouped[type]) grouped[type] = [];
|
|
51
|
+
grouped[type].push({ filename: files[i], name: meta.name || files[i], description: meta.description || "" });
|
|
52
|
+
} catch {}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
var lines: string[] = ["# Memory Index", ""];
|
|
56
|
+
var types = Object.keys(grouped).sort();
|
|
57
|
+
for (var t = 0; t < types.length; t++) {
|
|
58
|
+
lines.push("## " + types[t].charAt(0).toUpperCase() + types[t].slice(1));
|
|
59
|
+
var entries = grouped[types[t]];
|
|
60
|
+
for (var e = 0; e < entries.length; e++) {
|
|
61
|
+
var desc = entries[e].description ? " — " + entries[e].description : "";
|
|
62
|
+
lines.push("- [" + entries[e].filename + "](" + entries[e].filename + ")" + desc);
|
|
63
|
+
}
|
|
64
|
+
lines.push("");
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
writeFileSync(join(memoryDir, "MEMORY.md"), lines.join("\n"), "utf-8");
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
registerHandler("memory", function (clientId: string, message: ClientMessage) {
|
|
71
|
+
if (message.type === "memory:list") {
|
|
72
|
+
var listMsg = message as { type: "memory:list"; projectSlug: string };
|
|
73
|
+
var memDir = getMemoryDir(listMsg.projectSlug);
|
|
74
|
+
if (!memDir || !existsSync(memDir)) {
|
|
75
|
+
sendTo(clientId, { type: "memory:list_result", projectSlug: listMsg.projectSlug, memories: [] });
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
var files = readdirSync(memDir).filter(function (f) {
|
|
80
|
+
return f.endsWith(".md") && f !== "MEMORY.md";
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
var memories: Array<{ filename: string; name: string; description: string; type: string }> = [];
|
|
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
|
+
} catch {}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
memories.sort(function (a, b) { return a.name.localeCompare(b.name); });
|
|
98
|
+
sendTo(clientId, { type: "memory:list_result", projectSlug: listMsg.projectSlug, memories: memories });
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (message.type === "memory:view") {
|
|
103
|
+
var viewMsg = message as { type: "memory:view"; projectSlug: string; filename: string };
|
|
104
|
+
var viewDir = getMemoryDir(viewMsg.projectSlug);
|
|
105
|
+
if (!viewDir) {
|
|
106
|
+
sendTo(clientId, { type: "memory:view_result", filename: viewMsg.filename, content: "Project not found." });
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
try {
|
|
110
|
+
var viewContent = readFileSync(join(viewDir, viewMsg.filename), "utf-8");
|
|
111
|
+
sendTo(clientId, { type: "memory:view_result", filename: viewMsg.filename, content: viewContent });
|
|
112
|
+
} catch {
|
|
113
|
+
sendTo(clientId, { type: "memory:view_result", filename: viewMsg.filename, content: "File not found." });
|
|
114
|
+
}
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (message.type === "memory:save") {
|
|
119
|
+
var saveMsg = message as { type: "memory:save"; projectSlug: string; filename: string; content: string };
|
|
120
|
+
var saveDir = getMemoryDir(saveMsg.projectSlug);
|
|
121
|
+
if (!saveDir) {
|
|
122
|
+
sendTo(clientId, { type: "memory:save_result", success: false, message: "Project not found." });
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
try {
|
|
126
|
+
mkdirSync(saveDir, { recursive: true });
|
|
127
|
+
writeFileSync(join(saveDir, saveMsg.filename), saveMsg.content, "utf-8");
|
|
128
|
+
regenerateIndex(saveDir);
|
|
129
|
+
sendTo(clientId, { type: "memory:save_result", success: true });
|
|
130
|
+
var updatedFiles = readdirSync(saveDir).filter(function (f) { return f.endsWith(".md") && f !== "MEMORY.md"; });
|
|
131
|
+
var updatedMemories: Array<{ filename: string; name: string; description: string; type: string }> = [];
|
|
132
|
+
for (var j = 0; j < updatedFiles.length; j++) {
|
|
133
|
+
try {
|
|
134
|
+
var c = readFileSync(join(saveDir, updatedFiles[j]), "utf-8");
|
|
135
|
+
var m = parseFrontmatter(c);
|
|
136
|
+
updatedMemories.push({ filename: updatedFiles[j], name: m.name || updatedFiles[j].replace(/\.md$/, ""), description: m.description, type: m.type || "other" });
|
|
137
|
+
} catch {}
|
|
138
|
+
}
|
|
139
|
+
updatedMemories.sort(function (a, b) { return a.name.localeCompare(b.name); });
|
|
140
|
+
sendTo(clientId, { type: "memory:list_result", projectSlug: saveMsg.projectSlug, memories: updatedMemories });
|
|
141
|
+
} catch (err) {
|
|
142
|
+
sendTo(clientId, { type: "memory:save_result", success: false, message: "Failed to save: " + String(err) });
|
|
143
|
+
}
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (message.type === "memory:delete") {
|
|
148
|
+
var delMsg = message as { type: "memory:delete"; projectSlug: string; filename: string };
|
|
149
|
+
var delDir = getMemoryDir(delMsg.projectSlug);
|
|
150
|
+
if (!delDir) {
|
|
151
|
+
sendTo(clientId, { type: "memory:delete_result", success: false, message: "Project not found." });
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
try {
|
|
155
|
+
var filePath = join(delDir, delMsg.filename);
|
|
156
|
+
if (!existsSync(filePath)) {
|
|
157
|
+
sendTo(clientId, { type: "memory:delete_result", success: false, message: "Memory not found." });
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
unlinkSync(filePath);
|
|
161
|
+
regenerateIndex(delDir);
|
|
162
|
+
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: Array<{ filename: string; name: string; description: string; type: string }> = [];
|
|
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
|
+
} catch {}
|
|
171
|
+
}
|
|
172
|
+
remainingMemories.sort(function (a, b) { return a.name.localeCompare(b.name); });
|
|
173
|
+
sendTo(clientId, { type: "memory:list_result", projectSlug: delMsg.projectSlug, memories: remainingMemories });
|
|
174
|
+
} catch (err) {
|
|
175
|
+
sendTo(clientId, { type: "memory:delete_result", success: false, message: "Failed to delete: " + String(err) });
|
|
176
|
+
}
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
});
|
|
@@ -1,109 +1,114 @@
|
|
|
1
|
-
import type { ClientMessage, SettingsGetMessage, SettingsUpdateMessage } from "@lattice/shared";
|
|
2
|
-
import { registerHandler } from "../ws/router";
|
|
3
|
-
import { sendTo, broadcast } from "../ws/broadcast";
|
|
4
|
-
import { loadConfig, saveConfig } from "../config";
|
|
5
|
-
import { addProject } from "../project/registry";
|
|
6
|
-
import type { LatticeConfig } from "@lattice/shared";
|
|
7
|
-
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
8
|
-
import { join } from "node:path";
|
|
9
|
-
import { homedir } from "node:os";
|
|
10
|
-
import { readGlobalMcpServers, writeGlobalMcpServers, readGlobalSkills } from "../project/project-files";
|
|
11
|
-
import { loadOrCreateIdentity } from "../identity";
|
|
12
|
-
|
|
13
|
-
function loadGlobalClaudeMd(): string {
|
|
14
|
-
var mdPath = join(homedir(), ".claude", "CLAUDE.md");
|
|
15
|
-
if (existsSync(mdPath)) {
|
|
16
|
-
try {
|
|
17
|
-
return readFileSync(mdPath, "utf-8");
|
|
18
|
-
} catch {}
|
|
19
|
-
}
|
|
20
|
-
return "";
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function saveGlobalClaudeMd(content: string): void {
|
|
24
|
-
var claudeDir = join(homedir(), ".claude");
|
|
25
|
-
if (!existsSync(claudeDir)) {
|
|
26
|
-
mkdirSync(claudeDir, { recursive: true });
|
|
27
|
-
}
|
|
28
|
-
writeFileSync(join(claudeDir, "CLAUDE.md"), content, "utf-8");
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
registerHandler("settings", function (clientId: string, message: ClientMessage) {
|
|
32
|
-
if (message.type === "settings:get") {
|
|
33
|
-
var config = loadConfig();
|
|
34
|
-
var identity = loadOrCreateIdentity();
|
|
35
|
-
var configWithClaudeMd = { ...config, claudeMd: loadGlobalClaudeMd() };
|
|
36
|
-
sendTo(clientId, {
|
|
37
|
-
type: "settings:data",
|
|
38
|
-
config: configWithClaudeMd,
|
|
39
|
-
mcpServers: readGlobalMcpServers() as Record<string, import("@lattice/shared").McpServerConfig>,
|
|
40
|
-
globalSkills: readGlobalSkills(),
|
|
41
|
-
});
|
|
42
|
-
sendTo(clientId, {
|
|
43
|
-
type: "projects:list",
|
|
44
|
-
projects: config.projects.map(function (p) {
|
|
45
|
-
return { slug: p.slug, path: p.path, title: p.title, nodeId: identity.id, nodeName: config.name, isRemote: false };
|
|
46
|
-
}),
|
|
47
|
-
});
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
if (message.type === "settings:update") {
|
|
52
|
-
var updateMsg = message as SettingsUpdateMessage;
|
|
53
|
-
var current = loadConfig();
|
|
54
|
-
|
|
55
|
-
var incoming = updateMsg.settings as Record<string, unknown>;
|
|
56
|
-
if (typeof incoming.claudeMd === "string") {
|
|
57
|
-
saveGlobalClaudeMd(incoming.claudeMd);
|
|
58
|
-
delete incoming.claudeMd;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
if (incoming.mcpServers != null) {
|
|
62
|
-
writeGlobalMcpServers(incoming.mcpServers as Record<string, unknown>);
|
|
63
|
-
delete incoming.mcpServers;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
1
|
+
import type { ClientMessage, SettingsGetMessage, SettingsUpdateMessage } from "@lattice/shared";
|
|
2
|
+
import { registerHandler } from "../ws/router";
|
|
3
|
+
import { sendTo, broadcast } from "../ws/broadcast";
|
|
4
|
+
import { loadConfig, saveConfig } from "../config";
|
|
5
|
+
import { addProject, removeProject } from "../project/registry";
|
|
6
|
+
import type { LatticeConfig } from "@lattice/shared";
|
|
7
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
import { homedir } from "node:os";
|
|
10
|
+
import { readGlobalMcpServers, writeGlobalMcpServers, readGlobalSkills } from "../project/project-files";
|
|
11
|
+
import { loadOrCreateIdentity } from "../identity";
|
|
12
|
+
|
|
13
|
+
function loadGlobalClaudeMd(): string {
|
|
14
|
+
var mdPath = join(homedir(), ".claude", "CLAUDE.md");
|
|
15
|
+
if (existsSync(mdPath)) {
|
|
16
|
+
try {
|
|
17
|
+
return readFileSync(mdPath, "utf-8");
|
|
18
|
+
} catch {}
|
|
19
|
+
}
|
|
20
|
+
return "";
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function saveGlobalClaudeMd(content: string): void {
|
|
24
|
+
var claudeDir = join(homedir(), ".claude");
|
|
25
|
+
if (!existsSync(claudeDir)) {
|
|
26
|
+
mkdirSync(claudeDir, { recursive: true });
|
|
27
|
+
}
|
|
28
|
+
writeFileSync(join(claudeDir, "CLAUDE.md"), content, "utf-8");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
registerHandler("settings", function (clientId: string, message: ClientMessage) {
|
|
32
|
+
if (message.type === "settings:get") {
|
|
33
|
+
var config = loadConfig();
|
|
34
|
+
var identity = loadOrCreateIdentity();
|
|
35
|
+
var configWithClaudeMd = { ...config, claudeMd: loadGlobalClaudeMd() };
|
|
36
|
+
sendTo(clientId, {
|
|
37
|
+
type: "settings:data",
|
|
38
|
+
config: configWithClaudeMd,
|
|
39
|
+
mcpServers: readGlobalMcpServers() as Record<string, import("@lattice/shared").McpServerConfig>,
|
|
40
|
+
globalSkills: readGlobalSkills(),
|
|
41
|
+
});
|
|
42
|
+
sendTo(clientId, {
|
|
43
|
+
type: "projects:list",
|
|
44
|
+
projects: config.projects.map(function (p) {
|
|
45
|
+
return { slug: p.slug, path: p.path, title: p.title, nodeId: identity.id, nodeName: config.name, isRemote: false };
|
|
46
|
+
}),
|
|
47
|
+
});
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (message.type === "settings:update") {
|
|
52
|
+
var updateMsg = message as SettingsUpdateMessage;
|
|
53
|
+
var current = loadConfig();
|
|
54
|
+
|
|
55
|
+
var incoming = updateMsg.settings as Record<string, unknown>;
|
|
56
|
+
if (typeof incoming.claudeMd === "string") {
|
|
57
|
+
saveGlobalClaudeMd(incoming.claudeMd);
|
|
58
|
+
delete incoming.claudeMd;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (incoming.mcpServers != null) {
|
|
62
|
+
writeGlobalMcpServers(incoming.mcpServers as Record<string, unknown>);
|
|
63
|
+
delete incoming.mcpServers;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (typeof incoming.removeProject === "string") {
|
|
67
|
+
removeProject(incoming.removeProject as string);
|
|
68
|
+
delete incoming.removeProject;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
var incomingProjects = incoming.projects as Array<{ path: string; slug?: string; title: string; env?: Record<string, string> }> | undefined;
|
|
72
|
+
if (incomingProjects && incomingProjects.length > 0) {
|
|
73
|
+
for (var i = 0; i < incomingProjects.length; i++) {
|
|
74
|
+
var proj = incomingProjects[i];
|
|
75
|
+
addProject(proj.path, proj.title);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
var refreshed = loadConfig();
|
|
80
|
+
var updated: LatticeConfig = {
|
|
81
|
+
...refreshed,
|
|
82
|
+
...(incoming as Partial<LatticeConfig>),
|
|
83
|
+
globalEnv: {
|
|
84
|
+
...refreshed.globalEnv,
|
|
85
|
+
...((incoming.globalEnv as Record<string, string>) ?? {}),
|
|
86
|
+
},
|
|
87
|
+
projects: refreshed.projects,
|
|
88
|
+
};
|
|
89
|
+
saveConfig(updated);
|
|
90
|
+
var updatedWithClaudeMd = { ...updated, claudeMd: loadGlobalClaudeMd() };
|
|
91
|
+
sendTo(clientId, {
|
|
92
|
+
type: "settings:data",
|
|
93
|
+
config: updatedWithClaudeMd,
|
|
94
|
+
mcpServers: readGlobalMcpServers() as Record<string, import("@lattice/shared").McpServerConfig>,
|
|
95
|
+
globalSkills: readGlobalSkills(),
|
|
96
|
+
});
|
|
97
|
+
var updatedIdentity = loadOrCreateIdentity();
|
|
98
|
+
broadcast({
|
|
99
|
+
type: "projects:list",
|
|
100
|
+
projects: updated.projects.map(function (p) {
|
|
101
|
+
return { slug: p.slug, path: p.path, title: p.title, nodeId: updatedIdentity.id, nodeName: updated.name, isRemote: false };
|
|
102
|
+
}),
|
|
103
|
+
});
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (message.type === "settings:restart") {
|
|
108
|
+
console.log("[lattice] Restart requested by client");
|
|
109
|
+
setTimeout(function () {
|
|
110
|
+
process.exit(0);
|
|
111
|
+
}, 200);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
});
|
package/shared/src/messages.ts
CHANGED
|
@@ -223,6 +223,39 @@ export interface SkillsUpdateMessage {
|
|
|
223
223
|
source: string;
|
|
224
224
|
}
|
|
225
225
|
|
|
226
|
+
export interface BrowseListMessage {
|
|
227
|
+
type: "browse:list";
|
|
228
|
+
path: string;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export interface MemoryListMessage {
|
|
232
|
+
type: "memory:list";
|
|
233
|
+
projectSlug: string;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export interface MemoryViewMessage {
|
|
237
|
+
type: "memory:view";
|
|
238
|
+
projectSlug: string;
|
|
239
|
+
filename: string;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export interface MemorySaveMessage {
|
|
243
|
+
type: "memory:save";
|
|
244
|
+
projectSlug: string;
|
|
245
|
+
filename: string;
|
|
246
|
+
content: string;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
export interface MemoryDeleteMessage {
|
|
250
|
+
type: "memory:delete";
|
|
251
|
+
projectSlug: string;
|
|
252
|
+
filename: string;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export interface BrowseSuggestionsMessage {
|
|
256
|
+
type: "browse:suggestions";
|
|
257
|
+
}
|
|
258
|
+
|
|
226
259
|
export interface ProjectSettingsGetMessage {
|
|
227
260
|
type: "project-settings:get";
|
|
228
261
|
projectSlug: string;
|
|
@@ -289,7 +322,13 @@ export type ClientMessage =
|
|
|
289
322
|
| SkillsInstallMessage
|
|
290
323
|
| SkillsViewMessage
|
|
291
324
|
| SkillsDeleteMessage
|
|
292
|
-
| SkillsUpdateMessage
|
|
325
|
+
| SkillsUpdateMessage
|
|
326
|
+
| BrowseListMessage
|
|
327
|
+
| MemoryListMessage
|
|
328
|
+
| MemoryViewMessage
|
|
329
|
+
| MemorySaveMessage
|
|
330
|
+
| MemoryDeleteMessage
|
|
331
|
+
| BrowseSuggestionsMessage;
|
|
293
332
|
|
|
294
333
|
export interface SessionListMessage {
|
|
295
334
|
type: "session:list";
|
|
@@ -548,6 +587,56 @@ export interface SkillsDeleteResultMessage {
|
|
|
548
587
|
message?: string;
|
|
549
588
|
}
|
|
550
589
|
|
|
590
|
+
export interface BrowseListResultMessage {
|
|
591
|
+
type: "browse:list_result";
|
|
592
|
+
path: string;
|
|
593
|
+
homedir: string;
|
|
594
|
+
entries: Array<{
|
|
595
|
+
name: string;
|
|
596
|
+
path: string;
|
|
597
|
+
hasClaudeMd: boolean;
|
|
598
|
+
projectName: string | null;
|
|
599
|
+
}>;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
export interface MemoryListResultMessage {
|
|
603
|
+
type: "memory:list_result";
|
|
604
|
+
projectSlug: string;
|
|
605
|
+
memories: Array<{
|
|
606
|
+
filename: string;
|
|
607
|
+
name: string;
|
|
608
|
+
description: string;
|
|
609
|
+
type: string;
|
|
610
|
+
}>;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
export interface MemoryViewResultMessage {
|
|
614
|
+
type: "memory:view_result";
|
|
615
|
+
filename: string;
|
|
616
|
+
content: string;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
export interface MemorySaveResultMessage {
|
|
620
|
+
type: "memory:save_result";
|
|
621
|
+
success: boolean;
|
|
622
|
+
message?: string;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
export interface MemoryDeleteResultMessage {
|
|
626
|
+
type: "memory:delete_result";
|
|
627
|
+
success: boolean;
|
|
628
|
+
message?: string;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
export interface BrowseSuggestionsResultMessage {
|
|
632
|
+
type: "browse:suggestions_result";
|
|
633
|
+
suggestions: Array<{
|
|
634
|
+
path: string;
|
|
635
|
+
name: string;
|
|
636
|
+
hasClaudeMd: boolean;
|
|
637
|
+
}>;
|
|
638
|
+
}
|
|
639
|
+
|
|
551
640
|
export type ServerMessage =
|
|
552
641
|
| SessionListMessage
|
|
553
642
|
| SessionCreatedMessage
|
|
@@ -592,7 +681,13 @@ export type ServerMessage =
|
|
|
592
681
|
| SkillsSearchResultsMessage
|
|
593
682
|
| SkillsInstallResultMessage
|
|
594
683
|
| SkillsViewResultMessage
|
|
595
|
-
| SkillsDeleteResultMessage
|
|
684
|
+
| SkillsDeleteResultMessage
|
|
685
|
+
| BrowseListResultMessage
|
|
686
|
+
| MemoryListResultMessage
|
|
687
|
+
| MemoryViewResultMessage
|
|
688
|
+
| MemorySaveResultMessage
|
|
689
|
+
| MemoryDeleteResultMessage
|
|
690
|
+
| BrowseSuggestionsResultMessage;
|
|
596
691
|
|
|
597
692
|
export interface MeshHelloMessage {
|
|
598
693
|
type: "mesh:hello";
|
|
@@ -15,7 +15,7 @@ export type McpServerConfig =
|
|
|
15
15
|
| { type: "sse"; url: string; headers?: Record<string, string> };
|
|
16
16
|
|
|
17
17
|
export type ProjectSettingsSection =
|
|
18
|
-
| "general" | "claude" | "environment" | "mcp" | "skills" | "rules" | "permissions";
|
|
18
|
+
| "general" | "claude" | "environment" | "mcp" | "skills" | "rules" | "permissions" | "memory";
|
|
19
19
|
|
|
20
20
|
export interface ProjectSettings {
|
|
21
21
|
title: string;
|
package/themes/amoled.json
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "AMOLED Dark",
|
|
3
|
-
"variant": "dark",
|
|
4
|
-
"base00": "000000",
|
|
5
|
-
"base01": "0a0a0a",
|
|
6
|
-
"base02": "1a1a1a",
|
|
7
|
-
"base03": "555555",
|
|
8
|
-
"base04": "999999",
|
|
9
|
-
"base05": "e0e0e0",
|
|
10
|
-
"base06": "f5f5f5",
|
|
11
|
-
"base07": "ffffff",
|
|
12
|
-
"base08": "ff6b6b",
|
|
13
|
-
"base09": "ffa94d",
|
|
14
|
-
"base0A": "ffd93d",
|
|
15
|
-
"base0B": "6bcf7f",
|
|
16
|
-
"base0C": "4ecdc4",
|
|
17
|
-
"base0D": "74b7ff",
|
|
18
|
-
"base0E": "ff6ef7",
|
|
19
|
-
"base0F": "c8a2ff"
|
|
20
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "AMOLED Dark",
|
|
3
|
+
"variant": "dark",
|
|
4
|
+
"base00": "000000",
|
|
5
|
+
"base01": "0a0a0a",
|
|
6
|
+
"base02": "1a1a1a",
|
|
7
|
+
"base03": "555555",
|
|
8
|
+
"base04": "999999",
|
|
9
|
+
"base05": "e0e0e0",
|
|
10
|
+
"base06": "f5f5f5",
|
|
11
|
+
"base07": "ffffff",
|
|
12
|
+
"base08": "ff6b6b",
|
|
13
|
+
"base09": "ffa94d",
|
|
14
|
+
"base0A": "ffd93d",
|
|
15
|
+
"base0B": "6bcf7f",
|
|
16
|
+
"base0C": "4ecdc4",
|
|
17
|
+
"base0D": "74b7ff",
|
|
18
|
+
"base0E": "ff6ef7",
|
|
19
|
+
"base0F": "c8a2ff"
|
|
20
|
+
}
|
package/themes/ayu-light.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "Ayu Light",
|
|
3
|
-
"author": "Ike Ku",
|
|
4
|
-
"variant": "light",
|
|
5
|
-
"base00": "FAFAFA", "base01": "EDEFF1", "base02": "D2D4D8", "base03": "A0A6AC",
|
|
6
|
-
"base04": "8A9199", "base05": "5C6166", "base06": "4E5257", "base07": "404447",
|
|
7
|
-
"base08": "F07171", "base09": "FA8D3E", "base0A": "F2AE49", "base0B": "6CBF49",
|
|
8
|
-
"base0C": "4CBF99", "base0D": "399EE6", "base0E": "A37ACC", "base0F": "E6BA7E"
|
|
9
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "Ayu Light",
|
|
3
|
+
"author": "Ike Ku",
|
|
4
|
+
"variant": "light",
|
|
5
|
+
"base00": "FAFAFA", "base01": "EDEFF1", "base02": "D2D4D8", "base03": "A0A6AC",
|
|
6
|
+
"base04": "8A9199", "base05": "5C6166", "base06": "4E5257", "base07": "404447",
|
|
7
|
+
"base08": "F07171", "base09": "FA8D3E", "base0A": "F2AE49", "base0B": "6CBF49",
|
|
8
|
+
"base0C": "4CBF99", "base0D": "399EE6", "base0E": "A37ACC", "base0F": "E6BA7E"
|
|
9
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "Catppuccin Latte",
|
|
3
|
-
"author": "catppuccin",
|
|
4
|
-
"variant": "light",
|
|
5
|
-
"base00": "eff1f5", "base01": "e6e9ef", "base02": "ccd0da", "base03": "9ca0b0",
|
|
6
|
-
"base04": "8c8fa1", "base05": "5c5f77", "base06": "4c4f69", "base07": "303446",
|
|
7
|
-
"base08": "d20f39", "base09": "fe640b", "base0A": "df8e1d", "base0B": "40a02b",
|
|
8
|
-
"base0C": "179299", "base0D": "1e66f5", "base0E": "8839ef", "base0F": "dd7878"
|
|
9
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "Catppuccin Latte",
|
|
3
|
+
"author": "catppuccin",
|
|
4
|
+
"variant": "light",
|
|
5
|
+
"base00": "eff1f5", "base01": "e6e9ef", "base02": "ccd0da", "base03": "9ca0b0",
|
|
6
|
+
"base04": "8c8fa1", "base05": "5c5f77", "base06": "4c4f69", "base07": "303446",
|
|
7
|
+
"base08": "d20f39", "base09": "fe640b", "base0A": "df8e1d", "base0B": "40a02b",
|
|
8
|
+
"base0C": "179299", "base0D": "1e66f5", "base0E": "8839ef", "base0F": "dd7878"
|
|
9
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "Catppuccin Mocha",
|
|
3
|
-
"author": "catppuccin",
|
|
4
|
-
"variant": "dark",
|
|
5
|
-
"base00": "1e1e2e", "base01": "181825", "base02": "313244", "base03": "45475a",
|
|
6
|
-
"base04": "585b70", "base05": "cdd6f4", "base06": "f5e0dc", "base07": "b4befe",
|
|
7
|
-
"base08": "f38ba8", "base09": "fab387", "base0A": "f9e2af", "base0B": "a6e3a1",
|
|
8
|
-
"base0C": "94e2d5", "base0D": "89b4fa", "base0E": "cba6f7", "base0F": "f2cdcd"
|
|
9
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "Catppuccin Mocha",
|
|
3
|
+
"author": "catppuccin",
|
|
4
|
+
"variant": "dark",
|
|
5
|
+
"base00": "1e1e2e", "base01": "181825", "base02": "313244", "base03": "45475a",
|
|
6
|
+
"base04": "585b70", "base05": "cdd6f4", "base06": "f5e0dc", "base07": "b4befe",
|
|
7
|
+
"base08": "f38ba8", "base09": "fab387", "base0A": "f9e2af", "base0B": "a6e3a1",
|
|
8
|
+
"base0C": "94e2d5", "base0D": "89b4fa", "base0E": "cba6f7", "base0F": "f2cdcd"
|
|
9
|
+
}
|
package/themes/clay-light.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "Clay Light",
|
|
3
|
-
"author": "Clay",
|
|
4
|
-
"variant": "light",
|
|
5
|
-
"base00": "F3EBE7", "base01": "EBE1DC", "base02": "D8CCC6", "base03": "A09590",
|
|
6
|
-
"base04": "786D67", "base05": "504541", "base06": "332925", "base07": "1A1412",
|
|
7
|
-
"base08": "C83520", "base09": "F74728", "base0A": "C08520", "base0B": "008F6B",
|
|
8
|
-
"base0C": "1C8575", "base0D": "3560B0", "base0E": "8C4E8E", "base0F": "A57C45",
|
|
9
|
-
"accent2": "2A26E5"
|
|
10
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "Clay Light",
|
|
3
|
+
"author": "Clay",
|
|
4
|
+
"variant": "light",
|
|
5
|
+
"base00": "F3EBE7", "base01": "EBE1DC", "base02": "D8CCC6", "base03": "A09590",
|
|
6
|
+
"base04": "786D67", "base05": "504541", "base06": "332925", "base07": "1A1412",
|
|
7
|
+
"base08": "C83520", "base09": "F74728", "base0A": "C08520", "base0B": "008F6B",
|
|
8
|
+
"base0C": "1C8575", "base0D": "3560B0", "base0E": "8C4E8E", "base0F": "A57C45",
|
|
9
|
+
"accent2": "2A26E5"
|
|
10
|
+
}
|