@andespindola/brainlink 0.1.0-beta.147 → 0.1.0-beta.149
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.
|
@@ -258,12 +258,12 @@ li small {
|
|
|
258
258
|
|
|
259
259
|
.content-dialog {
|
|
260
260
|
position: fixed;
|
|
261
|
-
top:
|
|
262
|
-
right:
|
|
261
|
+
top: 74px;
|
|
262
|
+
right: 16px;
|
|
263
263
|
margin: 0;
|
|
264
|
-
width: min(
|
|
265
|
-
height: min(calc(100svh -
|
|
266
|
-
max-height: calc(100svh -
|
|
264
|
+
width: min(760px, calc(100vw - 32px));
|
|
265
|
+
height: min(calc(100svh - 96px), 920px);
|
|
266
|
+
max-height: calc(100svh - 96px);
|
|
267
267
|
padding: 0;
|
|
268
268
|
border: 1px solid var(--line);
|
|
269
269
|
border-radius: 8px;
|
|
@@ -331,7 +331,7 @@ li small {
|
|
|
331
331
|
|
|
332
332
|
.content-meta {
|
|
333
333
|
display: grid;
|
|
334
|
-
grid-template-columns: repeat(
|
|
334
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
335
335
|
gap: 10px;
|
|
336
336
|
padding: 14px 22px;
|
|
337
337
|
border-bottom: 1px solid var(--line);
|
|
@@ -358,12 +358,16 @@ li small {
|
|
|
358
358
|
|
|
359
359
|
.content-meta-section ul,
|
|
360
360
|
.content-meta-section .tags {
|
|
361
|
-
max-height:
|
|
361
|
+
max-height: 280px;
|
|
362
362
|
overflow: auto;
|
|
363
363
|
align-content: flex-start;
|
|
364
364
|
padding-right: 4px;
|
|
365
365
|
}
|
|
366
366
|
|
|
367
|
+
.content-meta-section:last-child {
|
|
368
|
+
grid-column: span 2;
|
|
369
|
+
}
|
|
370
|
+
|
|
367
371
|
.content-dialog .note-content {
|
|
368
372
|
max-height: none;
|
|
369
373
|
min-height: 0;
|
|
@@ -421,10 +425,10 @@ li small {
|
|
|
421
425
|
top: auto;
|
|
422
426
|
right: 12px;
|
|
423
427
|
left: 12px;
|
|
424
|
-
bottom:
|
|
428
|
+
bottom: 28px;
|
|
425
429
|
width: auto;
|
|
426
|
-
height: min(calc(100svh -
|
|
427
|
-
max-height: calc(100svh -
|
|
430
|
+
height: min(calc(100svh - 150px), 760px);
|
|
431
|
+
max-height: calc(100svh - 150px);
|
|
428
432
|
}
|
|
429
433
|
|
|
430
434
|
.metric-chip {
|
|
@@ -59,8 +59,10 @@ const state = {
|
|
|
59
59
|
searchToken: 0,
|
|
60
60
|
fetchToken: 0,
|
|
61
61
|
fetchTimer: null,
|
|
62
|
+
fetchAbortController: null,
|
|
62
63
|
cameraSyncScheduled: false,
|
|
63
64
|
lastDragFetchAt: 0,
|
|
65
|
+
lastWheelAt: 0,
|
|
64
66
|
lastVisibleNodes: 0,
|
|
65
67
|
lastVisibleEdges: 0,
|
|
66
68
|
totals: {
|
|
@@ -303,7 +305,7 @@ const extractContextLinks = (content) => {
|
|
|
303
305
|
const lines = content.split(/\\r?\\n/)
|
|
304
306
|
let start = -1
|
|
305
307
|
for (let index = 0; index < lines.length; index += 1) {
|
|
306
|
-
if (
|
|
308
|
+
if (/^#{1,6}\\s+(?:context\\s+links?|links?\\s+de\\s+contexto)\\b/i.test(lines[index].trim())) {
|
|
307
309
|
start = index + 1
|
|
308
310
|
break
|
|
309
311
|
}
|
|
@@ -313,6 +315,7 @@ const extractContextLinks = (content) => {
|
|
|
313
315
|
}
|
|
314
316
|
|
|
315
317
|
const links = []
|
|
318
|
+
const seenTitles = new Set()
|
|
316
319
|
for (let index = start; index < lines.length; index += 1) {
|
|
317
320
|
const line = lines[index].trim()
|
|
318
321
|
if (!line) {
|
|
@@ -321,17 +324,21 @@ const extractContextLinks = (content) => {
|
|
|
321
324
|
if (/^#{1,6}\\s+/.test(line)) {
|
|
322
325
|
break
|
|
323
326
|
}
|
|
324
|
-
const
|
|
325
|
-
if (
|
|
326
|
-
continue
|
|
327
|
-
}
|
|
328
|
-
const title = match[1].trim()
|
|
329
|
-
if (!title) {
|
|
327
|
+
const matches = Array.from(line.matchAll(/\\[\\[([^\\]]+)\\]\\]/g))
|
|
328
|
+
if (matches.length === 0) {
|
|
330
329
|
continue
|
|
331
330
|
}
|
|
332
331
|
const priorityMatch = line.match(/#(critical|important)\\b|priority:\\s*(high|critical)/i)
|
|
333
332
|
const priority = priorityMatch ? String(priorityMatch[1] || priorityMatch[2] || 'normal').toLowerCase() : 'normal'
|
|
334
|
-
|
|
333
|
+
|
|
334
|
+
for (let matchIndex = 0; matchIndex < matches.length; matchIndex += 1) {
|
|
335
|
+
const title = String(matches[matchIndex][1] || '').trim()
|
|
336
|
+
if (!title || seenTitles.has(title.toLowerCase())) {
|
|
337
|
+
continue
|
|
338
|
+
}
|
|
339
|
+
seenTitles.add(title.toLowerCase())
|
|
340
|
+
links.push({ title, priority })
|
|
341
|
+
}
|
|
335
342
|
}
|
|
336
343
|
return links
|
|
337
344
|
}
|
|
@@ -477,6 +484,11 @@ const fitFromChunk = () => {
|
|
|
477
484
|
|
|
478
485
|
const fetchChunk = async ({ fit } = { fit: false }) => {
|
|
479
486
|
const token = ++state.fetchToken
|
|
487
|
+
if (state.fetchAbortController) {
|
|
488
|
+
state.fetchAbortController.abort()
|
|
489
|
+
}
|
|
490
|
+
const controller = new AbortController()
|
|
491
|
+
state.fetchAbortController = controller
|
|
480
492
|
const worldTopLeft = screenToWorld(0, 0)
|
|
481
493
|
const worldBottomRight = screenToWorld(state.viewport.width, state.viewport.height)
|
|
482
494
|
const x = Math.min(worldTopLeft.x, worldBottomRight.x)
|
|
@@ -498,12 +510,15 @@ const fetchChunk = async ({ fit } = { fit: false }) => {
|
|
|
498
510
|
params.set('agent', state.agentId)
|
|
499
511
|
}
|
|
500
512
|
|
|
501
|
-
const response = await fetch('/api/graph-stream?' + params.toString())
|
|
513
|
+
const response = await fetch('/api/graph-stream?' + params.toString(), { signal: controller.signal })
|
|
502
514
|
if (!response.ok) {
|
|
503
515
|
throw new Error('Failed to fetch graph stream chunk')
|
|
504
516
|
}
|
|
505
517
|
|
|
506
518
|
const chunk = await response.json()
|
|
519
|
+
if (controller.signal.aborted) {
|
|
520
|
+
return
|
|
521
|
+
}
|
|
507
522
|
if (token !== state.fetchToken) {
|
|
508
523
|
return
|
|
509
524
|
}
|
|
@@ -539,10 +554,15 @@ const scheduleChunkFetch = ({ fit } = { fit: false }) => {
|
|
|
539
554
|
clearTimeout(state.fetchTimer)
|
|
540
555
|
}
|
|
541
556
|
|
|
542
|
-
const
|
|
557
|
+
const now = performance.now()
|
|
558
|
+
const recentlyWheeling = now - state.lastWheelAt < 180
|
|
559
|
+
const delay = fit ? 0 : (state.pointer.down ? 120 : (recentlyWheeling ? 140 : 48))
|
|
543
560
|
state.fetchTimer = setTimeout(() => {
|
|
544
561
|
state.fetchTimer = null
|
|
545
562
|
fetchChunk({ fit }).catch((error) => {
|
|
563
|
+
if (error && error.name === 'AbortError') {
|
|
564
|
+
return
|
|
565
|
+
}
|
|
546
566
|
console.error(error)
|
|
547
567
|
})
|
|
548
568
|
}, delay)
|
|
@@ -630,6 +650,7 @@ const setupInput = () => {
|
|
|
630
650
|
|
|
631
651
|
canvas.addEventListener('wheel', (event) => {
|
|
632
652
|
event.preventDefault()
|
|
653
|
+
state.lastWheelAt = performance.now()
|
|
633
654
|
const pointer = resolvePointer(event)
|
|
634
655
|
const exponent = Math.max(-0.05, Math.min(0.05, -event.deltaY * 0.001))
|
|
635
656
|
zoomAtPoint(pointer.x, pointer.y, Math.exp(exponent))
|
|
@@ -680,13 +701,6 @@ const setupInput = () => {
|
|
|
680
701
|
return
|
|
681
702
|
}
|
|
682
703
|
|
|
683
|
-
if (state.renderWorker && state.workerReady) {
|
|
684
|
-
state.renderWorker.postMessage({
|
|
685
|
-
type: 'pointer',
|
|
686
|
-
x: pointer.x,
|
|
687
|
-
y: pointer.y
|
|
688
|
-
})
|
|
689
|
-
}
|
|
690
704
|
})
|
|
691
705
|
|
|
692
706
|
canvas.addEventListener('pointerup', (event) => {
|
|
@@ -55,6 +55,7 @@ const createLayoutCache = (signature, nodes, edges, groups) => {
|
|
|
55
55
|
const groupById = new Map(groups.map((group) => [group.id, group]));
|
|
56
56
|
const degrees = new Map();
|
|
57
57
|
const adjacencyByNodeId = new Map();
|
|
58
|
+
const rankedAdjacencyByNodeId = new Map();
|
|
58
59
|
for (let index = 0; index < edges.length; index += 1) {
|
|
59
60
|
const edge = edges[index];
|
|
60
61
|
degrees.set(edge.source, (degrees.get(edge.source) ?? 0) + edge.weight);
|
|
@@ -69,12 +70,16 @@ const createLayoutCache = (signature, nodes, edges, groups) => {
|
|
|
69
70
|
targetAdjacency.push(index);
|
|
70
71
|
adjacencyByNodeId.set(edge.target, targetAdjacency);
|
|
71
72
|
}
|
|
73
|
+
for (const [nodeId, adjacency] of adjacencyByNodeId.entries()) {
|
|
74
|
+
rankedAdjacencyByNodeId.set(nodeId, [...adjacency].sort((leftIndex, rightIndex) => edgeRank(edges[rightIndex]) - edgeRank(edges[leftIndex])));
|
|
75
|
+
}
|
|
72
76
|
return {
|
|
73
77
|
signature,
|
|
74
78
|
degrees,
|
|
75
79
|
nodeById,
|
|
76
80
|
groupById,
|
|
77
|
-
adjacencyByNodeId
|
|
81
|
+
adjacencyByNodeId,
|
|
82
|
+
rankedAdjacencyByNodeId
|
|
78
83
|
};
|
|
79
84
|
};
|
|
80
85
|
const getOrCreateLayoutCache = (signature, nodes, edges, groups) => {
|
|
@@ -198,17 +203,16 @@ const collectEdgesForNodes = (allEdges, cache, nodeRows, edgeBudget, maxEdgesPer
|
|
|
198
203
|
const nodeIds = new Set(nodeRows.map((row) => row[0]));
|
|
199
204
|
const collected = new Map();
|
|
200
205
|
for (const nodeId of nodeIds) {
|
|
201
|
-
const adjacency = cache.
|
|
206
|
+
const adjacency = cache.rankedAdjacencyByNodeId.get(nodeId);
|
|
202
207
|
if (!adjacency || adjacency.length === 0) {
|
|
203
208
|
continue;
|
|
204
209
|
}
|
|
205
210
|
let perNodeCount = 0;
|
|
206
|
-
|
|
207
|
-
for (let index = 0; index < rankedAdjacency.length; index += 1) {
|
|
211
|
+
for (let index = 0; index < adjacency.length; index += 1) {
|
|
208
212
|
if (perNodeCount >= maxEdgesPerNode) {
|
|
209
213
|
break;
|
|
210
214
|
}
|
|
211
|
-
const edge = allEdges[
|
|
215
|
+
const edge = allEdges[adjacency[index]];
|
|
212
216
|
if (!edge.target || !nodeIds.has(edge.source) || !nodeIds.has(edge.target)) {
|
|
213
217
|
continue;
|
|
214
218
|
}
|
package/package.json
CHANGED