@cryptiklemur/lattice 0.0.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 (162) hide show
  1. package/.editorconfig +12 -0
  2. package/.github/workflows/release.yml +44 -0
  3. package/.impeccable.md +66 -0
  4. package/.releaserc.json +32 -0
  5. package/.serena/project.yml +138 -0
  6. package/CLAUDE.md +35 -0
  7. package/CONTRIBUTING.md +93 -0
  8. package/LICENSE +21 -0
  9. package/README.md +83 -0
  10. package/bun.lock +1459 -0
  11. package/bunfig.toml +2 -0
  12. package/client/index.html +32 -0
  13. package/client/package.json +37 -0
  14. package/client/public/icons/icon-192.svg +11 -0
  15. package/client/public/icons/icon-512.svg +11 -0
  16. package/client/public/manifest.json +24 -0
  17. package/client/public/sw.js +61 -0
  18. package/client/src/App.tsx +28 -0
  19. package/client/src/components/auth/PassphrasePrompt.tsx +70 -0
  20. package/client/src/components/chat/ChatInput.tsx +241 -0
  21. package/client/src/components/chat/ChatView.tsx +727 -0
  22. package/client/src/components/chat/Message.tsx +362 -0
  23. package/client/src/components/chat/ModelSelector.tsx +87 -0
  24. package/client/src/components/chat/PermissionModeSelector.tsx +41 -0
  25. package/client/src/components/chat/StatusBar.tsx +50 -0
  26. package/client/src/components/chat/ToolGroup.tsx +129 -0
  27. package/client/src/components/chat/ToolResultRenderer.tsx +343 -0
  28. package/client/src/components/chat/toolSummary.ts +41 -0
  29. package/client/src/components/dashboard/DashboardView.tsx +219 -0
  30. package/client/src/components/dashboard/ProjectDashboardView.tsx +168 -0
  31. package/client/src/components/mesh/NodeBadge.tsx +24 -0
  32. package/client/src/components/mesh/PairingDialog.tsx +281 -0
  33. package/client/src/components/panels/FileBrowser.tsx +241 -0
  34. package/client/src/components/panels/StickyNotes.tsx +187 -0
  35. package/client/src/components/panels/Terminal.tsx +128 -0
  36. package/client/src/components/project-settings/ProjectClaude.tsx +304 -0
  37. package/client/src/components/project-settings/ProjectEnvironment.tsx +235 -0
  38. package/client/src/components/project-settings/ProjectGeneral.tsx +76 -0
  39. package/client/src/components/project-settings/ProjectMcp.tsx +232 -0
  40. package/client/src/components/project-settings/ProjectPermissions.tsx +209 -0
  41. package/client/src/components/project-settings/ProjectRules.tsx +277 -0
  42. package/client/src/components/project-settings/ProjectSettingsView.tsx +99 -0
  43. package/client/src/components/project-settings/ProjectSkills.tsx +91 -0
  44. package/client/src/components/settings/Appearance.tsx +151 -0
  45. package/client/src/components/settings/ClaudeSettings.tsx +151 -0
  46. package/client/src/components/settings/Environment.tsx +185 -0
  47. package/client/src/components/settings/GlobalMcp.tsx +207 -0
  48. package/client/src/components/settings/GlobalSkills.tsx +125 -0
  49. package/client/src/components/settings/MeshStatus.tsx +145 -0
  50. package/client/src/components/settings/SettingsView.tsx +57 -0
  51. package/client/src/components/settings/SkillMarketplace.tsx +175 -0
  52. package/client/src/components/settings/mcp-shared.tsx +194 -0
  53. package/client/src/components/settings/skill-shared.tsx +177 -0
  54. package/client/src/components/setup/SetupWizard.tsx +750 -0
  55. package/client/src/components/sidebar/NodeSettingsModal.tsx +180 -0
  56. package/client/src/components/sidebar/ProjectDropdown.tsx +43 -0
  57. package/client/src/components/sidebar/ProjectRail.tsx +291 -0
  58. package/client/src/components/sidebar/SearchFilter.tsx +52 -0
  59. package/client/src/components/sidebar/SessionList.tsx +384 -0
  60. package/client/src/components/sidebar/SettingsSidebar.tsx +128 -0
  61. package/client/src/components/sidebar/Sidebar.tsx +209 -0
  62. package/client/src/components/sidebar/UserIsland.tsx +59 -0
  63. package/client/src/components/sidebar/UserMenu.tsx +101 -0
  64. package/client/src/components/ui/CommandPalette.tsx +321 -0
  65. package/client/src/components/ui/ErrorBoundary.tsx +56 -0
  66. package/client/src/components/ui/IconPicker.tsx +209 -0
  67. package/client/src/components/ui/LatticeLogomark.tsx +19 -0
  68. package/client/src/components/ui/PopupMenu.tsx +98 -0
  69. package/client/src/components/ui/SaveFooter.tsx +38 -0
  70. package/client/src/components/ui/Toast.tsx +112 -0
  71. package/client/src/hooks/useMesh.ts +89 -0
  72. package/client/src/hooks/useProjectSettings.ts +56 -0
  73. package/client/src/hooks/useProjects.ts +66 -0
  74. package/client/src/hooks/useSaveState.ts +59 -0
  75. package/client/src/hooks/useSession.ts +317 -0
  76. package/client/src/hooks/useSidebar.ts +74 -0
  77. package/client/src/hooks/useSkills.ts +30 -0
  78. package/client/src/hooks/useTheme.ts +114 -0
  79. package/client/src/hooks/useWebSocket.ts +26 -0
  80. package/client/src/main.tsx +10 -0
  81. package/client/src/providers/WebSocketProvider.tsx +146 -0
  82. package/client/src/router.tsx +391 -0
  83. package/client/src/stores/mesh.ts +78 -0
  84. package/client/src/stores/session.ts +322 -0
  85. package/client/src/stores/sidebar.ts +336 -0
  86. package/client/src/stores/theme.ts +44 -0
  87. package/client/src/styles/global.css +167 -0
  88. package/client/src/styles/theme-vars.css +18 -0
  89. package/client/src/themes/index.ts +79 -0
  90. package/client/src/utils/findDuplicateKeys.ts +12 -0
  91. package/client/tsconfig.json +14 -0
  92. package/client/vite.config.ts +20 -0
  93. package/package.json +46 -0
  94. package/server/package.json +22 -0
  95. package/server/src/auth/passphrase.ts +48 -0
  96. package/server/src/config.ts +55 -0
  97. package/server/src/daemon.ts +338 -0
  98. package/server/src/features/ralph-loop.ts +173 -0
  99. package/server/src/features/scheduler.ts +281 -0
  100. package/server/src/features/sticky-notes.ts +102 -0
  101. package/server/src/handlers/chat.ts +194 -0
  102. package/server/src/handlers/fs.ts +84 -0
  103. package/server/src/handlers/loop.ts +37 -0
  104. package/server/src/handlers/mesh.ts +125 -0
  105. package/server/src/handlers/notes.ts +45 -0
  106. package/server/src/handlers/project-settings.ts +174 -0
  107. package/server/src/handlers/scheduler.ts +47 -0
  108. package/server/src/handlers/session.ts +159 -0
  109. package/server/src/handlers/settings.ts +109 -0
  110. package/server/src/handlers/skills.ts +380 -0
  111. package/server/src/handlers/terminal.ts +70 -0
  112. package/server/src/identity.ts +26 -0
  113. package/server/src/index.ts +190 -0
  114. package/server/src/mesh/connector.ts +209 -0
  115. package/server/src/mesh/discovery.ts +123 -0
  116. package/server/src/mesh/pairing.ts +94 -0
  117. package/server/src/mesh/peers.ts +52 -0
  118. package/server/src/mesh/proxy.ts +103 -0
  119. package/server/src/mesh/session-sync.ts +107 -0
  120. package/server/src/project/context-breakdown.ts +289 -0
  121. package/server/src/project/file-browser.ts +106 -0
  122. package/server/src/project/project-files.ts +267 -0
  123. package/server/src/project/registry.ts +57 -0
  124. package/server/src/project/sdk-bridge.ts +566 -0
  125. package/server/src/project/session.ts +432 -0
  126. package/server/src/project/terminal.ts +69 -0
  127. package/server/src/tls.ts +51 -0
  128. package/server/src/ws/broadcast.ts +31 -0
  129. package/server/src/ws/router.ts +104 -0
  130. package/server/src/ws/server.ts +2 -0
  131. package/server/tsconfig.json +16 -0
  132. package/shared/package.json +11 -0
  133. package/shared/src/constants.ts +7 -0
  134. package/shared/src/index.ts +4 -0
  135. package/shared/src/messages.ts +638 -0
  136. package/shared/src/models.ts +136 -0
  137. package/shared/src/project-settings.ts +45 -0
  138. package/shared/tsconfig.json +11 -0
  139. package/themes/amoled.json +20 -0
  140. package/themes/ayu-light.json +9 -0
  141. package/themes/catppuccin-latte.json +9 -0
  142. package/themes/catppuccin-mocha.json +9 -0
  143. package/themes/clay-light.json +10 -0
  144. package/themes/clay.json +10 -0
  145. package/themes/dracula.json +9 -0
  146. package/themes/everforest-light.json +9 -0
  147. package/themes/everforest.json +9 -0
  148. package/themes/github-light.json +9 -0
  149. package/themes/gruvbox-dark.json +9 -0
  150. package/themes/gruvbox-light.json +9 -0
  151. package/themes/monokai.json +9 -0
  152. package/themes/nord-light.json +9 -0
  153. package/themes/nord.json +9 -0
  154. package/themes/one-dark.json +9 -0
  155. package/themes/one-light.json +9 -0
  156. package/themes/rose-pine-dawn.json +9 -0
  157. package/themes/rose-pine.json +9 -0
  158. package/themes/solarized-dark.json +9 -0
  159. package/themes/solarized-light.json +9 -0
  160. package/themes/tokyo-night-light.json +9 -0
  161. package/themes/tokyo-night.json +9 -0
  162. package/tsconfig.json +26 -0
