@andespindola/brainlink 1.6.5 → 1.6.6
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/dist/application/frontend/client/elements.js +1 -0
- package/dist/application/frontend/client/live-refresh.js +42 -0
- package/dist/application/frontend/client/worker-bootstrap.js +1 -0
- package/dist/application/frontend/client-js.js +2 -0
- package/dist/application/server/graph-version.js +11 -0
- package/dist/application/server/routes.js +6 -0
- package/dist/application/start-server.js +7 -0
- package/package.json +1 -1
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export const createLiveRefreshJs = () => `
|
|
2
|
+
// Poll a cheap generation counter so the graph reflects vault changes live:
|
|
3
|
+
// when an agent writes notes via MCP, the watcher bumps the version and the
|
|
4
|
+
// client re-fetches the current viewport and refreshes the context list, so new
|
|
5
|
+
// nodes and contexts surface without a manual reload.
|
|
6
|
+
const liveRefreshIntervalMs = 3000
|
|
7
|
+
|
|
8
|
+
const pollGraphVersion = async () => {
|
|
9
|
+
try {
|
|
10
|
+
const response = await fetch('/api/graph-version', { headers: { accept: 'application/json' } })
|
|
11
|
+
if (!response.ok) {
|
|
12
|
+
return
|
|
13
|
+
}
|
|
14
|
+
const payload = await response.json()
|
|
15
|
+
const version = typeof payload?.version === 'number' ? payload.version : null
|
|
16
|
+
if (version === null) {
|
|
17
|
+
return
|
|
18
|
+
}
|
|
19
|
+
if (state.graphVersion === null) {
|
|
20
|
+
state.graphVersion = version
|
|
21
|
+
return
|
|
22
|
+
}
|
|
23
|
+
if (version !== state.graphVersion) {
|
|
24
|
+
state.graphVersion = version
|
|
25
|
+
await loadContexts().catch((error) => console.error(error))
|
|
26
|
+
scheduleChunkFetch()
|
|
27
|
+
}
|
|
28
|
+
} catch (error) {
|
|
29
|
+
// Transient poll failures (offline, redeploy) are non-fatal; the next tick retries.
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const startLiveRefresh = () => {
|
|
34
|
+
if (typeof fetch !== 'function') {
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
pollGraphVersion().catch(() => {})
|
|
38
|
+
setInterval(() => {
|
|
39
|
+
pollGraphVersion().catch(() => {})
|
|
40
|
+
}, liveRefreshIntervalMs)
|
|
41
|
+
}
|
|
42
|
+
`;
|
|
@@ -8,6 +8,7 @@ import { createChunkFetchJs } from './client/chunk-fetch.js';
|
|
|
8
8
|
import { createInputJs } from './client/input.js';
|
|
9
9
|
import { createUploadJs } from './client/upload.js';
|
|
10
10
|
import { createControlsJs } from './client/controls.js';
|
|
11
|
+
import { createLiveRefreshJs } from './client/live-refresh.js';
|
|
11
12
|
import { createGraphRendererJs } from './client/graph-renderer.js';
|
|
12
13
|
import { createWorkerBootstrapJs } from './client/worker-bootstrap.js';
|
|
13
14
|
export const createClientJs = () => [
|
|
@@ -21,6 +22,7 @@ export const createClientJs = () => [
|
|
|
21
22
|
createInputJs(),
|
|
22
23
|
createUploadJs(),
|
|
23
24
|
createControlsJs(),
|
|
25
|
+
createLiveRefreshJs(),
|
|
24
26
|
createGraphRendererJs(),
|
|
25
27
|
createWorkerBootstrapJs()
|
|
26
28
|
].join('');
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Monotonic generation counter for the graph. The vault watcher bumps it after
|
|
2
|
+
// every reindex, and the web client polls /api/graph-version to know when to
|
|
3
|
+
// re-fetch — so nodes and contexts written by an agent (via MCP) surface live
|
|
4
|
+
// in an open graph without a manual reload. Process-local by design: a restart
|
|
5
|
+
// resets it, which the client simply treats as one more change.
|
|
6
|
+
let version = 0;
|
|
7
|
+
export const bumpGraphVersion = () => {
|
|
8
|
+
version += 1;
|
|
9
|
+
return version;
|
|
10
|
+
};
|
|
11
|
+
export const getGraphVersion = () => version;
|
|
@@ -24,6 +24,7 @@ import { createClientWorkerJs } from '../frontend/client-worker-js.js';
|
|
|
24
24
|
import { createClientRenderWorkerJs } from '../frontend/client-render-worker-js.js';
|
|
25
25
|
import { createLoginPageHtml, createChangePasswordPageHtml } from '../frontend/login-page.js';
|
|
26
26
|
import { buildClearSessionCookie, buildSessionSetCookie, changeWebPassword, createSessionToken, parseCookies, resolveWebAuth, SESSION_COOKIE_NAME, verifySessionToken, verifyWebPassword } from './web-auth.js';
|
|
27
|
+
import { getGraphVersion } from './graph-version.js';
|
|
27
28
|
import { contentTypes, createJsonResponse, isReadMethod, parsePositiveInteger } from './http.js';
|
|
28
29
|
import { parseMultipartForm } from './multipart.js';
|
|
29
30
|
const readRuntimeDefaults = async (url) => {
|
|
@@ -519,6 +520,11 @@ export const route = async (request, url, vaultPath, options = {}) => {
|
|
|
519
520
|
if (isReadMethod(request) && url.pathname === '/api/agents') {
|
|
520
521
|
return createResponse(createJsonResponse({ agents: await listAgents(vaultPath) }), 200, contentTypes['.json']);
|
|
521
522
|
}
|
|
523
|
+
// Cheap generation counter the client polls to auto-refresh when the vault
|
|
524
|
+
// changes (new nodes/contexts written via MCP surface live).
|
|
525
|
+
if (isReadMethod(request) && url.pathname === '/api/graph-version') {
|
|
526
|
+
return createResponse(createJsonResponse({ version: getGraphVersion() }), 200, contentTypes['.json']);
|
|
527
|
+
}
|
|
522
528
|
if (isReadMethod(request) && url.pathname === '/api/graph-contexts') {
|
|
523
529
|
return createResponse(createJsonResponse({ contexts: await getGraphContexts(vaultPath, readAgentQuery(url)) }), 200, contentTypes['.json']);
|
|
524
530
|
}
|
|
@@ -2,6 +2,7 @@ import { createServer } from 'node:http';
|
|
|
2
2
|
import { brotliCompressSync, constants, gzipSync } from 'node:zlib';
|
|
3
3
|
import { indexVault } from './index-vault.js';
|
|
4
4
|
import { startVaultWatcher } from './watch-vault.js';
|
|
5
|
+
import { bumpGraphVersion } from './server/graph-version.js';
|
|
5
6
|
import { assertLoopbackHost } from './server/host-security.js';
|
|
6
7
|
import { contentTypes, createJsonResponse, isHttpError } from './server/http.js';
|
|
7
8
|
import { route } from './server/routes.js';
|
|
@@ -82,10 +83,16 @@ export const startServer = async (input) => {
|
|
|
82
83
|
}
|
|
83
84
|
if (input.shouldIndex) {
|
|
84
85
|
await indexVault(input.vaultPath);
|
|
86
|
+
bumpGraphVersion();
|
|
85
87
|
}
|
|
86
88
|
const watcher = input.shouldWatch
|
|
87
89
|
? startVaultWatcher({
|
|
88
90
|
vaultPath: input.vaultPath,
|
|
91
|
+
// Signal the web client (via /api/graph-version) that the graph changed
|
|
92
|
+
// so it can re-fetch and surface new nodes/contexts live.
|
|
93
|
+
onIndex: () => {
|
|
94
|
+
bumpGraphVersion();
|
|
95
|
+
},
|
|
89
96
|
onError: (error) => console.error(error)
|
|
90
97
|
})
|
|
91
98
|
: null;
|
package/package.json
CHANGED