@cryptiklemur/lattice 5.4.2 → 5.5.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/README.md +114 -0
- package/dist/client/assets/{angular-html-SJYR00xk.js → angular-html-Bmjy4gNc.js} +1 -1
- package/dist/client/assets/{angular-ts-D-0qcYO-.js → angular-ts-10l13C4C.js} +1 -1
- package/dist/client/assets/{apl-C_yUf_Q8.js → apl--Bn7yH0T.js} +1 -1
- package/dist/client/assets/{astro-DWb1sYof.js → astro-C8P9TQkP.js} +1 -1
- package/dist/client/assets/{blade-gpPhvMw5.js → blade-DQiHYnIS.js} +1 -1
- package/dist/client/assets/{c-Bll-v5tl.js → c-BFny-WnE.js} +1 -1
- package/dist/client/assets/{cobol-BtwRKHKx.js → cobol-hGEexMYH.js} +1 -1
- package/dist/client/assets/{coffee-lhi7pwZU.js → coffee-j3W4ZALV.js} +1 -1
- package/dist/client/assets/{cpp-DhSfzDsk.js → cpp-DquWJNps.js} +1 -1
- package/dist/client/assets/{crystal-BDslEuCS.js → crystal-CWL31dIV.js} +1 -1
- package/dist/client/assets/{css-wZiH58D5.js → css-Di4GSq8V.js} +1 -1
- package/dist/client/assets/{dist-CSLVAWWj.js → dist-CaJdL3Va.js} +2 -2
- package/dist/client/assets/{edge-DYebWUkr.js → edge-rK4d050l.js} +1 -1
- package/dist/client/assets/{elixir-CdQhteX2.js → elixir-BMFKKu5z.js} +1 -1
- package/dist/client/assets/{elm-BHfFlGS-.js → elm-B0QVlW3-.js} +1 -1
- package/dist/client/assets/{erb-BUj390yA.js → erb-C9w9QbhL.js} +1 -1
- package/dist/client/assets/{git-rebase-D8IOT_TG.js → git-rebase-FaylS7Vl.js} +1 -1
- package/dist/client/assets/{glimmer-js-DQa2GaPP.js → glimmer-js-Bi2XnbHi.js} +1 -1
- package/dist/client/assets/{glimmer-ts-yWWiDGaM.js → glimmer-ts-DOdxK6E6.js} +1 -1
- package/dist/client/assets/{glsl-C_ZnI9md.js → glsl-BiGDIGbZ.js} +1 -1
- package/dist/client/assets/{graphql-BaUc-XOO.js → graphql-CZJB8KIP.js} +1 -1
- package/dist/client/assets/{hack-Chs6cNkF.js → hack-CNGYBFqH.js} +1 -1
- package/dist/client/assets/{haml-D538SVOD.js → haml-pf3Zh5MH.js} +1 -1
- package/dist/client/assets/{handlebars-B8nrl3PR.js → handlebars-BsQwsvPC.js} +1 -1
- package/dist/client/assets/{html-DsesQty8.js → html-Dj4Hvv69.js} +1 -1
- package/dist/client/assets/{html-derivative-Dznd2N7i.js → html-derivative-CE7dQ_mI.js} +1 -1
- package/dist/client/assets/{http-DdUXd6Cv.js → http-DjOuMI1u.js} +1 -1
- package/dist/client/assets/{hurl-BSNmPifU.js → hurl-BH_MQrQo.js} +1 -1
- package/dist/client/assets/{index-DQRuYWBh.js → index-DA8ZBSYW.js} +321 -88
- package/dist/client/assets/{index-2jfMHAda.css → index-DcwXjiH0.css} +1 -1
- package/dist/client/assets/{java-closdFmr.js → java-CnpykAva.js} +1 -1
- package/dist/client/assets/{javascript-C6pRyT7u.js → javascript-BbqQ1sQM.js} +1 -1
- package/dist/client/assets/{jinja-29z7zfl-.js → jinja-DddpvWwk.js} +1 -1
- package/dist/client/assets/{jison-BlzhS9df.js → jison-Bd3G2n4x.js} +1 -1
- package/dist/client/assets/{json-BVYyKt19.js → json-F0eTFQKP.js} +1 -1
- package/dist/client/assets/{jsx-78E4xoje.js → jsx-B-wB5nUs.js} +1 -1
- package/dist/client/assets/{julia-B6DwXmVv.js → julia-9Lfz4b5s.js} +1 -1
- package/dist/client/assets/{just-ht50WZ6C.js → just-BVE1sBJx.js} +1 -1
- package/dist/client/assets/{latex-CjZuet49.js → latex-SF3xMSWG.js} +1 -1
- package/dist/client/assets/{liquid-Cjfh-yZc.js → liquid-CLkbZ0ZV.js} +1 -1
- package/dist/client/assets/{lua-CVSB6AEI.js → lua-DNph6TL8.js} +1 -1
- package/dist/client/assets/{marko-BFrF6uWg.js → marko-CGqdEtbF.js} +1 -1
- package/dist/client/assets/{mdc-qvNjCqiX.js → mdc-BLpzcq82.js} +1 -1
- package/dist/client/assets/{nginx-MsabrNG_.js → nginx-s7ciyZD1.js} +1 -1
- package/dist/client/assets/{nim-Cc2JeGZC.js → nim-C4FeZI3R.js} +1 -1
- package/dist/client/assets/{perl-Bvo-EvFm.js → perl-GDfD5AIi.js} +1 -1
- package/dist/client/assets/{php-C7efK-fE.js → php-CusAuy6y.js} +1 -1
- package/dist/client/assets/{pug-BHu66rzG.js → pug-DCKuXO7x.js} +1 -1
- package/dist/client/assets/{qml-BLhrl-5q.js → qml-rp1ZHoeo.js} +1 -1
- package/dist/client/assets/{r-B2ehj4h6.js → r-CwNbYaVb.js} +1 -1
- package/dist/client/assets/{razor-D6r43dAd.js → razor-CinY5yf4.js} +1 -1
- package/dist/client/assets/{regexp-hbR6TLtq.js → regexp-CxVI4rKV.js} +1 -1
- package/dist/client/assets/{rst-BolhcSc3.js → rst-BrBmBgUr.js} +1 -1
- package/dist/client/assets/{ruby-CBN1zxC_.js → ruby-BzNCpRio.js} +1 -1
- package/dist/client/assets/{sas-JEvub8hp.js → sas-B4IAap7m.js} +1 -1
- package/dist/client/assets/{scss-D4arWi-Q.js → scss-eNAsUEA1.js} +1 -1
- package/dist/client/assets/{shellscript-v9q5xlF5.js → shellscript-BwH0aChW.js} +1 -1
- package/dist/client/assets/{shellsession-DT_8eUZ3.js → shellsession-B5ibJBbh.js} +1 -1
- package/dist/client/assets/{soy-CitjdPtE.js → soy-BrqReQP3.js} +1 -1
- package/dist/client/assets/{sql-YlhezUxw.js → sql-KIDgTieS.js} +1 -1
- package/dist/client/assets/{stata-50KEEAuW.js → stata-D6yim7Rr.js} +1 -1
- package/dist/client/assets/{surrealql-CHxisHFK.js → surrealql-C51iMPEA.js} +1 -1
- package/dist/client/assets/{svelte-D9-Nhiy4.js → svelte-DYs5QSVt.js} +1 -1
- package/dist/client/assets/{templ-CD-Nb-TG.js → templ-CLDdaEXl.js} +1 -1
- package/dist/client/assets/{tex-BJjdCsnl.js → tex-D16HBCoj.js} +1 -1
- package/dist/client/assets/{ts-tags-Cij8ie91.js → ts-tags-DTcB2bBd.js} +1 -1
- package/dist/client/assets/{tsx-DEOZxt7J.js → tsx-BxGfVt8a.js} +1 -1
- package/dist/client/assets/{twig-B_IYmySH.js → twig-BUC08jwe.js} +1 -1
- package/dist/client/assets/{typescript-CdNmBQel.js → typescript-CuPGT2MR.js} +1 -1
- package/dist/client/assets/{vue-DmoveTFa.js → vue-_ip8-SIk.js} +1 -1
- package/dist/client/assets/{vue-html-CYcJvbOP.js → vue-html-D-I9-U-x.js} +1 -1
- package/dist/client/assets/{vue-vine-SDsNLzWn.js → vue-vine-7AONB1tt.js} +1 -1
- package/dist/client/assets/{xml-BmY74qrp.js → xml-D2ZUDsPU.js} +1 -1
- package/dist/client/assets/{xsl-10UVJPoU.js → xsl-GlFKKlLy.js} +1 -1
- package/dist/client/assets/{yaml-DrtC5l50.js → yaml-BnuTxWck.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/client/sw.js +1 -1
- package/dist/server/daemon.js +30 -20
- package/dist/server/features/brainstorm.js +267 -0
- package/dist/server/handlers/brainstorm.js +33 -0
- package/dist/server/handlers/fs.js +3 -0
- package/dist/server/handlers/session.js +13 -5
- package/dist/server/project/sdk-bridge.js +2 -22
- package/dist/server/project/session.js +92 -11
- package/package.json +1 -1
|
@@ -13,6 +13,9 @@ export function setActiveProject(clientId, projectSlug) {
|
|
|
13
13
|
export function clearActiveProject(clientId) {
|
|
14
14
|
activeProjectByClient.delete(clientId);
|
|
15
15
|
}
|
|
16
|
+
export function getActiveProjectForClient(clientId) {
|
|
17
|
+
return activeProjectByClient.get(clientId);
|
|
18
|
+
}
|
|
16
19
|
registerHandler("fs", function (clientId, message) {
|
|
17
20
|
if (message.type === "fs:list") {
|
|
18
21
|
var listMsg = message;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { registerHandler } from "../ws/router.js";
|
|
2
|
-
import { sendTo } from "../ws/broadcast.js";
|
|
2
|
+
import { sendTo, broadcast } from "../ws/broadcast.js";
|
|
3
3
|
import { loadConfig } from "../config.js";
|
|
4
|
-
import { createSession, deleteSession, findProjectSlugForSession, getSessionPreview, getSessionTitle, getSessionUsage, listSessions, invalidateSessionCache, invalidateHistoryCache, getSessionHistoryPage, loadSessionHistory, renameSession, getSessionFileSizeBytes, } from "../project/session.js";
|
|
4
|
+
import { createSession, deleteSession, findProjectSlugForSession, getSessionPreview, getSessionTitle, getSessionUsage, listSessions, invalidateSessionCache, invalidateHistoryCache, getSessionHistoryPage, loadSessionHistory, renameSession, getSessionFileSizeBytes, updateSessionInIndex, removeSessionFromIndex, } from "../project/session.js";
|
|
5
5
|
import { getContextBreakdown } from "../project/context-breakdown.js";
|
|
6
6
|
import { setActiveSession, getActiveSession } from "./chat.js";
|
|
7
7
|
import { setActiveProject } from "./fs.js";
|
|
@@ -71,7 +71,15 @@ registerHandler("session", function (clientId, message) {
|
|
|
71
71
|
if (message.type === "session:create") {
|
|
72
72
|
var createMsg = message;
|
|
73
73
|
var session = createSession(createMsg.projectSlug);
|
|
74
|
+
updateSessionInIndex(createMsg.projectSlug, session);
|
|
74
75
|
sendTo(clientId, { type: "session:created", session });
|
|
76
|
+
broadcast({
|
|
77
|
+
type: "session:list",
|
|
78
|
+
projectSlug: createMsg.projectSlug,
|
|
79
|
+
sessions: [session],
|
|
80
|
+
totalCount: undefined,
|
|
81
|
+
offset: 0,
|
|
82
|
+
});
|
|
75
83
|
return;
|
|
76
84
|
}
|
|
77
85
|
if (message.type === "session:activate") {
|
|
@@ -160,7 +168,7 @@ registerHandler("session", function (clientId, message) {
|
|
|
160
168
|
void renameSession(projectSlug, renameMsg.sessionId, renameMsg.title).then(function () {
|
|
161
169
|
invalidateSessionCache(projectSlug);
|
|
162
170
|
void listSessions(projectSlug, { limit: 40 }).then(function (result) {
|
|
163
|
-
|
|
171
|
+
broadcast({
|
|
164
172
|
type: "session:list",
|
|
165
173
|
projectSlug,
|
|
166
174
|
sessions: result.sessions,
|
|
@@ -179,9 +187,9 @@ registerHandler("session", function (clientId, message) {
|
|
|
179
187
|
return;
|
|
180
188
|
}
|
|
181
189
|
void deleteSession(deleteProjectSlug, deleteMsg.sessionId).then(function () {
|
|
182
|
-
|
|
190
|
+
removeSessionFromIndex(deleteProjectSlug, deleteMsg.sessionId);
|
|
183
191
|
void listSessions(deleteProjectSlug, { limit: 40 }).then(function (result) {
|
|
184
|
-
|
|
192
|
+
broadcast({
|
|
185
193
|
type: "session:list",
|
|
186
194
|
projectSlug: deleteProjectSlug,
|
|
187
195
|
sessions: result.sessions,
|
|
@@ -671,7 +671,6 @@ export function startChatStream(options) {
|
|
|
671
671
|
persistStreamState();
|
|
672
672
|
broadcast({ type: "session:busy", sessionId, busy: true }, clientId);
|
|
673
673
|
void (async function () {
|
|
674
|
-
var retried = false;
|
|
675
674
|
try {
|
|
676
675
|
await stream.initializationResult();
|
|
677
676
|
}
|
|
@@ -689,27 +688,8 @@ export function startChatStream(options) {
|
|
|
689
688
|
if (errMsg.includes("aborted") || errMsg.includes("AbortError")) {
|
|
690
689
|
log.chat("Session %s stream aborted", sessionId);
|
|
691
690
|
}
|
|
692
|
-
else if (errMsg.includes("Sent before connected")
|
|
693
|
-
|
|
694
|
-
log.chat("Session %s SDK WebSocket race condition, retrying after delay...", sessionId);
|
|
695
|
-
await new Promise(function (r) { setTimeout(r, 500); });
|
|
696
|
-
try {
|
|
697
|
-
var retryMq = createMessageQueue();
|
|
698
|
-
var retryStream = query({ prompt: retryMq, options: queryOptions });
|
|
699
|
-
retryMq.push(firstMsg);
|
|
700
|
-
sessionStream.queryInstance = retryStream;
|
|
701
|
-
sessionStream.messageQueue = retryMq;
|
|
702
|
-
for await (var retryMsg of retryStream) {
|
|
703
|
-
processMessage(sessionStream, retryMsg);
|
|
704
|
-
}
|
|
705
|
-
}
|
|
706
|
-
catch (retryErr) {
|
|
707
|
-
var retryErrMsg = retryErr instanceof Error ? retryErr.message : String(retryErr);
|
|
708
|
-
if (!retryErrMsg.includes("aborted") && !retryErrMsg.includes("AbortError")) {
|
|
709
|
-
console.error("[lattice] SDK stream retry error: " + retryErrMsg);
|
|
710
|
-
sendTo(sessionStream.clientId, { type: "chat:error", message: retryErrMsg });
|
|
711
|
-
}
|
|
712
|
-
}
|
|
691
|
+
else if (errMsg.includes("Sent before connected")) {
|
|
692
|
+
log.chat("Session %s SDK WebSocket race condition: %s", sessionId, errMsg);
|
|
713
693
|
}
|
|
714
694
|
else {
|
|
715
695
|
console.error("[lattice] SDK stream error: " + errMsg);
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { listSessions as sdkListSessions, getSessionInfo, getSessionMessages, renameSession as sdkRenameSession, } from "@anthropic-ai/claude-agent-sdk";
|
|
2
|
-
import { existsSync, unlinkSync, readFileSync, statSync } from "node:fs";
|
|
2
|
+
import { existsSync, unlinkSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
3
3
|
import * as fsPromises from "node:fs/promises";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { randomUUID } from "node:crypto";
|
|
6
6
|
import { homedir } from "node:os";
|
|
7
|
-
import { loadConfig } from "../config.js";
|
|
7
|
+
import { loadConfig, getLatticeHome } from "../config.js";
|
|
8
8
|
import { log } from "../logger.js";
|
|
9
9
|
function getProjectPath(projectSlug) {
|
|
10
10
|
var config = loadConfig();
|
|
@@ -428,7 +428,81 @@ export async function getSessionPreview(projectSlug, sessionId) {
|
|
|
428
428
|
}
|
|
429
429
|
}
|
|
430
430
|
var sessionListCache = new Map();
|
|
431
|
-
var SESSION_CACHE_TTL =
|
|
431
|
+
var SESSION_CACHE_TTL = 60000;
|
|
432
|
+
var RECONCILE_INTERVAL = 5 * 60 * 1000;
|
|
433
|
+
var lastReconcile = new Map();
|
|
434
|
+
function getIndexPath() {
|
|
435
|
+
return join(getLatticeHome(), "session-index.json");
|
|
436
|
+
}
|
|
437
|
+
function loadSessionIndex() {
|
|
438
|
+
var indexPath = getIndexPath();
|
|
439
|
+
if (!existsSync(indexPath))
|
|
440
|
+
return {};
|
|
441
|
+
try {
|
|
442
|
+
return JSON.parse(readFileSync(indexPath, "utf-8"));
|
|
443
|
+
}
|
|
444
|
+
catch {
|
|
445
|
+
return {};
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
function saveSessionIndex(index) {
|
|
449
|
+
try {
|
|
450
|
+
writeFileSync(getIndexPath(), JSON.stringify(index), "utf-8");
|
|
451
|
+
}
|
|
452
|
+
catch (err) {
|
|
453
|
+
log.session("Failed to save session index: %O", err);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
export function updateSessionInIndex(projectSlug, session) {
|
|
457
|
+
var index = loadSessionIndex();
|
|
458
|
+
var sessions = index[projectSlug] || [];
|
|
459
|
+
var existing = -1;
|
|
460
|
+
for (var i = 0; i < sessions.length; i++) {
|
|
461
|
+
if (sessions[i].id === session.id) {
|
|
462
|
+
existing = i;
|
|
463
|
+
break;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
if (existing >= 0) {
|
|
467
|
+
sessions[existing] = session;
|
|
468
|
+
}
|
|
469
|
+
else {
|
|
470
|
+
sessions.push(session);
|
|
471
|
+
}
|
|
472
|
+
sessions.sort(function (a, b) { return b.updatedAt - a.updatedAt; });
|
|
473
|
+
index[projectSlug] = sessions;
|
|
474
|
+
saveSessionIndex(index);
|
|
475
|
+
sessionListCache.set(projectSlug, { sessions, time: Date.now() });
|
|
476
|
+
}
|
|
477
|
+
export function removeSessionFromIndex(projectSlug, sessionId) {
|
|
478
|
+
var index = loadSessionIndex();
|
|
479
|
+
var sessions = index[projectSlug] || [];
|
|
480
|
+
index[projectSlug] = sessions.filter(function (s) { return s.id !== sessionId; });
|
|
481
|
+
saveSessionIndex(index);
|
|
482
|
+
sessionListCache.set(projectSlug, { sessions: index[projectSlug], time: Date.now() });
|
|
483
|
+
}
|
|
484
|
+
async function reconcileWithSDK(projectSlug) {
|
|
485
|
+
var projectPath = getProjectPath(projectSlug);
|
|
486
|
+
if (!projectPath)
|
|
487
|
+
return [];
|
|
488
|
+
var sdkT0 = Date.now();
|
|
489
|
+
var sdkSessions = await sdkListSessions({ dir: projectPath });
|
|
490
|
+
log.session("sdkListSessions for %s: %dms (%d sessions)", projectSlug, Date.now() - sdkT0, sdkSessions.length);
|
|
491
|
+
var summaries = sdkSessions.map(function (s) { return mapSDKSession(s, projectSlug); });
|
|
492
|
+
summaries.sort(function (a, b) { return b.updatedAt - a.updatedAt; });
|
|
493
|
+
var index = loadSessionIndex();
|
|
494
|
+
index[projectSlug] = summaries;
|
|
495
|
+
saveSessionIndex(index);
|
|
496
|
+
sessionListCache.set(projectSlug, { sessions: summaries, time: Date.now() });
|
|
497
|
+
lastReconcile.set(projectSlug, Date.now());
|
|
498
|
+
return summaries;
|
|
499
|
+
}
|
|
500
|
+
function needsReconcile(projectSlug) {
|
|
501
|
+
var last = lastReconcile.get(projectSlug);
|
|
502
|
+
if (!last)
|
|
503
|
+
return true;
|
|
504
|
+
return Date.now() - last > RECONCILE_INTERVAL;
|
|
505
|
+
}
|
|
432
506
|
export async function listSessions(projectSlug, options) {
|
|
433
507
|
var projectPath = getProjectPath(projectSlug);
|
|
434
508
|
if (!projectPath) {
|
|
@@ -441,15 +515,22 @@ export async function listSessions(projectSlug, options) {
|
|
|
441
515
|
var sliced = limit > 0 ? cached.sessions.slice(offset, offset + limit) : cached.sessions;
|
|
442
516
|
return { sessions: sliced, totalCount: cached.sessions.length };
|
|
443
517
|
}
|
|
518
|
+
var index = loadSessionIndex();
|
|
519
|
+
var indexed = index[projectSlug];
|
|
520
|
+
if (indexed && indexed.length > 0) {
|
|
521
|
+
sessionListCache.set(projectSlug, { sessions: indexed, time: Date.now() });
|
|
522
|
+
if (needsReconcile(projectSlug)) {
|
|
523
|
+
reconcileWithSDK(projectSlug).catch(function (err) {
|
|
524
|
+
log.session("Background reconcile failed: %O", err);
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
var offset3 = options?.offset ?? 0;
|
|
528
|
+
var limit3 = options?.limit ?? 0;
|
|
529
|
+
var sliced3 = limit3 > 0 ? indexed.slice(offset3, offset3 + limit3) : indexed;
|
|
530
|
+
return { sessions: sliced3, totalCount: indexed.length };
|
|
531
|
+
}
|
|
444
532
|
try {
|
|
445
|
-
var
|
|
446
|
-
var sdkSessions = await sdkListSessions({ dir: projectPath });
|
|
447
|
-
log.session("sdkListSessions for %s: %dms (%d sessions)", projectSlug, Date.now() - sdkT0, sdkSessions.length);
|
|
448
|
-
var summaries = sdkSessions.map(function (s) {
|
|
449
|
-
return mapSDKSession(s, projectSlug);
|
|
450
|
-
});
|
|
451
|
-
summaries.sort(function (a, b) { return b.updatedAt - a.updatedAt; });
|
|
452
|
-
sessionListCache.set(projectSlug, { sessions: summaries, time: Date.now() });
|
|
533
|
+
var summaries = await reconcileWithSDK(projectSlug);
|
|
453
534
|
var offset2 = options?.offset ?? 0;
|
|
454
535
|
var limit2 = options?.limit ?? 0;
|
|
455
536
|
var sliced2 = limit2 > 0 ? summaries.slice(offset2, offset2 + limit2) : summaries;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cryptiklemur/lattice",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.5.0",
|
|
4
4
|
"description": "Multi-machine agentic dashboard for Claude Code. Monitor sessions, manage MCP servers and skills, orchestrate across mesh-networked nodes.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Aaron Scherer <me@aaronscherer.me>",
|