@andespindola/brainlink 0.1.0-beta.1 → 0.1.0-beta.100

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 (64) hide show
  1. package/AGENTS.md +8 -5
  2. package/CHANGELOG.md +72 -2
  3. package/CONTRIBUTING.md +2 -2
  4. package/COPYRIGHT.md +5 -0
  5. package/README.md +374 -24
  6. package/SECURITY.md +1 -1
  7. package/dist/application/add-note.js +62 -13
  8. package/dist/application/analyze-vault.js +95 -8
  9. package/dist/application/build-context.js +56 -1
  10. package/dist/application/dedupe-notes.js +226 -0
  11. package/dist/application/frontend/client-css.js +230 -99
  12. package/dist/application/frontend/client-html.js +62 -44
  13. package/dist/application/frontend/client-js.js +3331 -163
  14. package/dist/application/frontend/client-worker-js.js +66 -0
  15. package/dist/application/get-graph-layout.js +22 -7
  16. package/dist/application/get-graph-node.js +12 -0
  17. package/dist/application/get-graph-summary.js +12 -0
  18. package/dist/application/get-graph.js +3 -3
  19. package/dist/application/import-legacy-sqlite.js +296 -0
  20. package/dist/application/index-vault.js +252 -19
  21. package/dist/application/list-agents.js +3 -3
  22. package/dist/application/list-links.js +5 -5
  23. package/dist/application/migrate-vault.js +91 -0
  24. package/dist/application/offline-pack-backup.js +44 -0
  25. package/dist/application/search-graph-node-ids.js +12 -0
  26. package/dist/application/search-knowledge.js +75 -5
  27. package/dist/application/server/routes.js +102 -1
  28. package/dist/application/start-server.js +75 -4
  29. package/dist/application/watch-vault.js +23 -2
  30. package/dist/benchmarks/large-vault.js +1 -1
  31. package/dist/cli/commands/agent-commands.js +419 -0
  32. package/dist/cli/commands/config-commands.js +167 -0
  33. package/dist/cli/commands/read-commands.js +25 -8
  34. package/dist/cli/commands/write-commands.js +989 -10
  35. package/dist/cli/main.js +4 -0
  36. package/dist/cli/runtime.js +5 -2
  37. package/dist/domain/context.js +53 -11
  38. package/dist/domain/embeddings.js +2 -1
  39. package/dist/domain/graph-layout.js +67 -16
  40. package/dist/domain/markdown.js +36 -4
  41. package/dist/domain/middle-out.js +18 -0
  42. package/dist/infrastructure/config.js +132 -8
  43. package/dist/infrastructure/file-index.js +358 -0
  44. package/dist/infrastructure/file-system-vault.js +30 -0
  45. package/dist/infrastructure/index-state.js +56 -0
  46. package/dist/infrastructure/paths.js +9 -1
  47. package/dist/infrastructure/private-pack-codec.js +134 -0
  48. package/dist/infrastructure/search-packs.js +452 -0
  49. package/dist/infrastructure/session-state.js +172 -0
  50. package/dist/mcp/main.js +11 -3
  51. package/dist/mcp/server.js +27 -2
  52. package/dist/mcp/startup.js +35 -0
  53. package/dist/mcp/tools.js +633 -19
  54. package/docs/AGENT_USAGE.md +180 -16
  55. package/docs/ARCHITECTURE.md +37 -26
  56. package/docs/QUICKSTART.md +111 -0
  57. package/docs/RELEASE.md +3 -3
  58. package/package.json +6 -4
  59. package/dist/infrastructure/sqlite/document-writer.js +0 -51
  60. package/dist/infrastructure/sqlite/graph-reader.js +0 -120
  61. package/dist/infrastructure/sqlite/schema.js +0 -111
  62. package/dist/infrastructure/sqlite/search-reader.js +0 -156
  63. package/dist/infrastructure/sqlite/types.js +0 -1
  64. package/dist/infrastructure/sqlite-index.js +0 -25
@@ -25,6 +25,13 @@ body {
25
25
  font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
26
26
  }
27
27
 
28
+ body {
29
+ display: flex;
30
+ flex-direction: column;
31
+ min-height: 100vh;
32
+ min-height: 100dvh;
33
+ }
34
+
28
35
  button,
29
36
  input,