@@ -0,0 +1,167 @@
1
+ @import "tailwindcss";
2
+ @plugin "daisyui";
3
+ @plugin "@tailwindcss/typography";
4
+ @plugin "daisyui/theme" {
5
+ name: "lattice-dark";
6
+ default: true;
7
+ prefersdark: true;
8
+ color-scheme: dark;
9
+ --color-base-100: oklch(13% 0.02 280);
10
+ --color-base-200: oklch(16% 0.02 280);
11
+ --color-base-300: oklch(20% 0.02 280);
12
+ --color-base-content: oklch(90% 0.02 280);
13
+ --color-primary: oklch(55% 0.25 280);
14
+ --color-primary-content: oklch(98% 0.01 280);
15
+ --color-secondary: oklch(60% 0.2 280);
16
+ --color-secondary-content: oklch(98% 0.01 280);
17
+ --color-accent: oklch(65% 0.25 150);
18
+ --color-accent-content: oklch(98% 0.01 150);
19
+ --color-neutral: oklch(25% 0.02 280);
20
+ --color-neutral-content: oklch(85% 0.02 280);
21
+ --color-info: oklch(65% 0.2 240);
22
+ --color-info-content: oklch(98% 0.01 240);
23
+ --color-success: oklch(70% 0.2 150);
24
+ --color-success-content: oklch(98% 0.01 150);
25
+ --color-warning: oklch(80% 0.2 85);
26
+ --color-warning-content: oklch(20% 0.05 85);
27
+ --color-error: oklch(65% 0.25 25);
28
+ --color-error-content: oklch(98% 0.01 25);
29
+ --radius-selector: 0.5rem;
30
+ --radius-field: 0.25rem;
31
+ --radius-box: 0.5rem;
32
+ --size-selector: 0.25rem;
33
+ --size-field: 0.25rem;
34
+ --border: 1px;
35
+ --depth: 1;
36
+ --noise: 0;
37
+ }
38
+
39
+ :root {
40
+ --sidebar-width: 260px;
41
+ --node-rail-width: 52px;
42
+
43
+ --font-ui: "IBM Plex Sans", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
44
+ --font-mono: "JetBrains Mono", "Berkeley Mono", "Geist Mono", ui-monospace, monospace;
45
+ --font-heading: "JetBrains Mono", "Berkeley Mono", ui-monospace, monospace;
46
+ }
47
+
48
+ html, body {
49
+ height: 100%;
50
+ width: 100%;
51
+ max-width: 100vw;
52
+ overflow-x: hidden;
53
+ font-family: var(--font-ui);
54
+ -webkit-font-smoothing: antialiased;
55
+ -moz-osx-font-smoothing: grayscale;
56
+ }
57
+
58
+ #root {
59
+ height: 100%;
60
+ width: 100%;
61
+ max-width: 100vw;
62
+ display: flex;
63
+ overflow: hidden;
64
+ position: relative;
65
+ }
66
+
67
+ ::-webkit-scrollbar {
68
+ width: 6px;
69
+ height: 6px;
70
+ }
71
+
72
+ ::-webkit-scrollbar-track {
73
+ background: transparent;
74
+ }
75
+
76
+ ::-webkit-scrollbar-thumb {
77
+ background: oklch(from var(--color-base-content) l c h / 0.15);
78
+ border-radius: 3px;
79
+ }
80
+
81
+ ::-webkit-scrollbar-thumb:hover {
82
+ background: oklch(from var(--color-base-content) l c h / 0.25);
83
+ }
84
+
85
+ * {
86
+ scrollbar-width: thin;
87
+ scrollbar-color: oklch(from var(--color-base-content) l c h / 0.15) transparent;
88
+ }
89
+
90
+ .prose pre {
91
+ border-radius: 0.5rem;
92
+ border: 1px solid oklch(from var(--color-base-content) l c h / 0.1);
93
+ font-family: var(--font-mono);
94
+ font-size: 13px;
95
+ line-height: 1.6;
96
+ }
97
+
98
+ .prose code {
99
+ font-family: var(--font-mono);
100
+ font-size: 13px;
101
+ padding: 0.15em 0.3em;
102
+ border-radius: 0.25rem;
103
+ background: oklch(from var(--color-base-content) l c h / 0.08);
104
+ }
105
+
106
+ .prose pre code {
107
+ padding: 0;
108
+ background: transparent;
109
+ }
110
+
111
+ .bg-lattice-grid {
112
+ background-color: transparent;
113
+ }
114
+
115
+ @media (min-width: 640px) {
116
+ .bg-lattice-grid {
117
+ background-image: radial-gradient(circle, oklch(90% 0.02 280 / 0.05) 1px, transparent 1px);
118
+ background-size: 24px 24px;
119
+ }
120
+ }
121
+
122
+ @keyframes pulse {
123
+ 0%, 80%, 100% { opacity: 0.2; transform: scale(0.8); }
124
+ 40% { opacity: 1; transform: scale(1); }
125
+ }
126
+
127
+ @keyframes spin {
128
+ to { transform: rotate(360deg); }
129
+ }
130
+
131
+ @keyframes toast-in {
132
+ from { opacity: 0; transform: translateX(12px); }
133
+ to { opacity: 1; transform: translateX(0); }
134
+ }
135
+
136
+ @media (pointer: coarse) {
137
+ .btn-xs,
138
+ .btn-sm,
139
+ .select-xs,
140
+ .select-sm {
141
+ min-height: 44px;
142
+ min-width: 44px;
143
+ }
144
+
145
+ .select-xs,
146
+ .select-sm {
147
+ min-width: unset;
148
+ }
149
+ }
150
+
151
+ .scrollbar-hidden {
152
+ scrollbar-width: none;
153
+ -ms-overflow-style: none;
154
+ }
155
+
156
+ .scrollbar-hidden::-webkit-scrollbar {
157
+ display: none;
158
+ }
159
+
160
+ @media (prefers-reduced-motion: reduce) {
161
+ *, *::before, *::after {
162
+ animation-duration: 0.01ms !important;
163
+ animation-iteration-count: 1 !important;
164
+ transition-duration: 0.01ms !important;
165
+ scroll-behavior: auto !important;
166
+ }
167
+ }
@@ -0,0 +1,18 @@
1
+ :root {
2
+ --bg-primary: var(--base00);
3
+ --bg-secondary: var(--base01);
4
+ --bg-tertiary: var(--base02);
5
+ --text-muted: var(--base03);
6
+ --text-secondary: var(--base04);
7
+ --text-primary: var(--base05);
8
+ --text-bright: var(--base06);
9
+ --text-accent: var(--base07);
10
+ --red: var(--base08);
11
+ --orange: var(--base09);
12
+ --yellow: var(--base0A);
13
+ --green: var(--base0B);
14
+ --cyan: var(--base0C);
15
+ --blue: var(--base0D);
16
+ --purple: var(--base0E);
17
+ --magenta: var(--base0F);
18
+ }
@@ -0,0 +1,79 @@
1
+ import amoled from "../../../themes/amoled.json";
2
+ import ayuLight from "../../../themes/ayu-light.json";
3
+ import catppuccinLatte from "../../../themes/catppuccin-latte.json";
4
+ import catppuccinMocha from "../../../themes/catppuccin-mocha.json";
5
+ import clayLight from "../../../themes/clay-light.json";
6
+ import clay from "../../../themes/clay.json";
7
+ import dracula from "../../../themes/dracula.json";
8
+ import everforestLight from "../../../themes/everforest-light.json";
9
+ import everforest from "../../../themes/everforest.json";
10
+ import githubLight from "../../../themes/github-light.json";
11
+ import gruvboxDark from "../../../themes/gruvbox-dark.json";
12
+ import gruvboxLight from "../../../themes/gruvbox-light.json";
13
+ import monokai from "../../../themes/monokai.json";
14
+ import nordLight from "../../../themes/nord-light.json";
15
+ import nord from "../../../themes/nord.json";
16
+ import oneDark from "../../../themes/one-dark.json";
17
+ import oneLight from "../../../themes/one-light.json";
18
+ import rosePineDawn from "../../../themes/rose-pine-dawn.json";
19
+ import rosePine from "../../../themes/rose-pine.json";
20
+ import solarizedDark from "../../../themes/solarized-dark.json";
21
+ import solarizedLight from "../../../themes/solarized-light.json";
22
+ import tokyoNightLight from "../../../themes/tokyo-night-light.json";
23
+ import tokyoNight from "../../../themes/tokyo-night.json";
24
+
25
+ export interface ThemeColors {
26
+ base00: string;
27
+ base01: string;
28
+ base02: string;
29
+ base03: string;
30
+ base04: string;
31
+ base05: string;
32
+ base06: string;
33
+ base07: string;
34
+ base08: string;
35
+ base09: string;
36
+ base0A: string;
37
+ base0B: string;
38
+ base0C: string;
39
+ base0D: string;
40
+ base0E: string;
41
+ base0F: string;
42
+ }
43
+
44
+ export interface Theme extends ThemeColors {
45
+ name: string;
46
+ author: string;
47
+ variant: "dark" | "light";
48
+ }
49
+
50
+ export interface ThemeEntry {
51
+ id: string;
52
+ theme: Theme;
53
+ }
54
+
55
+ export var themes: ThemeEntry[] = [
56
+ { id: "amoled", theme: amoled as Theme },
57
+ { id: "ayu-light", theme: ayuLight as Theme },
58
+ { id: "catppuccin-latte", theme: catppuccinLatte as Theme },
59
+ { id: "catppuccin-mocha", theme: catppuccinMocha as Theme },
60
+ { id: "clay-light", theme: clayLight as Theme },
61
+ { id: "clay", theme: clay as Theme },
62
+ { id: "dracula", theme: dracula as Theme },
63
+ { id: "everforest-light", theme: everforestLight as Theme },
64
+ { id: "everforest", theme: everforest as Theme },
65
+ { id: "github-light", theme: githubLight as Theme },
66
+ { id: "gruvbox-dark", theme: gruvboxDark as Theme },
67
+ { id: "gruvbox-light", theme: gruvboxLight as Theme },
68
+ { id: "monokai", theme: monokai as Theme },
69
+ { id: "nord-light", theme: nordLight as Theme },
70
+ { id: "nord", theme: nord as Theme },
71
+ { id: "one-dark", theme: oneDark as Theme },
72
+ { id: "one-light", theme: oneLight as Theme },
73
+ { id: "rose-pine-dawn", theme: rosePineDawn as Theme },
74
+ { id: "rose-pine", theme: rosePine as Theme },
75
+ { id: "solarized-dark", theme: solarizedDark as Theme },
76
+ { id: "solarized-light", theme: solarizedLight as Theme },
77
+ { id: "tokyo-night-light", theme: tokyoNightLight as Theme },
78
+ { id: "tokyo-night", theme: tokyoNight as Theme },
79
+ ];
@@ -0,0 +1,12 @@
1
+ export function findDuplicateKeys(entries: Array<{ key: string }>): Set<string> {
2
+ var seen = new Map<string, number>();
3
+ var dupes = new Set<string>();
4
+ for (var i = 0; i < entries.length; i++) {
5
+ var k = entries[i].key.trim();
6
+ if (!k) continue;
7
+ var count = (seen.get(k) || 0) + 1;
8
+ seen.set(k, count);
9
+ if (count > 1) dupes.add(k);
10
+ }
11
+ return dupes;
12
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "extends": "../tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "./dist",
5
+ "rootDir": "./src",
6
+ "jsx": "react-jsx"
7
+ },
8
+ "include": [
9
+ "src"
10
+ ],
11
+ "references": [
12
+ { "path": "../shared" }
13
+ ]
14
+ }
@@ -0,0 +1,20 @@
1
+ import { defineConfig } from "vite";
2
+ import react from "@vitejs/plugin-react";
3
+ import tailwindcss from "@tailwindcss/vite";
4
+
5
+ export default defineConfig({
6
+ plugins: [tailwindcss(), react()],
7
+ server: {
8
+ host: "0.0.0.0",
9
+ open: true,
10
+ proxy: {
11
+ "/ws": {
12
+ target: "ws://localhost:7654",
13
+ ws: true,
14
+ },
15
+ "/api": {
16
+ target: "http://localhost:7654",
17
+ },
18
+ },
19
+ },
20
+ });
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@cryptiklemur/lattice",
3
+ "version": "0.0.0",
4
+ "description": "Multi-machine agentic dashboard for Claude Code. Monitor sessions, manage MCP servers and skills, orchestrate across mesh-networked nodes.",
5
+ "license": "MIT",
6
+ "author": "Aaron Scherer <me@aaronscherer.me>",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/cryptiklemur/lattice.git"
10
+ },
11
+ "homepage": "https://github.com/cryptiklemur/lattice",
12
+ "bugs": {
13
+ "url": "https://github.com/cryptiklemur/lattice/issues"
14
+ },
15
+ "keywords": [
16
+ "claude",
17
+ "claude-code",
18
+ "dashboard",
19
+ "mcp",
20
+ "agentic",
21
+ "ai",
22
+ "mesh",
23
+ "lattice"
24
+ ],
25
+ "bin": {
26
+ "lattice": "./server/src/index.ts"
27
+ },
28
+ "scripts": {
29
+ "dev": "bun run --filter '*' dev",
30
+ "build": "bun run --filter '*' build",
31
+ "lint": "bun run --filter '*' lint",
32
+ "typecheck": "bunx tsc --noEmit -p tsconfig.json"
33
+ },
34
+ "workspaces": [
35
+ "shared",
36
+ "server",
37
+ "client"
38
+ ],
39
+ "devDependencies": {
40
+ "@semantic-release/commit-analyzer": "^13.0.1",
41
+ "@semantic-release/github": "^12.0.6",
42
+ "@semantic-release/npm": "^13.1.5",
43
+ "@semantic-release/release-notes-generator": "^14.1.0",
44
+ "semantic-release": "^25.0.3"
45
+ }
46
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "@lattice/server",
3
+ "private": true,
4
+ "version": "0.0.1",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "bun --watch src/index.ts daemon",
8
+ "start": "bun src/index.ts"
9
+ },
10
+ "dependencies": {
11
+ "@anthropic-ai/claude-agent-sdk": "^0.2.79",
12
+ "@lattice/shared": "workspace:*",
13
+ "bonjour-service": "^1.3.0",
14
+ "js-tiktoken": "^1.0.21",
15
+ "node-pty": "^1.1.0",
16
+ "qrcode": "^1.5.4"
17
+ },
18
+ "devDependencies": {
19
+ "@types/qrcode": "^1.5.6",
20
+ "bun-types": "latest"
21
+ }
22
+ }
@@ -0,0 +1,48 @@
1
+ import { scryptSync, randomBytes, timingSafeEqual } from "node:crypto";
2
+
3
+ var activeSessions = new Set<string>();
4
+
5
+ export function hashPassphrase(passphrase: string): string {
6
+ var salt = randomBytes(16).toString("hex");
7
+ var hash = scryptSync(passphrase, salt, 64).toString("hex");
8
+ return salt + ":" + hash;
9
+ }
10
+
11
+ export function verifyPassphrase(passphrase: string, storedHash: string): boolean {
12
+ var parts = storedHash.split(":");
13
+ if (parts.length !== 2) {
14
+ return false;
15
+ }
16
+ var salt = parts[0];
17
+ var hash = parts[1];
18
+ try {
19
+ var derived = scryptSync(passphrase, salt, 64);
20
+ var expected = Buffer.from(hash, "hex");
21
+ if (derived.length !== expected.length) {
22
+ return false;
23
+ }
24
+ return timingSafeEqual(derived, expected);
25
+ } catch {
26
+ return false;
27
+ }
28
+ }
29
+
30
+ export function generateSessionToken(): string {
31
+ return randomBytes(32).toString("hex");
32
+ }
33
+
34
+ export function addSession(token: string): void {
35
+ activeSessions.add(token);
36
+ }
37
+
38
+ export function removeSession(token: string): void {
39
+ activeSessions.delete(token);
40
+ }
41
+
42
+ export function isValidSession(token: string): boolean {
43
+ return activeSessions.has(token);
44
+ }
45
+
46
+ export function clearSessions(): void {
47
+ activeSessions.clear();
48
+ }
@@ -0,0 +1,55 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { homedir, hostname } from "node:os";
3
+ import { join } from "node:path";
4
+ import { DEFAULT_PORT, LATTICE_HOME_DIR } from "@lattice/shared";
5
+ import type { LatticeConfig } from "@lattice/shared";
6
+
7
+ var home = join(homedir(), LATTICE_HOME_DIR);
8
+ var cachedConfig: LatticeConfig | null = null;
9
+
10
+ export function getLatticeHome(): string {
11
+ if (!existsSync(home)) {
12
+ mkdirSync(home, { recursive: true });
13
+ }
14
+ return home;
15
+ }
16
+
17
+ export function getConfigPath(): string {
18
+ return join(getLatticeHome(), "config.json");
19
+ }
20
+
21
+ export function loadConfig(): LatticeConfig {
22
+ if (cachedConfig) {
23
+ return cachedConfig;
24
+ }
25
+ var configPath = getConfigPath();
26
+ if (!existsSync(configPath)) {
27
+ return createDefaultConfig();
28
+ }
29
+ var raw = readFileSync(configPath, "utf-8");
30
+ cachedConfig = JSON.parse(raw) as LatticeConfig;
31
+ return cachedConfig;
32
+ }
33
+
34
+ export function saveConfig(config: LatticeConfig): void {
35
+ var configPath = getConfigPath();
36
+ writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
37
+ cachedConfig = config;
38
+ }
39
+
40
+ export function invalidateConfigCache(): void {
41
+ cachedConfig = null;
42
+ }
43
+
44
+ function createDefaultConfig(): LatticeConfig {
45
+ var config: LatticeConfig = {
46
+ port: DEFAULT_PORT,
47
+ name: hostname(),
48
+ tls: false,
49
+ debug: false,
50
+ globalEnv: {},
51
+ projects: [],
52
+ };
53
+ saveConfig(config);
54
+ return config;
55
+ }