relaybrain 0.2.0 → 0.2.1
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 +434 -291
- package/backend/lib/falkor/demo.js +221 -0
- package/backend/lib/falkor/migrations.js +56 -56
- package/backend/lib/falkor/routes.js +52 -8
- package/backend/lib/localBrowse.js +109 -109
- package/backend/lib/notices.js +7 -0
- package/backend/lib/room.js +152 -12
- package/backend/lib/transcripts/discover.js +109 -10
- package/backend/server.js +62 -7
- package/cli/graph.js +8 -0
- package/cli/relay.js +64 -8
- package/docs/MEMORY-GRAPH.md +57 -12
- package/mission-control/out/404.html +1 -1
- package/mission-control/out/__next.__PAGE__.txt +3 -3
- package/mission-control/out/__next._full.txt +3 -3
- package/mission-control/out/__next._tree.txt +2 -2
- package/mission-control/out/_next/static/chunks/064ntycm-fx5v.js +1 -0
- package/mission-control/out/_next/static/chunks/{25rvg4bnew99f.css → 1-dy52ls2ntb_.css} +1 -1
- package/mission-control/out/_next/static/chunks/31qgr-p-oulpb.js +1 -0
- package/mission-control/out/_not-found/__next._full.txt +1 -1
- package/mission-control/out/_not-found/__next._not-found/__PAGE__.txt +1 -1
- package/mission-control/out/_not-found/__next._tree.txt +1 -1
- package/mission-control/out/_not-found.html +1 -1
- package/mission-control/out/_not-found.txt +1 -1
- package/mission-control/out/index.html +1 -1
- package/mission-control/out/index.txt +3 -3
- package/package.json +76 -76
- package/scripts/falkor-rebuild.js +8 -27
- package/scripts/falkor-seed-demo.js +12 -140
- package/mission-control/out/_next/static/chunks/3_5x4qn1_b4al.js +0 -1
- package/mission-control/out/_next/static/chunks/3o1tiwncjss_k.js +0 -1
- /package/mission-control/out/_next/static/{dglM39XRu0cmneClUkGYd → BuhfCxd0WQE65yIzZJCOM}/_buildManifest.js +0 -0
- /package/mission-control/out/_next/static/{dglM39XRu0cmneClUkGYd → BuhfCxd0WQE65yIzZJCOM}/_clientMiddlewareManifest.js +0 -0
- /package/mission-control/out/_next/static/{dglM39XRu0cmneClUkGYd → BuhfCxd0WQE65yIzZJCOM}/_ssgManifest.js +0 -0
package/package.json
CHANGED
|
@@ -1,76 +1,76 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "relaybrain",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"description": "Coordination layer for parallel AI coding agents — file locks, patch sync, Mission Control, and a FalkorDB memory graph that tells every agent who is doing what, and why.",
|
|
5
|
-
"keywords": [
|
|
6
|
-
"ai-agents",
|
|
7
|
-
"multi-agent",
|
|
8
|
-
"coordination",
|
|
9
|
-
"agent-memory",
|
|
10
|
-
"falkordb",
|
|
11
|
-
"graph",
|
|
12
|
-
"mcp",
|
|
13
|
-
"claude-code",
|
|
14
|
-
"cursor",
|
|
15
|
-
"codex",
|
|
16
|
-
"copilot",
|
|
17
|
-
"file-locking"
|
|
18
|
-
],
|
|
19
|
-
"homepage": "https://relay-brain.vercel.app",
|
|
20
|
-
"repository": {
|
|
21
|
-
"type": "git",
|
|
22
|
-
"url": "git+https://github.com/prakrititz/relayBrain.git"
|
|
23
|
-
},
|
|
24
|
-
"bugs": {
|
|
25
|
-
"url": "https://github.com/prakrititz/relayBrain/issues"
|
|
26
|
-
},
|
|
27
|
-
"license": "MIT",
|
|
28
|
-
"workspaces": [
|
|
29
|
-
"mission-control"
|
|
30
|
-
],
|
|
31
|
-
"bin": {
|
|
32
|
-
"relay": "cli/relay.js",
|
|
33
|
-
"relaybrain": "cli/relay.js"
|
|
34
|
-
},
|
|
35
|
-
"files": [
|
|
36
|
-
"backend/",
|
|
37
|
-
"!backend/**/*.test.js",
|
|
38
|
-
"cli/",
|
|
39
|
-
"hooks/",
|
|
40
|
-
"mission-control/out/",
|
|
41
|
-
"scripts/falkor-rebuild.js",
|
|
42
|
-
"scripts/falkor-seed-demo.js",
|
|
43
|
-
"docker-compose.falkor.yml",
|
|
44
|
-
"docs/MEMORY-GRAPH.md"
|
|
45
|
-
],
|
|
46
|
-
"scripts": {
|
|
47
|
-
"dev": "concurrently -n api,ui -c cyan,magenta \"node backend/server.js --port 3001\" \"npm run dev -w mission-control\"",
|
|
48
|
-
"dev:api": "node backend/server.js --port 3001",
|
|
49
|
-
"dev:ui": "npm run dev -w mission-control",
|
|
50
|
-
"start": "node backend/server.js --port 3001",
|
|
51
|
-
"coordinator": "node backend/coordinator/server.js",
|
|
52
|
-
"test": "node scripts/run-tests.js",
|
|
53
|
-
"build:ui": "node scripts/build-ui.js",
|
|
54
|
-
"prepack": "node scripts/build-ui.js",
|
|
55
|
-
"falkor:up": "docker compose -f docker-compose.falkor.yml up -d",
|
|
56
|
-
"falkor:down": "docker compose -f docker-compose.falkor.yml down",
|
|
57
|
-
"falkor:spike": "node scripts/falkor-spike.js",
|
|
58
|
-
"falkor:rebuild": "node scripts/falkor-rebuild.js",
|
|
59
|
-
"falkor:seed-demo": "node scripts/falkor-seed-demo.js",
|
|
60
|
-
"test:e2e": "node scripts/e2e-full-test.js",
|
|
61
|
-
"test:e2e:room": "node scripts/e2e-room-test.js"
|
|
62
|
-
},
|
|
63
|
-
"dependencies": {
|
|
64
|
-
"@vscode/tree-sitter-wasm": "^0.3.1",
|
|
65
|
-
"cors": "^2.8.5",
|
|
66
|
-
"express": "^4.21.2",
|
|
67
|
-
"falkordb": "^6.8.0",
|
|
68
|
-
"ws": "^8.18.0"
|
|
69
|
-
},
|
|
70
|
-
"devDependencies": {
|
|
71
|
-
"concurrently": "^9.1.2"
|
|
72
|
-
},
|
|
73
|
-
"engines": {
|
|
74
|
-
"node": ">=20"
|
|
75
|
-
}
|
|
76
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "relaybrain",
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"description": "Coordination layer for parallel AI coding agents — file locks, patch sync, Mission Control, and a FalkorDB memory graph that tells every agent who is doing what, and why.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"ai-agents",
|
|
7
|
+
"multi-agent",
|
|
8
|
+
"coordination",
|
|
9
|
+
"agent-memory",
|
|
10
|
+
"falkordb",
|
|
11
|
+
"graph",
|
|
12
|
+
"mcp",
|
|
13
|
+
"claude-code",
|
|
14
|
+
"cursor",
|
|
15
|
+
"codex",
|
|
16
|
+
"copilot",
|
|
17
|
+
"file-locking"
|
|
18
|
+
],
|
|
19
|
+
"homepage": "https://relay-brain.vercel.app",
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/prakrititz/relayBrain.git"
|
|
23
|
+
},
|
|
24
|
+
"bugs": {
|
|
25
|
+
"url": "https://github.com/prakrititz/relayBrain/issues"
|
|
26
|
+
},
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"workspaces": [
|
|
29
|
+
"mission-control"
|
|
30
|
+
],
|
|
31
|
+
"bin": {
|
|
32
|
+
"relay": "cli/relay.js",
|
|
33
|
+
"relaybrain": "cli/relay.js"
|
|
34
|
+
},
|
|
35
|
+
"files": [
|
|
36
|
+
"backend/",
|
|
37
|
+
"!backend/**/*.test.js",
|
|
38
|
+
"cli/",
|
|
39
|
+
"hooks/",
|
|
40
|
+
"mission-control/out/",
|
|
41
|
+
"scripts/falkor-rebuild.js",
|
|
42
|
+
"scripts/falkor-seed-demo.js",
|
|
43
|
+
"docker-compose.falkor.yml",
|
|
44
|
+
"docs/MEMORY-GRAPH.md"
|
|
45
|
+
],
|
|
46
|
+
"scripts": {
|
|
47
|
+
"dev": "concurrently -n api,ui -c cyan,magenta \"node backend/server.js --port 3001\" \"npm run dev -w mission-control\"",
|
|
48
|
+
"dev:api": "node backend/server.js --port 3001",
|
|
49
|
+
"dev:ui": "npm run dev -w mission-control",
|
|
50
|
+
"start": "node backend/server.js --port 3001",
|
|
51
|
+
"coordinator": "node backend/coordinator/server.js",
|
|
52
|
+
"test": "node scripts/run-tests.js",
|
|
53
|
+
"build:ui": "node scripts/build-ui.js",
|
|
54
|
+
"prepack": "node scripts/build-ui.js",
|
|
55
|
+
"falkor:up": "docker compose -f docker-compose.falkor.yml up -d",
|
|
56
|
+
"falkor:down": "docker compose -f docker-compose.falkor.yml down",
|
|
57
|
+
"falkor:spike": "node scripts/falkor-spike.js",
|
|
58
|
+
"falkor:rebuild": "node scripts/falkor-rebuild.js",
|
|
59
|
+
"falkor:seed-demo": "node scripts/falkor-seed-demo.js",
|
|
60
|
+
"test:e2e": "node scripts/e2e-full-test.js",
|
|
61
|
+
"test:e2e:room": "node scripts/e2e-room-test.js"
|
|
62
|
+
},
|
|
63
|
+
"dependencies": {
|
|
64
|
+
"@vscode/tree-sitter-wasm": "^0.3.1",
|
|
65
|
+
"cors": "^2.8.5",
|
|
66
|
+
"express": "^4.21.2",
|
|
67
|
+
"falkordb": "^6.8.0",
|
|
68
|
+
"ws": "^8.18.0"
|
|
69
|
+
},
|
|
70
|
+
"devDependencies": {
|
|
71
|
+
"concurrently": "^9.1.2"
|
|
72
|
+
},
|
|
73
|
+
"engines": {
|
|
74
|
+
"node": ">=20"
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -2,32 +2,8 @@
|
|
|
2
2
|
// Drop one project's memory graph and rebuild it from ~/.relay data.
|
|
3
3
|
// RELAY_FALKOR_URL=falkor://localhost:6379 node scripts/falkor-rebuild.js <projectId|all> [--keep]
|
|
4
4
|
const falkor = require("../backend/lib/falkor");
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const { ingestHistory, ingestPeer } = require("../backend/lib/falkor/ingest");
|
|
8
|
-
const analytics = require("../backend/lib/falkor/analytics");
|
|
9
|
-
const { loadRegistry, loadMemory } = require("../backend/lib/store");
|
|
10
|
-
|
|
11
|
-
async function rebuildOne(project, keep) {
|
|
12
|
-
const { client } = falkor.state;
|
|
13
|
-
if (!keep) {
|
|
14
|
-
await client.deleteGraph(project.id);
|
|
15
|
-
schema.forget(project.id);
|
|
16
|
-
cursor.reset(project.id);
|
|
17
|
-
}
|
|
18
|
-
const memory = loadMemory(project.id);
|
|
19
|
-
const history = memory.history || [];
|
|
20
|
-
const t = Date.now();
|
|
21
|
-
const result = await ingestHistory(project.id, history, project.path, { full: true });
|
|
22
|
-
const peers = Object.entries(memory.roomPeers || {});
|
|
23
|
-
for (const [key, snapshot] of peers) {
|
|
24
|
-
await ingestPeer(project.id, { snapshot, login: snapshot.login || key, trustRowOwners: key === "host" });
|
|
25
|
-
}
|
|
26
|
-
const stats = await analytics.run(project.id);
|
|
27
|
-
console.log(
|
|
28
|
-
`${project.id} ${project.path}\n events=${history.length} peers=${peers.length} ${JSON.stringify(result)} analytics=${JSON.stringify(stats)} in ${Date.now() - t}ms`
|
|
29
|
-
);
|
|
30
|
-
}
|
|
5
|
+
const { rebuildProjectGraph } = require("../backend/lib/falkor/demo");
|
|
6
|
+
const { loadRegistry } = require("../backend/lib/store");
|
|
31
7
|
|
|
32
8
|
async function main() {
|
|
33
9
|
const target = process.argv[2];
|
|
@@ -46,7 +22,12 @@ async function main() {
|
|
|
46
22
|
console.error(`no project ${target}`);
|
|
47
23
|
process.exit(2);
|
|
48
24
|
}
|
|
49
|
-
for (const p of projects)
|
|
25
|
+
for (const p of projects) {
|
|
26
|
+
const out = await rebuildProjectGraph(falkor, p.id, { keep });
|
|
27
|
+
console.log(
|
|
28
|
+
`${out.projectId} ${out.path}\n events=${out.events} peers=${out.peers} ${JSON.stringify(out.ingest)} analytics=${JSON.stringify(out.analytics)} in ${out.ms}ms`
|
|
29
|
+
);
|
|
30
|
+
}
|
|
50
31
|
await falkor.state.client.close();
|
|
51
32
|
process.exit(0);
|
|
52
33
|
}
|
|
@@ -1,154 +1,26 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// Seeds a rich, realistic multi-agent coordination history + FalkorDB graph for the live demo (#14, #15).
|
|
3
|
-
//
|
|
4
|
-
|
|
3
|
+
// By default seeds the isolated demo sandbox graph (`demo_<projectId>`), never polluting real workspace graphs.
|
|
4
|
+
// Pass `--raw` only if you explicitly want to write into the raw target projectId.
|
|
5
5
|
const falkor = require("../backend/lib/falkor");
|
|
6
|
-
const
|
|
7
|
-
const { projectHistory, projectPeer } = require("../backend/lib/falkor/project");
|
|
8
|
-
const { writeProjection } = require("../backend/lib/falkor/write");
|
|
9
|
-
const coord = require("../backend/lib/falkor/coord");
|
|
10
|
-
const central = require("../backend/lib/falkor/central");
|
|
11
|
-
const analytics = require("../backend/lib/falkor/analytics");
|
|
12
|
-
const intents = require("../backend/lib/falkor/intents");
|
|
6
|
+
const { seedDemoGraph } = require("../backend/lib/falkor/demo");
|
|
13
7
|
const { loadRegistry } = require("../backend/lib/store");
|
|
14
8
|
|
|
15
|
-
const WS = process.platform === "win32" ? "C:\\demo\\relay-app" : "/workspace/relay-app";
|
|
16
|
-
const wsFile = (...parts) => path.join(WS, ...parts);
|
|
17
|
-
|
|
18
|
-
const S_CLAUDE = "52b29a54-d8fb-4091-ab60-463ac73c9d6c";
|
|
19
|
-
const S_CURSOR = "3e62675d-9b0f-4d99-b17d-c1d875fe98dc";
|
|
20
|
-
const S_CODEX = "019e1fdf-e54d-70e2-ae26-d0d7103a404f";
|
|
21
|
-
const S_COPILOT = "fcc51653-804f-4e4f-9330-347a42abd57c";
|
|
22
|
-
const S_ANTI = "46d9adf1-1b25-4cf7-bd41-da8309d19f08";
|
|
23
|
-
|
|
24
|
-
function buildDemoHistory(now = Date.now()) {
|
|
25
|
-
const m = (minsAgo) => now - minsAgo * 60_000;
|
|
26
|
-
return [
|
|
27
|
-
// Session 1: Claude Code (@alice) switching login flow to JWT tokens
|
|
28
|
-
{ id: "d01", agent: "Claude Code", ownerLogin: "alice", sessionId: S_CLAUDE, ts: m(25), role: "user", kind: "message", text: "switch the login flow to short-lived JWT tokens with refresh rotation" },
|
|
29
|
-
{ id: "d02", agent: "Claude Code", ownerLogin: "alice", sessionId: S_CLAUDE, ts: m(24.5), role: "assistant", kind: "message", text: "I'll update src/auth.ts to issue 15-minute access JWTs and rotate refresh tokens in src/session.ts." },
|
|
30
|
-
{ id: "d03", agent: "Claude Code", ownerLogin: "alice", sessionId: S_CLAUDE, ts: m(24), role: "tool", kind: "code_edit", text: "Edit auth.ts", file: "auth.ts", path: wsFile("src", "auth.ts"), diff: "--- a/src/auth.ts\n+++ b/src/auth.ts\n@@ -10,4 +10,8 @@\n-export function loginWithCookie(user) {\n+export function issueJwtPair(user) {\n+ return signJwt(user, { expiresIn: '15m' });\n" },
|
|
31
|
-
{ id: "d04", agent: "Claude Code", ownerLogin: "alice", sessionId: S_CLAUDE, ts: m(23), role: "tool", kind: "code_edit", text: "Edit session.ts", file: "session.ts", path: wsFile("src", "session.ts"), diff: "--- a/src/session.ts\n+++ b/src/session.ts\n@@ -1,3 +1,6 @@\n+export function rotateRefreshToken(token) {\n+ return revokeAndMint(token);\n+}\n" },
|
|
32
|
-
{ id: "d05", agent: "Claude Code", ownerLogin: "alice", sessionId: S_CLAUDE, ts: m(22), role: "user", kind: "message", text: "continue" },
|
|
33
|
-
{ id: "d06", agent: "Claude Code", ownerLogin: "alice", sessionId: S_CLAUDE, ts: m(21.5), role: "tool", kind: "code_edit", text: "Edit middleware.ts", file: "middleware.ts", path: wsFile("src", "middleware.ts"), diff: "--- a/src/middleware.ts\n+++ b/src/middleware.ts\n@@ -4,2 +4,5 @@\n+export function verifyBearerJwt(req, res, next) {\n+ req.user = verifyJwt(req.headers.authorization);\n+}\n" },
|
|
34
|
-
|
|
35
|
-
// Session 2: Codex (@alice) hardening rate limits on auth & api routes
|
|
36
|
-
{ id: "d07", agent: "Codex", ownerLogin: "alice", sessionId: S_CODEX, ts: m(18), role: "user", kind: "message", text: "add sliding-window rate limiting to login and token refresh endpoints" },
|
|
37
|
-
{ id: "d08", agent: "Codex", ownerLogin: "alice", sessionId: S_CODEX, ts: m(17.5), role: "assistant", kind: "message", text: "Applying rate limiter middleware to src/routes.ts and src/auth.ts." },
|
|
38
|
-
{ id: "d09", agent: "Codex", ownerLogin: "alice", sessionId: S_CODEX, ts: m(17), role: "tool", kind: "code_edit", text: "apply_patch auth.ts", file: "auth.ts", path: wsFile("src", "auth.ts"), diff: "+import { rateLimit } from './rateLimit';\n+export const authLimiter = rateLimit({ windowMs: 60000, max: 10 });\n" },
|
|
39
|
-
{ id: "d10", agent: "Codex", ownerLogin: "alice", sessionId: S_CODEX, ts: m(16.8), role: "tool", kind: "code_edit", text: "apply_patch routes.ts", file: "routes.ts", path: wsFile("src", "routes.ts"), diff: "+app.post('/api/token/refresh', authLimiter, rotateRefreshToken);\n" },
|
|
40
|
-
|
|
41
|
-
// Session 3: Antigravity (@alice) updating UI auth client
|
|
42
|
-
{ id: "d11", agent: "Antigravity", ownerLogin: "alice", sessionId: S_ANTI, ts: m(12), role: "user", kind: "message", text: "wire automatic silent JWT refresh into the frontend API client" },
|
|
43
|
-
{ id: "d12", agent: "Antigravity", ownerLogin: "alice", sessionId: S_ANTI, ts: m(11.5), role: "assistant", kind: "message", text: "Updating src/client.ts and src/auth.ts types to retry 401 responses after refreshing the access token." },
|
|
44
|
-
{ id: "d13", agent: "Antigravity", ownerLogin: "alice", sessionId: S_ANTI, ts: m(11), role: "tool", kind: "code_edit", text: "replace_file_content client.ts", file: "client.ts", path: wsFile("src", "client.ts"), diff: "+if (res.status === 401) await refreshAccessToken();\n" },
|
|
45
|
-
{ id: "d14", agent: "Antigravity", ownerLogin: "alice", sessionId: S_ANTI, ts: m(10.5), role: "tool", kind: "code_edit", text: "replace_file_content auth.ts", file: "auth.ts", path: wsFile("src", "auth.ts"), diff: "+export type TokenPair = { accessToken: string; refreshToken: string; expiresIn: number };\n" },
|
|
46
|
-
];
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function buildPeerSnapshot(now = Date.now()) {
|
|
50
|
-
const m = (minsAgo) => now - minsAgo * 60_000;
|
|
51
|
-
return {
|
|
52
|
-
login: "bob",
|
|
53
|
-
chats: [
|
|
54
|
-
{
|
|
55
|
-
id: `chat_cursor_${S_CURSOR}`,
|
|
56
|
-
agent: "Cursor",
|
|
57
|
-
ownerLogin: "bob",
|
|
58
|
-
sessionId: S_CURSOR,
|
|
59
|
-
messages: [
|
|
60
|
-
{ role: "user", kind: "message", text: "add logout revocation endpoint and clear refresh token store", ts: m(20) },
|
|
61
|
-
{ role: "assistant", kind: "message", text: "Adding token revocation in src/auth.ts and src/session.ts.", ts: m(19.5) },
|
|
62
|
-
{ role: "tool", kind: "code_edit", text: "StrReplace auth.ts", file: "auth.ts", ts: m(19) },
|
|
63
|
-
{ role: "tool", kind: "code_edit", text: "StrReplace session.ts", file: "session.ts", ts: m(18.5) },
|
|
64
|
-
],
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
id: `chat_copilot_${S_COPILOT}`,
|
|
68
|
-
agent: "Copilot",
|
|
69
|
-
ownerLogin: "bob",
|
|
70
|
-
sessionId: S_COPILOT,
|
|
71
|
-
messages: [
|
|
72
|
-
{ role: "user", kind: "message", text: "add integration tests for JWT expiry and refresh rotation", ts: m(8) },
|
|
73
|
-
{ role: "assistant", kind: "message", text: "Creating tests/auth.test.ts and exporting verify helpers from src/auth.ts.", ts: m(7.5) },
|
|
74
|
-
{ role: "tool", kind: "code_edit", text: "replace_string_in_file auth.ts", file: "auth.ts", ts: m(7) },
|
|
75
|
-
{ role: "tool", kind: "code_edit", text: "create_file auth.test.ts", file: "auth.test.ts", ts: m(6.5) },
|
|
76
|
-
],
|
|
77
|
-
},
|
|
78
|
-
],
|
|
79
|
-
edits: [
|
|
80
|
-
{ id: "e_bob01", agent: "Cursor", ownerLogin: "bob", file: "src/auth.ts", ts: m(19), diff: "+export async function revokeSession(jti: string) { await denylist.add(jti); }\n" },
|
|
81
|
-
{ id: "e_bob02", agent: "Cursor", ownerLogin: "bob", file: "src/session.ts", ts: m(18.5), diff: "+export const denylist = new Set<string>();\n" },
|
|
82
|
-
{ id: "e_bob03", agent: "Copilot", ownerLogin: "bob", file: "src/auth.ts", ts: m(7), diff: "+export { verifyJwt } from './jwt';\n" },
|
|
83
|
-
{ id: "e_bob04", agent: "Copilot", ownerLogin: "bob", file: "tests/auth.test.ts", ts: m(6.5), diff: "+test('rotates refresh token and rejects replay', async () => {});\n" },
|
|
84
|
-
],
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
|
|
88
9
|
async function main() {
|
|
89
|
-
const
|
|
10
|
+
const args = process.argv.slice(2);
|
|
11
|
+
const rawTarget = args.includes("--raw");
|
|
12
|
+
const targetArg = args.find((a) => !a.startsWith("--"));
|
|
13
|
+
const baseId = targetArg || loadRegistry().projects?.[0]?.id || "proj_demo";
|
|
14
|
+
|
|
90
15
|
const info = falkor.init({ get() {}, post() {} }, {});
|
|
91
16
|
if (!info.enabled) {
|
|
92
17
|
console.error("FalkorDB is not enabled. Run `relay graph enable` or set RELAY_FALKOR_URL first.");
|
|
93
18
|
process.exit(1);
|
|
94
19
|
}
|
|
95
|
-
const {
|
|
96
|
-
|
|
97
|
-
await
|
|
98
|
-
|
|
99
|
-
const localProj = projectHistory(buildDemoHistory(now), { workspacePath: WS, storeText: true });
|
|
100
|
-
for (const i of localProj.intents.values()) intents.remember(i);
|
|
101
|
-
await writeProjection(client, targetId, localProj);
|
|
102
|
-
|
|
103
|
-
const peerProj = projectPeer(buildPeerSnapshot(now), { login: "bob", trustRowOwners: false, storeText: true });
|
|
104
|
-
for (const i of peerProj.intents.values()) intents.remember(i);
|
|
105
|
-
await writeProjection(client, targetId, peerProj);
|
|
106
|
-
|
|
107
|
-
// Record a realistic lock contention + active hold
|
|
108
|
-
coord.configure(falkor);
|
|
109
|
-
coord.recordHeld(targetId, `Claude Code:ALICE-DESK:${S_CLAUDE}`, "src/auth.ts", now - 2 * 60_000);
|
|
110
|
-
coord.recordContention(targetId, {
|
|
111
|
-
kind: "claim_blocked",
|
|
112
|
-
file: "src/auth.ts",
|
|
113
|
-
wanter: `Cursor:BOB-LAPTOP:${S_CURSOR}`,
|
|
114
|
-
holder: `Claude Code:ALICE-DESK:${S_CLAUDE}`,
|
|
115
|
-
reason: `File \`src/auth.ts\` is locked by Claude Code. They're working on: "switch the login flow to short-lived JWT tokens with refresh rotation" (2 min ago).`,
|
|
116
|
-
ts: now - 20 * 60_000,
|
|
117
|
-
holderIntentText: "switch the login flow to short-lived JWT tokens with refresh rotation",
|
|
118
|
-
});
|
|
119
|
-
await coord.flushAll();
|
|
120
|
-
|
|
121
|
-
// Record architectural decisions & tasks
|
|
122
|
-
central.configure(falkor);
|
|
123
|
-
const decisions = [
|
|
124
|
-
central.toRow({
|
|
125
|
-
event_id: 101,
|
|
126
|
-
kind: "decision",
|
|
127
|
-
decision_id: "jwt-refresh-rotation",
|
|
128
|
-
content: "Use 15-minute stateless JWT access tokens paired with single-use rotating refresh tokens in src/auth.ts and src/session.ts.",
|
|
129
|
-
status: "accepted",
|
|
130
|
-
user: "alice",
|
|
131
|
-
agent_label: "Claude Code",
|
|
132
|
-
files: ["src/auth.ts", "src/session.ts", "src/middleware.ts"],
|
|
133
|
-
ts: new Date(now - 21 * 60_000).toISOString(),
|
|
134
|
-
}),
|
|
135
|
-
central.toRow({
|
|
136
|
-
event_id: 102,
|
|
137
|
-
kind: "decision",
|
|
138
|
-
decision_id: "auth-rate-limit",
|
|
139
|
-
content: "Enforce 10 req/min sliding-window rate limit on /api/token/refresh and login routes.",
|
|
140
|
-
status: "accepted",
|
|
141
|
-
user: "alice",
|
|
142
|
-
agent_label: "Codex",
|
|
143
|
-
files: ["src/auth.ts", "src/routes.ts"],
|
|
144
|
-
ts: new Date(now - 16 * 60_000).toISOString(),
|
|
145
|
-
}),
|
|
146
|
-
].filter(Boolean);
|
|
147
|
-
await central.writeRows(targetId, decisions);
|
|
148
|
-
|
|
149
|
-
const summary = await analytics.run(targetId, { full: true });
|
|
150
|
-
console.log(`Seeded FalkorDB demo graph for project "${targetId}":`, JSON.stringify(summary));
|
|
151
|
-
await client.close();
|
|
20
|
+
const { targetId, summary } = await seedDemoGraph(falkor, baseId, { rawTarget });
|
|
21
|
+
console.log(`Seeded isolated FalkorDB demo graph "${targetId}" (for workspace "${baseId}"):`, JSON.stringify(summary));
|
|
22
|
+
await falkor.state.client.close();
|
|
23
|
+
process.exit(0);
|
|
152
24
|
}
|
|
153
25
|
|
|
154
26
|
main().catch((err) => {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,93595,c=>{c.v(s=>Promise.all(["static/chunks/25rvg4bnew99f.css","static/chunks/3vq9c4hivvgn_.js"].map(s=>c.l(s))).then(()=>s(93858)))}]);
|