30
37
  select {
@@ -32,70 +39,94 @@ select {
32
39
  }
33
40
 
34
41
  .shell {
35
- display: grid;
36
- grid-template-columns: minmax(0, 1fr) 360px;
42
+ flex: 1 1 auto;
37
43
  width: 100%;
38
- height: 100svh;
44
+ min-height: 0;
39
45
  overflow: hidden;
40
46
  }
41
47
 
42
48
  .workspace {
49
+ display: grid;
50
+ grid-template-rows: auto minmax(0, 1fr);
43
51
  position: relative;
52
+ width: 100%;
53
+ height: 100%;
44
54
  min-width: 0;
45
55
  min-height: 0;
46
56
  }
47
57
 
48
- #graph {
49
- display: block;
58
+ .graph-header {
59
+ z-index: 5;
60
+ display: flex;
61
+ align-items: center;
62
+ gap: 12px;
63
+ min-height: 72px;
64
+ padding: 10px 16px;
65
+ border-bottom: 1px solid var(--line);
66
+ background: linear-gradient(180deg, rgba(17, 21, 27, 0.96) 0%, rgba(17, 21, 27, 0.86) 100%);
67
+ backdrop-filter: blur(8px);
68
+ }
69
+
70
+ .brand-block {
71
+ display: grid;
72
+ gap: 2px;
73
+ min-width: max-content;
74
+ }
75
+
76
+ .brand-block strong {
77
+ font-size: 18px;
78
+ }
79
+
80
+ .graph-stage {
81
+ position: relative;
50
82
  width: 100%;
51
83
  height: 100%;
52
84
  background:
53
85
  radial-gradient(circle at 18% 20%, rgba(53, 208, 162, 0.12), transparent 28rem),
54
86
  linear-gradient(135deg, #0d0f12 0%, #12161c 55%, #0a0d10 100%);
55
- cursor: grab;
87
+ overflow: hidden;
56
88
  }
57
89
 
58
- #graph:active {
59
- cursor: grabbing;
90
+ #graph,
91
+ #graphGl {
92
+ display: block;
93
+ position: absolute;
94
+ inset: 0;
95
+ width: 100%;
96
+ height: 100%;
60
97
  }
61
98
 
62
- .topbar {
63
- position: absolute;
64
- top: 18px;
65
- left: 18px;
66
- right: 18px;
67
- display: flex;
68
- align-items: center;
69
- justify-content: space-between;
70
- gap: 18px;
71
- pointer-events: none;
99
+ #graph {
100
+ cursor: grab;
72
101
  }
73
102
 
74
- .topbar > div {
75
- display: flex;
76
- align-items: baseline;
77
- gap: 12px;
103
+ #graphGl {
104
+ pointer-events: none;
78
105
  }
79
106
 
80
- .topbar strong {
81
- font-size: 18px;
107
+ #graph:active {
108
+ cursor: grabbing;
82
109
  }
83
110
 
84
- .topbar span,
85
- .eyebrow,
86
- .inspector small {
111
+ .eyebrow {
87
112
  color: var(--muted);
88
113
  font-size: 12px;
89
114
  }
90
115
 
91
116
  .search {
92
- width: min(420px, 42vw);
93
- pointer-events: auto;
117
+ flex: 1 1 320px;
118
+ min-width: 220px;
94
119
  }
95
120
 
96
121
  .agent-filter {
97
122
  width: min(220px, 28vw);
98
- pointer-events: auto;
123
+ }
124
+
125
+ .header-actions {
126
+ display: flex;
127
+ align-items: center;
128
+ gap: 10px;
129
+ margin-left: auto;
99
130
  }
100
131
 
101
132
  .search input,
@@ -116,9 +147,6 @@ select {
116
147
  }
117
148
 
118
149
  .toolbar {
119
- position: absolute;
120
- left: 18px;
121
- bottom: 18px;
122
150
  display: flex;
123
151
  gap: 8px;
124
152
  }
@@ -138,70 +166,34 @@ select {
138
166
  color: var(--accent);
139
167
  }
140
168
 
141
- .inspector {
142
- display: grid;
143
- grid-template-rows: auto auto auto auto auto 1fr 1fr;
144
- gap: 22px;
145
- min-width: 0;
146
- height: 100%;
147
- padding: 24px;
148
- border-left: 1px solid var(--line);
149
- background: var(--panel);
150
- overflow: auto;
169
+ .floating-metrics {
170
+ display: flex;
171
+ gap: 10px;
172
+ flex-wrap: wrap;
151
173
  }
152
174
 
153
- .inspector h1,
154
- .inspector h2,
155
- .inspector p {
156
- margin: 0;
175
+ .metric-chip {
176
+ min-width: 94px;
177
+ padding: 10px 12px;
178
+ border: 1px solid var(--line);
179
+ border-radius: 10px;
180
+ background: rgba(21, 25, 31, 0.88);
181
+ display: grid;
182
+ gap: 3px;
157
183
  }
158
184
 
159
- .inspector h1 {
160
- margin-top: 6px;
185
+ .metric-chip strong {
161
186
  font-size: 26px;
162
- line-height: 1.12;
163
- overflow-wrap: anywhere;
187
+ line-height: 1;
164
188
  }
165
189
 
166
- .inspector h2 {
167
- margin-bottom: 10px;
190
+ .metric-chip small {
168
191
  color: var(--muted);
169
- font-size: 12px;
170
- font-weight: 700;
192
+ font-size: 11px;
193
+ letter-spacing: 0.03em;
171
194
  text-transform: uppercase;
172
195
  }
173
196
 
174
- #path {
175
- margin-top: 10px;
176
- color: var(--muted);
177
- line-height: 1.45;
178
- overflow-wrap: anywhere;
179
- }
180
-
181
- .metrics {
182
- display: grid;
183
- grid-template-columns: repeat(3, 1fr);
184
- border: 1px solid var(--line);
185
- border-radius: 8px;
186
- overflow: hidden;
187
- }
188
-
189
- .metrics div {
190
- display: grid;
191
- gap: 4px;
192
- padding: 14px;
193
- background: var(--panel-strong);
194
- }
195
-
196
- .metrics div + div {
197
- border-left: 1px solid var(--line);
198
- }
199
-
200
- .metrics span {
201
- font-size: 22px;
202
- font-weight: 700;
203
- }
204
-
205
197
  .tags {
206
198
  display: flex;
207
199
  flex-wrap: wrap;
@@ -215,6 +207,7 @@ select {
215
207
  background: var(--accent-weak);
216
208
  color: var(--accent);
217
209
  font-size: 12px;
210
+ word-break: break-word;
218
211
  overflow-wrap: anywhere;
219
212
  }
220
213
 
@@ -230,6 +223,7 @@ li {
230
223
  padding: 10px 0;
231
224
  border-bottom: 1px solid var(--line);
232
225
  color: var(--text);
226
+ word-break: break-word;
233
227
  overflow-wrap: anywhere;
234
228
  }
235
229
 
@@ -253,7 +247,7 @@ li small {
253
247
  }
254
248
 
255
249
  .note-content {
256
- max-height: 32svh;
250
+ max-height: min(68svh, 760px);
257
251
  margin: 0;
258
252
  padding: 12px;
259
253
  border: 1px solid var(--line);
@@ -267,28 +261,165 @@ li small {
267
261
  line-height: 1.5;
268
262
  }
269
263
 
270
- @media (max-width: 860px) {
271
- .shell {
272
- grid-template-columns: 1fr;
273
- grid-template-rows: minmax(0, 1fr) 42svh;
274
- }
264
+ .content-dialog {
265
+ width: min(1240px, calc(100vw - 24px));
266
+ max-height: calc(100svh - 20px);
267
+ padding: 0;
268
+ border: 1px solid var(--line);
269
+ border-radius: 8px;
270
+ background: var(--panel);
271
+ color: var(--text);
272
+ box-shadow: 0 24px 80px rgba(0, 0, 0, 0.48);
273
+ }
275
274
 
276
- .inspector {
277
- border-left: 0;
278
- border-top: 1px solid var(--line);
279
- padding: 18px;
280
- }
275
+ .content-dialog::backdrop {
276
+ background: rgba(4, 7, 10, 0.72);
277
+ backdrop-filter: blur(4px);
278
+ }
279
+
280
+ .content-dialog article {
281
+ display: grid;
282
+ grid-template-rows: auto auto minmax(0, 1fr);
283
+ max-height: calc(100svh - 22px);
284
+ }
285
+
286
+ .content-dialog header {
287
+ display: flex;
288
+ align-items: flex-start;
289
+ justify-content: space-between;
290
+ gap: 18px;
291
+ padding: 22px;
292
+ border-bottom: 1px solid var(--line);
293
+ }
294
+
295
+ .content-dialog h2,
296
+ .content-dialog p {
297
+ margin: 0;
298
+ }
299
+
300
+ .content-dialog h2 {
301
+ margin-top: 6px;
302
+ font-size: 24px;
303
+ line-height: 1.15;
304
+ overflow-wrap: anywhere;
305
+ }
306
+
307
+ .content-dialog p {
308
+ margin-top: 8px;
309
+ color: var(--muted);
310
+ overflow-wrap: anywhere;
311
+ }
312
+
313
+ .content-dialog button {
314
+ flex: 0 0 auto;
315
+ height: 38px;
316
+ padding: 0 14px;
317
+ border: 1px solid var(--line);
318
+ border-radius: 8px;
319
+ background: var(--panel-strong);
320
+ color: var(--text);
321
+ cursor: pointer;
322
+ }
323
+
324
+ .content-dialog button:hover,
325
+ .content-dialog button:focus {
326
+ border-color: var(--accent);
327
+ color: var(--accent);
328
+ }
329
+
330
+ .content-meta {
331
+ display: grid;
332
+ grid-template-columns: repeat(3, minmax(0, 1fr));
333
+ gap: 10px;
334
+ padding: 14px 22px;
335
+ border-bottom: 1px solid var(--line);
336
+ }
337
+
338
+ .content-meta-section {
339
+ min-height: 0;
340
+ padding: 10px;
341
+ border: 1px solid var(--line);
342
+ border-radius: 8px;
343
+ background: var(--panel-strong);
344
+ display: grid;
345
+ grid-template-rows: auto minmax(0, 1fr);
346
+ gap: 8px;
347
+ }
348
+
349
+ .content-meta-section h3 {
350
+ margin: 0;
351
+ color: var(--muted);
352
+ font-size: 11px;
353
+ font-weight: 700;
354
+ text-transform: uppercase;
355
+ }
356
+
357
+ .content-meta-section ul,
358
+ .content-meta-section .tags {
359
+ max-height: 220px;
360
+ overflow: auto;
361
+ align-content: flex-start;
362
+ padding-right: 4px;
363
+ }
364
+
365
+ .content-dialog .note-content {
366
+ max-height: none;
367
+ min-height: 0;
368
+ border: 0;
369
+ border-radius: 0;
370
+ padding: 22px;
371
+ }
281
372
 
282
- .topbar {
373
+ .app-footer {
374
+ flex: 0 0 28px;
375
+ height: 28px;
376
+ display: flex;
377
+ align-items: center;
378
+ justify-content: center;
379
+ background: transparent;
380
+ }
381
+
382
+ .app-footer small {
383
+ color: var(--muted);
384
+ font-size: 11px;
385
+ letter-spacing: 0.02em;
386
+ }
387
+
388
+ @media (max-width: 860px) {
389
+ .graph-header {
283
390
  align-items: stretch;
284
- flex-direction: column;
391
+ flex-wrap: wrap;
392
+ padding: 10px 12px;
393
+ min-height: 0;
285
394
  }
286
395
 
287
396
  .search {
288
397
  width: 100%;
398
+ flex-basis: 100%;
399
+ order: 3;
289
400
  }
290
401
 
291
402
  .agent-filter {
292
403
  width: 100%;
293
404
  }
405
+
406
+ .header-actions {
407
+ width: 100%;
408
+ margin-left: 0;
409
+ justify-content: space-between;
410
+ order: 4;
411
+ }
412
+
413
+ .content-dialog header {
414
+ align-items: stretch;
415
+ flex-direction: column;
416
+ }
417
+
418
+ .metric-chip {
419
+ min-width: 82px;
420
+ }
421
+
422
+ .content-meta {
423
+ grid-template-columns: 1fr;
424
+ }
294
425
  }`;
@@ -9,58 +9,76 @@ export const createClientHtml = () => `<!doctype html>
9
9
  <body>
10
10
  <main class="shell">
11
11
  <section class="workspace" aria-label="Knowledge graph">
12
- <canvas id="graph" aria-label="Brainlink knowledge graph"></canvas>
13
- <div class="topbar">
14
- <div>
12
+ <header class="graph-header" aria-label="Graph actions">
13
+ <div class="brand-block">
15
14
  <strong>Brainlink</strong>
16
- <span id="stats">Loading graph</span>
15
+ <span class="eyebrow">Knowledge Graph</span>
16
+ </div>
17
+ <div class="floating-metrics" aria-label="Graph totals">
18
+ <div class="metric-chip">
19
+ <strong id="nodeCount">0</strong>
20
+ <small>Notes</small>
21
+ </div>
22
+ <div class="metric-chip">
23
+ <strong id="edgeCount">0</strong>
24
+ <small>Links</small>
25
+ </div>
26
+ <div class="metric-chip">
27
+ <strong id="tagCount">0</strong>
28
+ <small>Tags</small>
29
+ </div>
17
30
  </div>
18
31
  <label class="search">
19
32
  <input id="search" type="search" placeholder="Filter notes, tags or paths" autocomplete="off" />
20
33
  </label>
21
- <label class="agent-filter">
22
- <select id="agent"></select>
23
- </label>
24
- </div>
25
- <div class="toolbar" aria-label="Graph controls">
26
- <button id="zoomIn" type="button" title="Zoom in">+</button>
27
- <button id="zoomOut" type="button" title="Zoom out">-</button>
28
- <button id="reset" type="button" title="Reset view">⌂</button>
34
+ <div class="header-actions">
35
+ <label class="agent-filter">
36
+ <select id="agent"></select>
37
+ </label>
38
+ <div class="toolbar" aria-label="Graph controls">
39
+ <button id="zoomIn" type="button" title="Zoom in">+</button>
40
+ <button id="zoomOut" type="button" title="Zoom out">-</button>
41
+ <button id="fit" type="button" title="Focus central hub">◎</button>
42
+ <button id="reset" type="button" title="Reset view">⌂</button>
43
+ </div>
44
+ </div>
45
+ </header>
46
+ <div class="graph-stage">
47
+ <canvas id="graphGl" aria-hidden="true"></canvas>
48
+ <canvas id="graph" aria-label="Brainlink knowledge graph"></canvas>
29
49
  </div>
30
50
  </section>
31
- <aside class="inspector" aria-label="Selected note">
32
- <div>
33
- <span class="eyebrow">Selected note</span>
34
- <h1 id="title">Graph Overview</h1>
35
- <p id="path">Select a node to inspect links and backlinks.</p>
36
- </div>
37
- <div class="metrics">
38
- <div><span id="nodeCount">0</span><small>Notes</small></div>
39
- <div><span id="edgeCount">0</span><small>Links</small></div>
40
- <div><span id="tagCount">0</span><small>Tags</small></div>
41
- </div>
42
- <section>
43
- <h2>Tags</h2>
44
- <div id="tags" class="tags"></div>
45
- </section>
46
- <section>
47
- <h2>Notes</h2>
48
- <ul id="notes"></ul>
49
- </section>
50
- <section>
51
- <h2>Content</h2>
52
- <pre id="content" class="note-content"></pre>
53
- </section>
54
- <section>
55
- <h2>Outgoing</h2>
56
- <ul id="outgoing"></ul>
57
- </section>
58
- <section>
59
- <h2>Backlinks</h2>
60
- <ul id="incoming"></ul>
61
- </section>
62
- </aside>
63
51
  </main>
52
+ <footer class="app-footer" aria-label="Copyright notice">
53
+ <small>Copyright © 2026 Substructa</small>
54
+ </footer>
55
+ <dialog id="contentDialog" class="content-dialog" aria-labelledby="contentTitle">
56
+ <article>
57
+ <header>
58
+ <div>
59
+ <span class="eyebrow">Markdown content</span>
60
+ <h2 id="contentTitle">Selected note</h2>
61
+ <p id="contentPath"></p>
62
+ </div>
63
+ <button id="contentClose" type="button">Close</button>
64
+ </header>
65
+ <div class="content-meta">
66
+ <section class="content-meta-section">
67
+ <h3>Tags</h3>
68
+ <div id="contentTags" class="tags"></div>
69
+ </section>
70
+ <section class="content-meta-section">
71
+ <h3>Outgoing</h3>
72
+ <ul id="contentOutgoing"></ul>
73
+ </section>
74
+ <section class="content-meta-section">
75
+ <h3>Backlinks</h3>
76
+ <ul id="contentIncoming"></ul>
77
+ </section>
78
+ </div>
79
+ <pre id="contentBody" class="note-content"></pre>
80
+ </article>
81
+ </dialog>
64
82
  <script src="/app.js"></script>
65
83
  </body>
66
84
  </html>`;