@cryptiklemur/lattice 2.0.0 → 4.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.
- package/bin/lattice +6 -1
- package/dist/client/assets/{angular-html-BBi1Szz5.js → angular-html-N8PCEquT.js} +1 -1
- package/dist/client/assets/{angular-ts-2PMpSPqc.js → angular-ts-CJ8RJIPD.js} +1 -1
- package/dist/client/assets/{apl-B-NEtBvQ.js → apl-BD6tCLWN.js} +1 -1
- package/dist/client/assets/{astro-mxH1DA5Z.js → astro-CpIIfBs6.js} +1 -1
- package/dist/client/assets/{blade-BUQ9XSm3.js → blade-D3qgnjiV.js} +1 -1
- package/dist/client/assets/{c-DrQixLw7.js → c-Dr6ADN_t.js} +1 -1
- package/dist/client/assets/{cobol-42amjOMh.js → cobol-BIfDE0Hr.js} +1 -1
- package/dist/client/assets/{coffee-CMSEUKyy.js → coffee-DHQ57vfY.js} +1 -1
- package/dist/client/assets/{cpp-C4yJBzl2.js → cpp-CEBY6JOp.js} +1 -1
- package/dist/client/assets/{crystal-DZ27EoiA.js → crystal-D125CSmP.js} +1 -1
- package/dist/client/assets/{css-CdQwkSNm.js → css-CBmrkYSr.js} +1 -1
- package/dist/client/assets/{dist-CBRIe7YG.js → dist-A_mCRD1f.js} +2 -2
- package/dist/client/assets/{edge-J8VemHZC.js → edge-Ccsz7cJW.js} +1 -1
- package/dist/client/assets/{elixir-DU66qSn_.js → elixir-Do6gk14X.js} +1 -1
- package/dist/client/assets/{elm-8cz1JjRg.js → elm-Db22zT4C.js} +1 -1
- package/dist/client/assets/{erb-DMl63J6s.js → erb-MXVqAAJD.js} +1 -1
- package/dist/client/assets/{git-rebase-DjlZL8cj.js → git-rebase-B-LLWBOA.js} +1 -1
- package/dist/client/assets/{glimmer-js-Fu7vOQY-.js → glimmer-js-eWszRU73.js} +1 -1
- package/dist/client/assets/{glimmer-ts-AJljRs0A.js → glimmer-ts-VQmwGqUp.js} +1 -1
- package/dist/client/assets/{glsl-CfodGzSv.js → glsl-B8ilOfAl.js} +1 -1
- package/dist/client/assets/{graphql-C8GPKPx1.js → graphql-DnTqxeOc.js} +1 -1
- package/dist/client/assets/{hack-Gp6OuE21.js → hack-XJsHYSQb.js} +1 -1
- package/dist/client/assets/{haml-BOyG6GfM.js → haml-CQ7Vqzwp.js} +1 -1
- package/dist/client/assets/{handlebars-B9IoVRxd.js → handlebars-C4szooBf.js} +1 -1
- package/dist/client/assets/{html-CFrSukiU.js → html-B6EgAiSd.js} +1 -1
- package/dist/client/assets/{html-derivative-D0_gRK_M.js → html-derivative-DdinogQX.js} +1 -1
- package/dist/client/assets/{http-D4MmFixi.js → http-BSLxCgRq.js} +1 -1
- package/dist/client/assets/{hurl-D1xbk-LS.js → hurl-pOsTwNfp.js} +1 -1
- package/dist/client/assets/{index-DrTbNMzI.css → index-2jfMHAda.css} +1 -1
- package/dist/client/assets/{index-ZIuI5BCP.js → index-BHQ_8mvl.js} +62 -62
- package/dist/client/assets/{java-CfPMY1Dv.js → java-DRQLiiST.js} +1 -1
- package/dist/client/assets/{javascript-B8vNHeqm.js → javascript-DvEK2-47.js} +1 -1
- package/dist/client/assets/{jinja-CF0K8bFV.js → jinja-D2NYJ25y.js} +1 -1
- package/dist/client/assets/{jison-BP7my5TL.js → jison-DDZaLNAp.js} +1 -1
- package/dist/client/assets/{json-TeXNjpMZ.js → json-TGR0NIWd.js} +1 -1
- package/dist/client/assets/{jsx-C86NmHc2.js → jsx-BjUoPYga.js} +1 -1
- package/dist/client/assets/{julia-C58U_aQP.js → julia-C4gjSpFu.js} +1 -1
- package/dist/client/assets/{just-h6Vco8Qu.js → just-H351x5u_.js} +1 -1
- package/dist/client/assets/{latex-DRsNisjT.js → latex-BiTmf6gf.js} +1 -1
- package/dist/client/assets/{liquid-C9jXC9M7.js → liquid-86ufjRy-.js} +1 -1
- package/dist/client/assets/{lua-BUYvdn-F.js → lua-BNxR0F_8.js} +1 -1
- package/dist/client/assets/{marko-BqB4tqw-.js → marko-CvRxpRjM.js} +1 -1
- package/dist/client/assets/{mdc-C8Rs68Nw.js → mdc-CYbAIy2C.js} +1 -1
- package/dist/client/assets/{nginx-Dj6E3HRL.js → nginx-egdgMq-F.js} +1 -1
- package/dist/client/assets/{nim-BizJb4iF.js → nim-CXBJVz_w.js} +1 -1
- package/dist/client/assets/{perl-DnJAtWNn.js → perl-XRfMobzg.js} +1 -1
- package/dist/client/assets/{php-BeY_VEeb.js → php-Br7a8uil.js} +1 -1
- package/dist/client/assets/{pug-DXhFbVDh.js → pug-BVbbUVvy.js} +1 -1
- package/dist/client/assets/{qml-CngzXsz8.js → qml-ByKvrL1j.js} +1 -1
- package/dist/client/assets/{r-BMmy9apu.js → r-mVoV0Ni6.js} +1 -1
- package/dist/client/assets/{razor-kIo5DNUk.js → razor-T5O-9UJL.js} +1 -1
- package/dist/client/assets/{regexp-BIa5IayX.js → regexp-CioRuhuN.js} +1 -1
- package/dist/client/assets/{rst-McWv3WP0.js → rst-V__uTudD.js} +1 -1
- package/dist/client/assets/{ruby-CkenUDKe.js → ruby-C_PuKPTI.js} +1 -1
- package/dist/client/assets/{sas-Dgn9Yrr5.js → sas-D_DqqQH4.js} +1 -1
- package/dist/client/assets/{scss-Tfn9jzBB.js → scss-D-TjzZ4c.js} +1 -1
- package/dist/client/assets/{shellscript-vGpgBWOS.js → shellscript-E5759VHu.js} +1 -1
- package/dist/client/assets/{shellsession-7CA0dOzR.js → shellsession-AESTM-Pv.js} +1 -1
- package/dist/client/assets/{soy-DbBURueN.js → soy-QrbrrcDv.js} +1 -1
- package/dist/client/assets/{sql-BJGtbEM8.js → sql-0M8VcDHD.js} +1 -1
- package/dist/client/assets/{stata-L0kV9FQT.js → stata-CgeIpGtc.js} +1 -1
- package/dist/client/assets/{surrealql-C17jcHRl.js → surrealql-DBGwnZbw.js} +1 -1
- package/dist/client/assets/{svelte-B5_CmVcu.js → svelte-Cv0PvUc_.js} +1 -1
- package/dist/client/assets/{templ-C5f2EORt.js → templ-B9t7xRE4.js} +1 -1
- package/dist/client/assets/{tex-DvaBtCMN.js → tex-DhZZ8dr2.js} +1 -1
- package/dist/client/assets/{ts-tags-DlZzQdBU.js → ts-tags-BFv8sbnd.js} +1 -1
- package/dist/client/assets/{tsx-DaLOIju9.js → tsx-CXC9KSbY.js} +1 -1
- package/dist/client/assets/{twig-BB7320dl.js → twig-CM_OO66r.js} +1 -1
- package/dist/client/assets/{typescript-D8B-VgXj.js → typescript-BdgOTaoD.js} +1 -1
- package/dist/client/assets/{vue-DylGFDrG.js → vue-BnQhjnCm.js} +1 -1
- package/dist/client/assets/{vue-html-Dt8r3B9y.js → vue-html-CNnGecRI.js} +1 -1
- package/dist/client/assets/{vue-vine-DdN02uhY.js → vue-vine-DCuMkRhK.js} +1 -1
- package/dist/client/assets/{xml-CBEuB6I0.js → xml-CbTD7cB8.js} +1 -1
- package/dist/client/assets/{xsl-CuhlgDL5.js → xsl-uOqqo7cf.js} +1 -1
- package/dist/client/assets/{yaml-Da6ymghi.js → yaml-BNrLoH59.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/client/sw.js +1 -1
- package/package.json +5 -2
- package/src/client/components/analytics/AnalyticsView.tsx +1 -1
- package/src/client/components/analytics/ChartCard.tsx +1 -1
- package/src/client/components/analytics/charts/NodeFleetOverview.tsx +1 -1
- package/src/client/components/chat/AttachmentChips.tsx +4 -4
- package/src/client/components/chat/ChatView.tsx +2 -2
- package/src/client/components/chat/CommandPalette.tsx +1 -1
- package/src/client/components/chat/ElicitationCard.tsx +3 -0
- package/src/client/components/chat/Message.tsx +7 -6
- package/src/client/components/chat/PromptQuestion.tsx +1 -1
- package/src/client/components/chat/TodoCard.tsx +1 -1
- package/src/client/components/chat/ToolGroup.tsx +1 -1
- package/src/client/components/chat/ToolResultRenderer.tsx +2 -2
- package/src/client/components/dashboard/DashboardView.tsx +1 -1
- package/src/client/components/dashboard/ProjectDashboardView.tsx +1 -1
- package/src/client/components/mesh/NodeBadge.tsx +1 -1
- package/src/client/components/mesh/PairingDialog.tsx +2 -2
- package/src/client/components/project-settings/ProjectClaude.tsx +1 -1
- package/src/client/components/project-settings/ProjectEnvironment.tsx +1 -1
- package/src/client/components/project-settings/ProjectGeneral.tsx +1 -1
- package/src/client/components/project-settings/ProjectMcp.tsx +1 -1
- package/src/client/components/project-settings/ProjectMemory.tsx +3 -3
- package/src/client/components/project-settings/ProjectPermissions.tsx +1 -1
- package/src/client/components/project-settings/ProjectPlugins.tsx +1 -1
- package/src/client/components/project-settings/ProjectRules.tsx +1 -1
- package/src/client/components/project-settings/ProjectSettingsView.tsx +1 -1
- package/src/client/components/project-settings/ProjectSkills.tsx +1 -1
- package/src/client/components/settings/Appearance.tsx +1 -1
- package/src/client/components/settings/BudgetSettings.tsx +1 -1
- package/src/client/components/settings/ClaudeSettings.tsx +1 -1
- package/src/client/components/settings/Editor.tsx +1 -1
- package/src/client/components/settings/Environment.tsx +1 -1
- package/src/client/components/settings/GlobalMcp.tsx +2 -2
- package/src/client/components/settings/GlobalPlugins.tsx +2 -2
- package/src/client/components/settings/GlobalRules.tsx +1 -1
- package/src/client/components/settings/GlobalSkills.tsx +1 -1
- package/src/client/components/settings/MeshStatus.tsx +1 -1
- package/src/client/components/settings/SkillMarketplace.tsx +1 -1
- package/src/client/components/settings/ThemeWizard.tsx +1 -1
- package/src/client/components/settings/mcp-shared.tsx +1 -1
- package/src/client/components/settings/skill-shared.tsx +2 -2
- package/src/client/components/setup/SetupWizard.tsx +5 -0
- package/src/client/components/sidebar/AddProjectModal.tsx +2 -2
- package/src/client/components/sidebar/NodeSettingsModal.tsx +2 -2
- package/src/client/components/sidebar/ProjectRail.tsx +1 -1
- package/src/client/components/sidebar/SessionList.tsx +2 -2
- package/src/client/components/sidebar/Sidebar.tsx +1 -1
- package/src/client/components/sidebar/UserIsland.tsx +1 -1
- package/src/client/components/ui/CommandPalette.tsx +1 -1
- package/src/client/components/ui/IconPicker.tsx +3 -1
- package/src/client/components/ui/KeyboardShortcuts.tsx +1 -1
- package/src/client/components/ui/UpdateBanner.tsx +1 -1
- package/src/client/components/workspace/BookmarksView.tsx +2 -2
- package/src/client/components/workspace/FileBrowser.tsx +1 -1
- package/src/client/components/workspace/FileTree.tsx +1 -1
- package/src/client/components/workspace/NoteCard.tsx +2 -1
- package/src/client/components/workspace/NotesView.tsx +1 -1
- package/src/client/components/workspace/ScheduledTasksView.tsx +1 -1
- package/src/client/components/workspace/TaskCard.tsx +2 -1
- package/src/client/components/workspace/TaskEditModal.tsx +2 -2
- package/src/client/components/workspace/TerminalInstance.tsx +1 -1
- package/src/client/hooks/useAnalytics.ts +7 -7
- package/src/client/hooks/useAttachments.ts +49 -16
- package/src/client/hooks/useBookmarks.ts +1 -1
- package/src/client/hooks/useEditorConfig.ts +1 -1
- package/src/client/hooks/useFocusTrap.ts +4 -2
- package/src/client/hooks/useIdleDetection.ts +6 -0
- package/src/client/hooks/useMesh.ts +1 -1
- package/src/client/hooks/useProjectSettings.ts +1 -1
- package/src/client/hooks/useProjects.ts +3 -3
- package/src/client/hooks/useSession.ts +31 -32
- package/src/client/hooks/useSkills.ts +2 -2
- package/src/client/hooks/useSpinnerVerb.ts +1 -1
- package/src/client/hooks/useVoiceRecorder.ts +5 -2
- package/src/client/hooks/useWebSocket.ts +1 -1
- package/src/client/providers/WebSocketProvider.tsx +9 -1
- package/src/client/router.tsx +1 -1
- package/src/client/stores/analytics.ts +1 -1
- package/src/client/stores/bookmarks.ts +1 -1
- package/src/client/stores/mesh.ts +1 -1
- package/src/client/stores/session.ts +1 -11
- package/src/client/stores/sidebar.ts +1 -1
- package/src/client/styles/global.css +12 -0
- package/src/server/analytics/engine.ts +1 -1
- package/src/server/auth/passphrase.ts +16 -6
- package/src/server/config.ts +2 -2
- package/src/server/daemon.ts +32 -12
- package/src/server/features/ralph-loop.ts +1 -1
- package/src/server/features/scheduler.ts +1 -1
- package/src/server/features/sticky-notes.ts +1 -1
- package/src/server/handlers/analytics.ts +1 -1
- package/src/server/handlers/attachment.ts +4 -3
- package/src/server/handlers/bookmarks.ts +1 -1
- package/src/server/handlers/chat.ts +1 -1
- package/src/server/handlers/editor.ts +1 -1
- package/src/server/handlers/fs.ts +1 -1
- package/src/server/handlers/loop.ts +1 -1
- package/src/server/handlers/memory.ts +1 -1
- package/src/server/handlers/mesh.ts +3 -3
- package/src/server/handlers/notes.ts +1 -1
- package/src/server/handlers/plugins.ts +1 -1
- package/src/server/handlers/project-settings.ts +1 -1
- package/src/server/handlers/scheduler.ts +1 -1
- package/src/server/handlers/session.ts +2 -1
- package/src/server/handlers/settings.ts +4 -4
- package/src/server/handlers/skills.ts +5 -5
- package/src/server/handlers/terminal.ts +12 -1
- package/src/server/handlers/themes.ts +1 -1
- package/src/server/handlers/update.ts +1 -1
- package/src/server/identity.ts +3 -1
- package/src/server/index.ts +2 -2
- package/src/server/mesh/connector.ts +1 -1
- package/src/server/mesh/peers.ts +1 -1
- package/src/server/mesh/proxy.ts +1 -1
- package/src/server/mesh/session-sync.ts +1 -1
- package/src/server/project/bookmarks.ts +1 -1
- package/src/server/project/context-breakdown.ts +1 -1
- package/src/server/project/file-browser.ts +1 -1
- package/src/server/project/registry.ts +1 -1
- package/src/server/project/sdk-bridge.ts +28 -2
- package/src/server/project/session.ts +7 -6
- package/src/server/tls.ts +15 -1
- package/src/server/tui.ts +2 -2
- package/src/server/ws/router.ts +1 -1
- package/tsconfig.json +1 -1
- package/vite.config.ts +1 -1
package/src/server/daemon.ts
CHANGED
|
@@ -18,7 +18,7 @@ import { startMeshConnections, onPeerConnected, onPeerDisconnected, onPeerMessag
|
|
|
18
18
|
import { handleProxyRequest, handleProxyResponse } from "./mesh/proxy";
|
|
19
19
|
import { verifyPassphrase, generateSessionToken, addSession, isValidSession } from "./auth/passphrase";
|
|
20
20
|
import { ensureCerts } from "./tls";
|
|
21
|
-
import type { ClientMessage, MeshMessage } from "
|
|
21
|
+
import type { ClientMessage, MeshMessage } from "#shared";
|
|
22
22
|
import { log } from "./logger";
|
|
23
23
|
import { detectIdeProjectName } from "./handlers/settings";
|
|
24
24
|
import "./handlers/session";
|
|
@@ -336,9 +336,26 @@ export async function startDaemon(portOverride?: number | null): Promise<void> {
|
|
|
336
336
|
var app = express();
|
|
337
337
|
app.use(express.json());
|
|
338
338
|
|
|
339
|
-
|
|
339
|
+
var authAttempts = new Map<string, number[]>();
|
|
340
|
+
var AUTH_RATE_LIMIT = 5;
|
|
341
|
+
var AUTH_RATE_WINDOW = 60000;
|
|
342
|
+
|
|
343
|
+
app.post("/auth", async function (req, res) {
|
|
344
|
+
var ip = req.ip || req.socket.remoteAddress || "unknown";
|
|
345
|
+
var now = Date.now();
|
|
346
|
+
var attempts = authAttempts.get(ip) || [];
|
|
347
|
+
attempts = attempts.filter(function (t) { return now - t < AUTH_RATE_WINDOW; });
|
|
348
|
+
|
|
349
|
+
if (attempts.length >= AUTH_RATE_LIMIT) {
|
|
350
|
+
res.status(429).json({ ok: false, error: "Too many attempts. Try again later." });
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
attempts.push(now);
|
|
355
|
+
authAttempts.set(ip, attempts);
|
|
356
|
+
|
|
340
357
|
var passphrase = (req.body as { passphrase?: string }).passphrase || "";
|
|
341
|
-
if (!config.passphraseHash || verifyPassphrase(passphrase, config.passphraseHash)) {
|
|
358
|
+
if (!config.passphraseHash || await verifyPassphrase(passphrase, config.passphraseHash)) {
|
|
342
359
|
var token = generateSessionToken();
|
|
343
360
|
addSession(token);
|
|
344
361
|
res.setHeader("Set-Cookie", "lattice_auth=" + token + "; HttpOnly; Path=/; SameSite=Strict");
|
|
@@ -381,20 +398,23 @@ export async function startDaemon(portOverride?: number | null): Promise<void> {
|
|
|
381
398
|
res.status(400).send("Missing path parameter");
|
|
382
399
|
return;
|
|
383
400
|
}
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
401
|
+
|
|
402
|
+
var resolved: string | null = null;
|
|
403
|
+
|
|
404
|
+
for (var pi = 0; pi < config.projects.length; pi++) {
|
|
405
|
+
var projectPath = resolve(config.projects[pi].path);
|
|
406
|
+
var candidate = resolve(projectPath, reqFilePath);
|
|
407
|
+
if (candidate.startsWith(projectPath + "/") && existsSync(candidate)) {
|
|
408
|
+
resolved = candidate;
|
|
409
|
+
break;
|
|
392
410
|
}
|
|
393
411
|
}
|
|
394
|
-
|
|
412
|
+
|
|
413
|
+
if (!resolved) {
|
|
395
414
|
res.status(404).send("File not found");
|
|
396
415
|
return;
|
|
397
416
|
}
|
|
417
|
+
|
|
398
418
|
var stat = statSync(resolved);
|
|
399
419
|
res.setHeader("Content-Type", getMimeType(resolved));
|
|
400
420
|
res.setHeader("Content-Length", stat.size);
|
|
@@ -5,7 +5,7 @@ import { query } from "@anthropic-ai/claude-agent-sdk";
|
|
|
5
5
|
import type { SDKMessage, SDKPartialAssistantMessage, SDKResultMessage } from "@anthropic-ai/claude-agent-sdk";
|
|
6
6
|
import { broadcast } from "../ws/broadcast";
|
|
7
7
|
import { getProjectBySlug } from "../project/registry";
|
|
8
|
-
import type { LoopStatus } from "
|
|
8
|
+
import type { LoopStatus } from "#shared";
|
|
9
9
|
|
|
10
10
|
var activeLoops = new Map<string, LoopStatus>();
|
|
11
11
|
|
|
@@ -3,7 +3,7 @@ import { join } from "node:path";
|
|
|
3
3
|
import { randomBytes } from "node:crypto";
|
|
4
4
|
import { getLatticeHome } from "../config";
|
|
5
5
|
import { broadcast } from "../ws/broadcast";
|
|
6
|
-
import type { ScheduledTask } from "
|
|
6
|
+
import type { ScheduledTask } from "#shared";
|
|
7
7
|
|
|
8
8
|
var schedulesFile = "";
|
|
9
9
|
var tasks: ScheduledTask[] = [];
|
|
@@ -2,7 +2,7 @@ import { appendFileSync, existsSync, mkdirSync, readFileSync, renameSync, writeF
|
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { randomBytes } from "node:crypto";
|
|
4
4
|
import { getLatticeHome } from "../config";
|
|
5
|
-
import type { StickyNote } from "
|
|
5
|
+
import type { StickyNote } from "#shared";
|
|
6
6
|
|
|
7
7
|
var notesFile = "";
|
|
8
8
|
var notes: StickyNote[] = [];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { Attachment } from "
|
|
2
|
-
import type { AttachmentChunkMessage, AttachmentCompleteMessage, ClientMessage } from "
|
|
1
|
+
import type { Attachment } from "#shared";
|
|
2
|
+
import type { AttachmentChunkMessage, AttachmentCompleteMessage, ClientMessage } from "#shared";
|
|
3
3
|
import { registerHandler } from "../ws/router";
|
|
4
4
|
import { sendTo } from "../ws/broadcast";
|
|
5
5
|
|
|
@@ -176,7 +176,7 @@ export function cleanupClient(clientId: string): void {
|
|
|
176
176
|
completed.delete(clientId);
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
-
setInterval(function () {
|
|
179
|
+
var ttlCleanupInterval = setInterval(function () {
|
|
180
180
|
var now = Date.now();
|
|
181
181
|
stores.forEach(function (store) {
|
|
182
182
|
store.forEach(function (pending, id) {
|
|
@@ -186,3 +186,4 @@ setInterval(function () {
|
|
|
186
186
|
});
|
|
187
187
|
});
|
|
188
188
|
}, CLEANUP_INTERVAL_MS);
|
|
189
|
+
ttlCleanupInterval.unref();
|
|
@@ -3,7 +3,7 @@ import type {
|
|
|
3
3
|
BookmarkListMessage,
|
|
4
4
|
BookmarkAddMessage,
|
|
5
5
|
BookmarkRemoveMessage,
|
|
6
|
-
} from "
|
|
6
|
+
} from "#shared";
|
|
7
7
|
import { registerHandler } from "../ws/router";
|
|
8
8
|
import { sendTo } from "../ws/broadcast";
|
|
9
9
|
import { listBookmarks, addBookmark, removeBookmark } from "../project/bookmarks";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ChatSendMessage, ChatPermissionResponseMessage, ChatSetPermissionModeMessage, ChatPromptResponseMessage, ClientMessage } from "
|
|
1
|
+
import type { ChatSendMessage, ChatPermissionResponseMessage, ChatSetPermissionModeMessage, ChatPromptResponseMessage, ClientMessage } from "#shared";
|
|
2
2
|
import { registerHandler } from "../ws/router";
|
|
3
3
|
import { sendTo } from "../ws/broadcast";
|
|
4
4
|
import { getProjectBySlug } from "../project/registry";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { execSync } from "node:child_process";
|
|
2
2
|
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
-
import type { ClientMessage, EditorDetectMessage, EditorEnsureProjectMessage } from "
|
|
4
|
+
import type { ClientMessage, EditorDetectMessage, EditorEnsureProjectMessage } from "#shared";
|
|
5
5
|
import { registerHandler } from "../ws/router";
|
|
6
6
|
import { sendTo } from "../ws/broadcast";
|
|
7
7
|
import { loadConfig } from "../config";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ClientMessage, FsListMessage, FsReadMessage, FsWriteMessage } from "
|
|
1
|
+
import type { ClientMessage, FsListMessage, FsReadMessage, FsWriteMessage } from "#shared";
|
|
2
2
|
import { registerHandler } from "../ws/router";
|
|
3
3
|
import { sendTo, broadcast } from "../ws/broadcast";
|
|
4
4
|
import { getProjectBySlug } from "../project/registry";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ClientMessage, LoopStartMessage, LoopStopMessage, LoopStatusRequestMessage } from "
|
|
1
|
+
import type { ClientMessage, LoopStartMessage, LoopStopMessage, LoopStatusRequestMessage } from "#shared";
|
|
2
2
|
import { registerHandler } from "../ws/router";
|
|
3
3
|
import { sendTo } from "../ws/broadcast";
|
|
4
4
|
import { startLoop, stopLoop, getLoopStatus } from "../features/ralph-loop";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync, readFileSync, writeFileSync, readdirSync, unlinkSync, mkdirSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
|
-
import type { ClientMessage } from "
|
|
4
|
+
import type { ClientMessage } from "#shared";
|
|
5
5
|
import { registerHandler } from "../ws/router";
|
|
6
6
|
import { sendTo } from "../ws/broadcast";
|
|
7
7
|
import { loadConfig } from "../config";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { ClientMessage, MeshPairMessage, MeshUnpairMessage, NodeInfo } from "
|
|
1
|
+
import type { ClientMessage, MeshPairMessage, MeshUnpairMessage, NodeInfo } from "#shared";
|
|
2
2
|
import { log } from "../logger";
|
|
3
3
|
import { handleProxyRequest, handleProxyResponse } from "../mesh/proxy";
|
|
4
|
-
import type { MeshProxyRequestMessage, MeshProxyResponseMessage } from "
|
|
4
|
+
import type { MeshProxyRequestMessage, MeshProxyResponseMessage } from "#shared";
|
|
5
5
|
import { registerHandler } from "../ws/router";
|
|
6
6
|
import { sendTo, broadcast } from "../ws/broadcast";
|
|
7
7
|
import { loadConfig } from "../config";
|
|
@@ -10,7 +10,7 @@ import { generateInviteCode, parseInviteCode, validatePairingToken, consumePairi
|
|
|
10
10
|
import { addPeer, removePeer, loadPeers, getPeer } from "../mesh/peers";
|
|
11
11
|
import { getConnectedPeerIds, connectToPeer, reconnectPeer, getPeerConnection, disconnectPeer, getConnectedPeerProjects, registerInboundPeer } from "../mesh/connector";
|
|
12
12
|
import { getClientWebSocket, registerVirtualClient, removeVirtualClient } from "../ws/broadcast";
|
|
13
|
-
import type { PeerInfo } from "
|
|
13
|
+
import type { PeerInfo } from "#shared";
|
|
14
14
|
import { networkInterfaces } from "node:os";
|
|
15
15
|
import { existsSync, readFileSync } from "node:fs";
|
|
16
16
|
import { execSync } from "node:child_process";
|
|
@@ -4,7 +4,7 @@ import type {
|
|
|
4
4
|
NotesCreateMessage,
|
|
5
5
|
NotesUpdateMessage,
|
|
6
6
|
NotesDeleteMessage,
|
|
7
|
-
} from "
|
|
7
|
+
} from "#shared";
|
|
8
8
|
import { registerHandler } from "../ws/router";
|
|
9
9
|
import { sendTo, broadcast } from "../ws/broadcast";
|
|
10
10
|
import { listNotes, createNote, updateNote, deleteNote } from "../features/sticky-notes";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ClientMessage, ProjectSettingsGetMessage, ProjectSettingsUpdateMessage, ProjectSettings, McpServerConfig } from "
|
|
1
|
+
import type { ClientMessage, ProjectSettingsGetMessage, ProjectSettingsUpdateMessage, ProjectSettings, McpServerConfig } from "#shared";
|
|
2
2
|
import { registerHandler } from "../ws/router";
|
|
3
3
|
import { sendTo } from "../ws/broadcast";
|
|
4
4
|
import { loadConfig, saveConfig, invalidateConfigCache } from "../config";
|
|
@@ -4,7 +4,7 @@ import type {
|
|
|
4
4
|
SchedulerDeleteMessage,
|
|
5
5
|
SchedulerToggleMessage,
|
|
6
6
|
SchedulerUpdateMessage,
|
|
7
|
-
} from "
|
|
7
|
+
} from "#shared";
|
|
8
8
|
import { registerHandler } from "../ws/router";
|
|
9
9
|
import { sendTo } from "../ws/broadcast";
|
|
10
10
|
import { listTasks, createTask, deleteTask, toggleTask, updateTask } from "../features/scheduler";
|
|
@@ -7,7 +7,7 @@ import type {
|
|
|
7
7
|
SessionListRequestMessage,
|
|
8
8
|
SessionPreviewRequestMessage,
|
|
9
9
|
SessionRenameMessage,
|
|
10
|
-
} from "
|
|
10
|
+
} from "#shared";
|
|
11
11
|
import { registerHandler } from "../ws/router";
|
|
12
12
|
import { sendTo } from "../ws/broadcast";
|
|
13
13
|
import { loadConfig } from "../config";
|
|
@@ -91,6 +91,7 @@ registerHandler("session", function (clientId: string, message: ClientMessage) {
|
|
|
91
91
|
sessionId: pageMsg.sessionId,
|
|
92
92
|
messages: page.messages,
|
|
93
93
|
hasMore: page.hasMore,
|
|
94
|
+
totalMessages: page.totalMessages,
|
|
94
95
|
});
|
|
95
96
|
});
|
|
96
97
|
return;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type { ClientMessage, SettingsGetMessage, SettingsUpdateMessage } from "
|
|
1
|
+
import type { ClientMessage, SettingsGetMessage, SettingsUpdateMessage } from "#shared";
|
|
2
2
|
import { registerHandler } from "../ws/router";
|
|
3
3
|
import { sendTo, broadcast } from "../ws/broadcast";
|
|
4
4
|
import { loadConfig, saveConfig } from "../config";
|
|
5
5
|
import { addProject, removeProject } from "../project/registry";
|
|
6
|
-
import type { LatticeConfig } from "
|
|
6
|
+
import type { LatticeConfig } from "#shared";
|
|
7
7
|
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
8
8
|
import { join } from "node:path";
|
|
9
9
|
import { homedir } from "node:os";
|
|
@@ -67,7 +67,7 @@ registerHandler("settings", function (clientId: string, message: ClientMessage)
|
|
|
67
67
|
sendTo(clientId, {
|
|
68
68
|
type: "settings:data",
|
|
69
69
|
config: configWithClaudeMd,
|
|
70
|
-
mcpServers: readGlobalMcpServers() as Record<string, import("
|
|
70
|
+
mcpServers: readGlobalMcpServers() as Record<string, import("#shared").McpServerConfig>,
|
|
71
71
|
globalSkills: readGlobalSkills(),
|
|
72
72
|
globalRules: readGlobalRules(),
|
|
73
73
|
spinnerVerbs: loadSpinnerVerbs(),
|
|
@@ -130,7 +130,7 @@ registerHandler("settings", function (clientId: string, message: ClientMessage)
|
|
|
130
130
|
sendTo(clientId, {
|
|
131
131
|
type: "settings:data",
|
|
132
132
|
config: updatedWithClaudeMd,
|
|
133
|
-
mcpServers: readGlobalMcpServers() as Record<string, import("
|
|
133
|
+
mcpServers: readGlobalMcpServers() as Record<string, import("#shared").McpServerConfig>,
|
|
134
134
|
globalSkills: readGlobalSkills(),
|
|
135
135
|
globalRules: readGlobalRules(),
|
|
136
136
|
spinnerVerbs: loadSpinnerVerbs(),
|
|
@@ -2,8 +2,8 @@ import { readdirSync, readFileSync, existsSync, lstatSync, realpathSync, statSyn
|
|
|
2
2
|
import { join, sep, dirname } from "node:path";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
4
|
import { execSync, spawn } from "node:child_process";
|
|
5
|
-
import type { ClientMessage } from "
|
|
6
|
-
import type { SkillInfo } from "
|
|
5
|
+
import type { ClientMessage } from "#shared";
|
|
6
|
+
import type { SkillInfo } from "#shared";
|
|
7
7
|
import { registerHandler } from "../ws/router";
|
|
8
8
|
import { sendTo } from "../ws/broadcast";
|
|
9
9
|
import { loadConfig } from "../config";
|
|
@@ -292,7 +292,7 @@ registerHandler("skills", function (clientId: string, message: ClientMessage) {
|
|
|
292
292
|
sendTo(clientId, {
|
|
293
293
|
type: "settings:data",
|
|
294
294
|
config: globalConfig,
|
|
295
|
-
mcpServers: readGlobalMcpServers() as Record<string, import("
|
|
295
|
+
mcpServers: readGlobalMcpServers() as Record<string, import("#shared").McpServerConfig>,
|
|
296
296
|
globalSkills: readGlobalSkills(),
|
|
297
297
|
});
|
|
298
298
|
}
|
|
@@ -333,7 +333,7 @@ registerHandler("skills", function (clientId: string, message: ClientMessage) {
|
|
|
333
333
|
sendTo(clientId, {
|
|
334
334
|
type: "settings:data",
|
|
335
335
|
config: delConfig,
|
|
336
|
-
mcpServers: readGlobalMcpServers() as Record<string, import("
|
|
336
|
+
mcpServers: readGlobalMcpServers() as Record<string, import("#shared").McpServerConfig>,
|
|
337
337
|
globalSkills: readGlobalSkills(),
|
|
338
338
|
});
|
|
339
339
|
} catch (err) {
|
|
@@ -366,7 +366,7 @@ registerHandler("skills", function (clientId: string, message: ClientMessage) {
|
|
|
366
366
|
sendTo(clientId, {
|
|
367
367
|
type: "settings:data",
|
|
368
368
|
config: updConfig,
|
|
369
|
-
mcpServers: readGlobalMcpServers() as Record<string, import("
|
|
369
|
+
mcpServers: readGlobalMcpServers() as Record<string, import("#shared").McpServerConfig>,
|
|
370
370
|
globalSkills: readGlobalSkills(),
|
|
371
371
|
});
|
|
372
372
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ClientMessage, TerminalCreateMessage, TerminalInputMessage, TerminalResizeMessage } from "
|
|
1
|
+
import type { ClientMessage, TerminalCreateMessage, TerminalInputMessage, TerminalResizeMessage } from "#shared";
|
|
2
2
|
import { registerHandler } from "../ws/router";
|
|
3
3
|
import { sendTo } from "../ws/broadcast";
|
|
4
4
|
import { createTerminal, destroyTerminal, writeToTerminal, resizeTerminal } from "../project/terminal";
|
|
@@ -65,12 +65,23 @@ registerHandler("terminal", function(clientId: string, message: ClientMessage) {
|
|
|
65
65
|
|
|
66
66
|
if (message.type === "terminal:input") {
|
|
67
67
|
var inputMsg = message as TerminalInputMessage;
|
|
68
|
+
var clientSet = clientTerminals.get(clientId);
|
|
69
|
+
if (!clientSet || !clientSet.has(inputMsg.termId)) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
if (typeof inputMsg.data === "string" && inputMsg.data.length > 65536) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
68
75
|
writeToTerminal(inputMsg.termId, inputMsg.data);
|
|
69
76
|
return;
|
|
70
77
|
}
|
|
71
78
|
|
|
72
79
|
if (message.type === "terminal:resize") {
|
|
73
80
|
var resizeMsg = message as TerminalResizeMessage;
|
|
81
|
+
var resizeClientSet = clientTerminals.get(clientId);
|
|
82
|
+
if (!resizeClientSet || !resizeClientSet.has(resizeMsg.termId)) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
74
85
|
resizeTerminal(resizeMsg.termId, resizeMsg.cols, resizeMsg.rows);
|
|
75
86
|
return;
|
|
76
87
|
}
|
|
@@ -4,7 +4,7 @@ import type {
|
|
|
4
4
|
ClientMessage,
|
|
5
5
|
ThemeSaveMessage,
|
|
6
6
|
ThemeDeleteMessage,
|
|
7
|
-
} from "
|
|
7
|
+
} from "#shared";
|
|
8
8
|
import { registerHandler } from "../ws/router";
|
|
9
9
|
import { sendTo, broadcast } from "../ws/broadcast";
|
|
10
10
|
import { getLatticeHome } from "../config";
|
|
@@ -2,7 +2,7 @@ import { chmodSync, writeFileSync, accessSync, copyFileSync, unlinkSync, constan
|
|
|
2
2
|
import { tmpdir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { execSync, spawn } from "node:child_process";
|
|
5
|
-
import type { ClientMessage } from "
|
|
5
|
+
import type { ClientMessage } from "#shared";
|
|
6
6
|
import { registerHandler } from "../ws/router";
|
|
7
7
|
import { sendTo, broadcast } from "../ws/broadcast";
|
|
8
8
|
import { checkForUpdate, getPackageName, getGitHubRepo, getInstallMode } from "../update-checker";
|
package/src/server/identity.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync, chmodSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { randomUUID, generateKeyPairSync } from "node:crypto";
|
|
4
4
|
import { getLatticeHome } from "./config";
|
|
@@ -25,6 +25,7 @@ export function loadOrCreateIdentity(): NodeIdentity {
|
|
|
25
25
|
stored.publicKey = keys.publicKey;
|
|
26
26
|
stored.privateKey = keys.privateKey;
|
|
27
27
|
writeFileSync(path, JSON.stringify(stored, null, 2), "utf-8");
|
|
28
|
+
chmodSync(path, 0o600);
|
|
28
29
|
return stored;
|
|
29
30
|
}
|
|
30
31
|
var keys = generateEd25519Keypair();
|
|
@@ -35,6 +36,7 @@ export function loadOrCreateIdentity(): NodeIdentity {
|
|
|
35
36
|
createdAt: Date.now(),
|
|
36
37
|
};
|
|
37
38
|
writeFileSync(path, JSON.stringify(identity, null, 2), "utf-8");
|
|
39
|
+
chmodSync(path, 0o600);
|
|
38
40
|
return identity;
|
|
39
41
|
}
|
|
40
42
|
|
package/src/server/index.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { existsSync, readFileSync, writeFileSync, unlinkSync, openSync } from "n
|
|
|
6
6
|
import { join, dirname } from "node:path";
|
|
7
7
|
import { fileURLToPath } from "node:url";
|
|
8
8
|
import { spawn, execSync } from "node:child_process";
|
|
9
|
-
import { DAEMON_PID_FILE } from "
|
|
9
|
+
import { DAEMON_PID_FILE } from "#shared";
|
|
10
10
|
import { getLatticeHome, loadConfig } from "./config";
|
|
11
11
|
|
|
12
12
|
var __filename_local = fileURLToPath(import.meta.url);
|
|
@@ -143,7 +143,7 @@ async function runDaemon(): Promise<void> {
|
|
|
143
143
|
if (onboarding.passphrase) {
|
|
144
144
|
var { hashPassphrase } = await import("./auth/passphrase");
|
|
145
145
|
var config = loadConfig();
|
|
146
|
-
config.passphraseHash = hashPassphrase(onboarding.passphrase);
|
|
146
|
+
config.passphraseHash = await hashPassphrase(onboarding.passphrase);
|
|
147
147
|
var { saveConfig: saveCfg } = await import("./config");
|
|
148
148
|
saveCfg(config);
|
|
149
149
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { MeshMessage, MeshHelloMessage, MeshSessionSyncMessage, MeshSessionRequestMessage } from "
|
|
1
|
+
import type { MeshMessage, MeshHelloMessage, MeshSessionSyncMessage, MeshSessionRequestMessage } from "#shared";
|
|
2
2
|
import * as peersModule from "./peers";
|
|
3
3
|
import { loadPeers } from "./peers";
|
|
4
4
|
import { loadOrCreateIdentity } from "../identity";
|
package/src/server/mesh/peers.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
-
import type { PeerInfo } from "
|
|
3
|
+
import type { PeerInfo } from "#shared";
|
|
4
4
|
import { getLatticeHome } from "../config";
|
|
5
5
|
|
|
6
6
|
function getPeersPath(): string {
|
package/src/server/mesh/proxy.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
-
import type { ClientMessage, MeshProxyRequestMessage, MeshProxyResponseMessage, ServerMessage } from "
|
|
2
|
+
import type { ClientMessage, MeshProxyRequestMessage, MeshProxyResponseMessage, ServerMessage } from "#shared";
|
|
3
3
|
import { getPeerConnection } from "./connector";
|
|
4
4
|
import { sendTo, broadcast, registerVirtualClient, removeVirtualClient } from "../ws/broadcast";
|
|
5
5
|
import { routeMessage } from "../ws/router";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readFileSync, appendFileSync, statSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
|
-
import type { MeshSessionSyncMessage, MeshSessionRequestMessage } from "
|
|
4
|
+
import type { MeshSessionSyncMessage, MeshSessionRequestMessage } from "#shared";
|
|
5
5
|
import { getConnectedPeerIds, getPeerConnection } from "./connector";
|
|
6
6
|
import { getLatticeHome } from "../config";
|
|
7
7
|
|
|
@@ -2,7 +2,7 @@ import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "
|
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { randomBytes } from "node:crypto";
|
|
4
4
|
import { getLatticeHome } from "../config";
|
|
5
|
-
import type { MessageBookmark } from "
|
|
5
|
+
import type { MessageBookmark } from "#shared";
|
|
6
6
|
|
|
7
7
|
var bookmarksFile = "";
|
|
8
8
|
var bookmarks: MessageBookmark[] = [];
|
|
@@ -2,7 +2,7 @@ import { encodingForModel } from "js-tiktoken";
|
|
|
2
2
|
import { existsSync, readFileSync, readdirSync, openSync, readSync, fstatSync, closeSync } from "node:fs";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { homedir } from "node:os";
|
|
5
|
-
import type { ContextBreakdownSegment } from "
|
|
5
|
+
import type { ContextBreakdownSegment } from "#shared";
|
|
6
6
|
import { guessContextWindow } from "./session";
|
|
7
7
|
import { loadConfig } from "../config";
|
|
8
8
|
import { getInstalledPluginCount, getPluginSkillRuleTokenEstimate } from "../handlers/plugins";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
2
|
import { basename } from "node:path";
|
|
3
3
|
import { loadConfig, saveConfig } from "../config";
|
|
4
|
-
import type { ProjectSummary } from "
|
|
4
|
+
import type { ProjectSummary } from "#shared";
|
|
5
5
|
|
|
6
6
|
export function listProjects(nodeId: string): ProjectSummary[] {
|
|
7
7
|
var config = loadConfig();
|
|
@@ -3,7 +3,7 @@ import { query } from "@anthropic-ai/claude-agent-sdk";
|
|
|
3
3
|
import type { SDKMessage, SDKPartialAssistantMessage, SDKResultMessage, SDKUserMessage } from "@anthropic-ai/claude-agent-sdk";
|
|
4
4
|
import type { CanUseTool, PermissionMode, PermissionResult, PermissionUpdate } from "@anthropic-ai/claude-agent-sdk";
|
|
5
5
|
type MessageParam = SDKUserMessage["message"];
|
|
6
|
-
import type { Attachment } from "
|
|
6
|
+
import type { Attachment } from "#shared";
|
|
7
7
|
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
8
8
|
import { join, resolve } from "node:path";
|
|
9
9
|
import { homedir } from "node:os";
|
|
@@ -777,7 +777,6 @@ export function startChatStream(options: ChatStreamOptions): void {
|
|
|
777
777
|
|
|
778
778
|
var mq = createMessageQueue();
|
|
779
779
|
var firstMsg = buildSDKUserMessage(prompt, attachments, sessionId);
|
|
780
|
-
mq.push(firstMsg);
|
|
781
780
|
|
|
782
781
|
var stream = query({ prompt: mq as any, options: queryOptions });
|
|
783
782
|
pendingStreams.delete(sessionId);
|
|
@@ -804,6 +803,13 @@ export function startChatStream(options: ChatStreamOptions): void {
|
|
|
804
803
|
broadcast({ type: "session:busy", sessionId, busy: true }, clientId);
|
|
805
804
|
|
|
806
805
|
void (async function () {
|
|
806
|
+
var retried = false;
|
|
807
|
+
try {
|
|
808
|
+
await stream.initializationResult();
|
|
809
|
+
} catch (initErr) {
|
|
810
|
+
log.chat("Session %s SDK initialization warning: %O", sessionId, initErr);
|
|
811
|
+
}
|
|
812
|
+
mq.push(firstMsg);
|
|
807
813
|
try {
|
|
808
814
|
for await (var msg of stream) {
|
|
809
815
|
processMessage(sessionStream, msg);
|
|
@@ -812,6 +818,26 @@ export function startChatStream(options: ChatStreamOptions): void {
|
|
|
812
818
|
var errMsg = err instanceof Error ? err.message : String(err);
|
|
813
819
|
if (errMsg.includes("aborted") || errMsg.includes("AbortError")) {
|
|
814
820
|
log.chat("Session %s stream aborted", sessionId);
|
|
821
|
+
} else if (errMsg.includes("Sent before connected") && !retried) {
|
|
822
|
+
retried = true;
|
|
823
|
+
log.chat("Session %s SDK WebSocket race condition, retrying after delay...", sessionId);
|
|
824
|
+
await new Promise(function (r) { setTimeout(r, 500); });
|
|
825
|
+
try {
|
|
826
|
+
var retryMq = createMessageQueue();
|
|
827
|
+
var retryStream = query({ prompt: retryMq as any, options: queryOptions });
|
|
828
|
+
retryMq.push(firstMsg);
|
|
829
|
+
sessionStream.queryInstance = retryStream;
|
|
830
|
+
sessionStream.messageQueue = retryMq;
|
|
831
|
+
for await (var retryMsg of retryStream) {
|
|
832
|
+
processMessage(sessionStream, retryMsg);
|
|
833
|
+
}
|
|
834
|
+
} catch (retryErr: unknown) {
|
|
835
|
+
var retryErrMsg = retryErr instanceof Error ? retryErr.message : String(retryErr);
|
|
836
|
+
if (!retryErrMsg.includes("aborted") && !retryErrMsg.includes("AbortError")) {
|
|
837
|
+
console.error("[lattice] SDK stream retry error: " + retryErrMsg);
|
|
838
|
+
sendTo(sessionStream.clientId, { type: "chat:error", message: retryErrMsg });
|
|
839
|
+
}
|
|
840
|
+
}
|
|
815
841
|
} else {
|
|
816
842
|
console.error("[lattice] SDK stream error: " + errMsg);
|
|
817
843
|
sendTo(sessionStream.clientId, { type: "chat:error", message: errMsg });
|
|
@@ -10,7 +10,7 @@ import * as fsPromises from "node:fs/promises";
|
|
|
10
10
|
import { join } from "node:path";
|
|
11
11
|
import { randomUUID } from "node:crypto";
|
|
12
12
|
import { homedir } from "node:os";
|
|
13
|
-
import type { HistoryMessage, SessionPreview, SessionSummary } from "
|
|
13
|
+
import type { HistoryMessage, SessionPreview, SessionSummary } from "#shared";
|
|
14
14
|
import { loadConfig } from "../config";
|
|
15
15
|
import { log } from "../logger";
|
|
16
16
|
|
|
@@ -629,7 +629,7 @@ export async function loadSessionHistory(projectSlug: string, sessionId: string)
|
|
|
629
629
|
}
|
|
630
630
|
}
|
|
631
631
|
|
|
632
|
-
export async function getSessionHistoryPage(sessionId: string, beforeIndex: number, limit: number, projectSlug?: string): Promise<{ messages: HistoryMessage[]; hasMore: boolean }> {
|
|
632
|
+
export async function getSessionHistoryPage(sessionId: string, beforeIndex: number, limit: number, projectSlug?: string): Promise<{ messages: HistoryMessage[]; hasMore: boolean; totalMessages: number }> {
|
|
633
633
|
var cached = historyCache.get(sessionId);
|
|
634
634
|
if (!cached && projectSlug) {
|
|
635
635
|
var projectPath = getProjectPath(projectSlug);
|
|
@@ -643,16 +643,17 @@ export async function getSessionHistoryPage(sessionId: string, beforeIndex: numb
|
|
|
643
643
|
cached = historyCache.get(sessionId)!;
|
|
644
644
|
log.session("getSessionHistoryPage: full load for %s, %d messages", sessionId.slice(0, 8), allMessages.length);
|
|
645
645
|
} catch {
|
|
646
|
-
return { messages: [], hasMore: false };
|
|
646
|
+
return { messages: [], hasMore: false, totalMessages: 0 };
|
|
647
647
|
}
|
|
648
648
|
}
|
|
649
|
-
if (!cached) return { messages: [], hasMore: false };
|
|
649
|
+
if (!cached) return { messages: [], hasMore: false, totalMessages: 0 };
|
|
650
650
|
|
|
651
|
-
var
|
|
651
|
+
var total = cached.messages.length;
|
|
652
|
+
var endIdx = Math.min(Math.max(0, beforeIndex), total);
|
|
652
653
|
var startIdx = Math.max(0, endIdx - limit);
|
|
653
654
|
var page = cached.messages.slice(startIdx, endIdx);
|
|
654
655
|
|
|
655
|
-
return { messages: page, hasMore: startIdx > 0 };
|
|
656
|
+
return { messages: page, hasMore: startIdx > 0, totalMessages: total };
|
|
656
657
|
}
|
|
657
658
|
|
|
658
659
|
export function createSession(projectSlug: string): SessionSummary {
|
package/src/server/tls.ts
CHANGED
|
@@ -16,12 +16,26 @@ export function getCertsDir(): string {
|
|
|
16
16
|
return certsDir;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
function isCertExpiringSoon(certPath: string): boolean {
|
|
20
|
+
try {
|
|
21
|
+
var result = spawnSync("openssl", ["x509", "-enddate", "-noout", "-in", certPath], { encoding: "utf-8" });
|
|
22
|
+
if (result.status !== 0) return true;
|
|
23
|
+
var match = result.stdout.match(/notAfter=(.+)/);
|
|
24
|
+
if (!match) return true;
|
|
25
|
+
var expiryDate = new Date(match[1]);
|
|
26
|
+
var daysLeft = (expiryDate.getTime() - Date.now()) / (1000 * 60 * 60 * 24);
|
|
27
|
+
return daysLeft < 30;
|
|
28
|
+
} catch {
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
19
33
|
export function ensureCerts(): CertPaths {
|
|
20
34
|
var certsDir = getCertsDir();
|
|
21
35
|
var certPath = join(certsDir, "cert.pem");
|
|
22
36
|
var keyPath = join(certsDir, "key.pem");
|
|
23
37
|
|
|
24
|
-
if (existsSync(certPath) && existsSync(keyPath)) {
|
|
38
|
+
if (existsSync(certPath) && existsSync(keyPath) && !isCertExpiringSoon(certPath)) {
|
|
25
39
|
return { cert: certPath, key: keyPath };
|
|
26
40
|
}
|
|
27
41
|
|
package/src/server/tui.ts
CHANGED
|
@@ -2,8 +2,8 @@ import * as p from "@clack/prompts";
|
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { getLatticeHome, loadConfig, saveConfig } from "./config";
|
|
5
|
-
import type { LatticeConfig } from "
|
|
6
|
-
import { DEFAULT_PORT } from "
|
|
5
|
+
import type { LatticeConfig } from "#shared";
|
|
6
|
+
import { DEFAULT_PORT } from "#shared";
|
|
7
7
|
|
|
8
8
|
var BANNER = `
|
|
9
9
|
\x1b[36m██╗\x1b[0m \x1b[36m█████╗\x1b[0m \x1b[36m████████╗████████╗██╗\x1b[0m \x1b[36m██████╗\x1b[0m \x1b[36m███████╗\x1b[0m
|