logseq-graph-living-atlas 0.1.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.
Files changed (41) hide show
  1. package/.env.example +29 -0
  2. package/CHANGELOG.md +38 -0
  3. package/CODE_OF_CONDUCT.md +33 -0
  4. package/CONTRIBUTING.md +116 -0
  5. package/GOVERNANCE.md +40 -0
  6. package/LICENSE +21 -0
  7. package/MAINTAINERS.md +34 -0
  8. package/README.md +370 -0
  9. package/ROADMAP.md +38 -0
  10. package/SECURITY.md +43 -0
  11. package/SUPPORT.md +31 -0
  12. package/dist/assets/AtlasCanvas-p-Pb_C3p.js +172 -0
  13. package/dist/assets/index-Cb0dgkF5.css +1 -0
  14. package/dist/assets/index-D-LUf-q7.js +12 -0
  15. package/dist/assets/three-DQCgX68K.js +3947 -0
  16. package/dist/index.html +13 -0
  17. package/docs/ADAPTERS.md +48 -0
  18. package/docs/API.md +145 -0
  19. package/docs/ARCHITECTURE.md +93 -0
  20. package/docs/CONCEPTS.md +62 -0
  21. package/docs/MCP.md +74 -0
  22. package/docs/RELEASE.md +65 -0
  23. package/docs/REPO_GUIDE.md +92 -0
  24. package/docs/TROUBLESHOOTING.md +138 -0
  25. package/docs/assets/living-atlas-demo.png +0 -0
  26. package/docs/assets/living-atlas-pathfinder.png +0 -0
  27. package/docs/assets/living-atlas-radar.png +0 -0
  28. package/docs/assets/living-atlas-source-detail.png +0 -0
  29. package/package.json +102 -0
  30. package/server/brain-service.mjs +201 -0
  31. package/server/contracts.mjs +346 -0
  32. package/server/fixture/create-fixture-graph.mjs +115 -0
  33. package/server/graph/pathfinding.mjs +155 -0
  34. package/server/graph/quality.mjs +11 -0
  35. package/server/graph/utils.mjs +25 -0
  36. package/server/graph-index.mjs +920 -0
  37. package/server/logseq/parser.mjs +121 -0
  38. package/server/logseq/source-adapter.mjs +147 -0
  39. package/server/redaction.mjs +89 -0
  40. package/server/service.mjs +777 -0
  41. package/server/source-adapter-contract.d.ts +46 -0
@@ -0,0 +1,138 @@
1
+ # Troubleshooting
2
+
3
+ ## `npx logseq-graph-living-atlas` Is Not Found
4
+
5
+ Confirm npm can see the package:
6
+
7
+ ```bash
8
+ npm view logseq-graph-living-atlas version
9
+ ```
10
+
11
+ If the package is not available yet, run from source:
12
+
13
+ ```bash
14
+ git clone https://github.com/johnschieferleuhlenbrock/logseq-graph-living-atlas.git
15
+ cd logseq-graph-living-atlas
16
+ npm install
17
+ npm run demo
18
+ ```
19
+
20
+ ## Missing `pages/`
21
+
22
+ `--root` must point at the Logseq graph folder, not the `pages/` folder:
23
+
24
+ ```text
25
+ my-logseq-graph/
26
+ pages/
27
+ journals/
28
+ ```
29
+
30
+ Check it with:
31
+
32
+ ```bash
33
+ ls /absolute/path/to/my-logseq-graph/pages
34
+ ```
35
+
36
+ ## Port Already In Use
37
+
38
+ Use another local port:
39
+
40
+ ```bash
41
+ living-atlas --root /absolute/path/to/logseq --port 8790
42
+ ```
43
+
44
+ ## `401` From `/api/*`
45
+
46
+ Real graph reads are token-protected by default. Open the `#token=...` URL printed by the service, or provide your own:
47
+
48
+ ```bash
49
+ LIVING_ATLAS_TOKEN=<random-local-token> living-atlas --root /absolute/path/to/logseq
50
+ ```
51
+
52
+ PowerShell:
53
+
54
+ ```powershell
55
+ $env:LIVING_ATLAS_TOKEN = "<random-local-token>"
56
+ living-atlas --root "D:\LogseqGraph"
57
+ ```
58
+
59
+ For fixture-only local experiments, you can opt out:
60
+
61
+ ```bash
62
+ living-atlas --root /path/to/public-fixture --allow-unauthenticated-read
63
+ ```
64
+
65
+ ## Split Dev CORS
66
+
67
+ When running Vite and the API separately, allow the local Vite origin and open the token URL:
68
+
69
+ ```bash
70
+ LIVING_ATLAS_TOKEN=<random-local-token> npm run dev:api -- --root /absolute/path/to/logseq --allowed-origin http://127.0.0.1:5177
71
+ npm run dev
72
+ ```
73
+
74
+ Open `http://127.0.0.1:5177/#token=<random-local-token>`.
75
+
76
+ PowerShell:
77
+
78
+ ```powershell
79
+ $env:LIVING_ATLAS_TOKEN = "<random-local-token>"
80
+ npm run dev:api -- --root "D:\LogseqGraph" --allowed-origin http://127.0.0.1:5177
81
+ npm run dev
82
+ ```
83
+
84
+ ## MCP Changes Do Not Appear In Atlas
85
+
86
+ Confirm both processes point at the same graph root:
87
+
88
+ ```bash
89
+ living-atlas --root /absolute/path/to/logseq
90
+ npx logseq-graph-mcp --root /absolute/path/to/logseq --readonly
91
+ ```
92
+
93
+ Atlas does not subscribe to the MCP protocol directly. It sees MCP writes as filesystem changes, so either keep Atlas running with `--watch` or call `POST /api/reindex` after a guarded MCP write. If you use a custom cache path, keep the cache outside the graph folder.
94
+
95
+ Run the public compatibility smoke when debugging install or path issues:
96
+
97
+ ```bash
98
+ npm run smoke:mcp
99
+ ```
100
+
101
+ ## Blank Or Unsupported WebGL
102
+
103
+ Living Atlas needs WebGL for the cinematic field. If WebGL is unavailable, the app should show the fallback graph-inspection panel with totals, top regions, and high-signal pages.
104
+
105
+ Try another browser, disable low-power/restricted graphics settings, or run the fixture smoke path:
106
+
107
+ ```bash
108
+ npm run demo
109
+ ```
110
+
111
+ ## UI Smoke Test Browser Missing
112
+
113
+ Install the Playwright browser once:
114
+
115
+ ```bash
116
+ npx playwright install chromium
117
+ ```
118
+
119
+ On Linux CI-like systems:
120
+
121
+ ```bash
122
+ npx playwright install --with-deps chromium
123
+ ```
124
+
125
+ ## Safe Bug Reports
126
+
127
+ Do not attach real graph files, private screenshots, cache files, token URLs, or terminal output containing local paths. Reproduce with the public fixture whenever possible:
128
+
129
+ ```bash
130
+ npm run demo
131
+ npm run test:ui
132
+ ```
133
+
134
+ For API-shaped bug reports from a real graph, request redacted JSON:
135
+
136
+ ```bash
137
+ curl -H "Authorization: Bearer <token>" "http://127.0.0.1:8787/api/snapshot?redact=1"
138
+ ```
package/package.json ADDED
@@ -0,0 +1,102 @@
1
+ {
2
+ "name": "logseq-graph-living-atlas",
3
+ "version": "0.1.0",
4
+ "description": "Local-only cinematic 3D atlas and read-only index service for Logseq markdown graphs.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "engines": {
8
+ "node": ">=20.19.0"
9
+ },
10
+ "packageManager": "npm@10.8.2",
11
+ "keywords": [
12
+ "logseq",
13
+ "knowledge-graph",
14
+ "threejs",
15
+ "visualization",
16
+ "local-first"
17
+ ],
18
+ "homepage": "https://github.com/johnschieferleuhlenbrock/logseq-graph-living-atlas#readme",
19
+ "bugs": {
20
+ "url": "https://github.com/johnschieferleuhlenbrock/logseq-graph-living-atlas/issues"
21
+ },
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "git+https://github.com/johnschieferleuhlenbrock/logseq-graph-living-atlas.git"
25
+ },
26
+ "publishConfig": {
27
+ "access": "public"
28
+ },
29
+ "bin": {
30
+ "living-atlas": "server/brain-service.mjs",
31
+ "logseq-graph-living-atlas": "server/brain-service.mjs"
32
+ },
33
+ "files": [
34
+ "dist/",
35
+ "server/",
36
+ "docs/API.md",
37
+ "docs/ADAPTERS.md",
38
+ "docs/ARCHITECTURE.md",
39
+ "docs/CONCEPTS.md",
40
+ "docs/MCP.md",
41
+ "docs/RELEASE.md",
42
+ "docs/REPO_GUIDE.md",
43
+ "docs/TROUBLESHOOTING.md",
44
+ "docs/assets/living-atlas-demo.png",
45
+ "docs/assets/living-atlas-pathfinder.png",
46
+ "docs/assets/living-atlas-radar.png",
47
+ "docs/assets/living-atlas-source-detail.png",
48
+ "README.md",
49
+ "CONTRIBUTING.md",
50
+ "CODE_OF_CONDUCT.md",
51
+ "CHANGELOG.md",
52
+ "SECURITY.md",
53
+ "SUPPORT.md",
54
+ "MAINTAINERS.md",
55
+ "GOVERNANCE.md",
56
+ "ROADMAP.md",
57
+ ".env.example",
58
+ "LICENSE"
59
+ ],
60
+ "scripts": {
61
+ "dev": "vite --host 127.0.0.1 --port 5177",
62
+ "dev:api": "node server/brain-service.mjs --watch --no-static --port 8787",
63
+ "build": "vite build",
64
+ "start": "npm run demo",
65
+ "serve": "node server/brain-service.mjs --watch --static dist --port 8787",
66
+ "serve:env": "npm run build && node --env-file=.env.local server/brain-service.mjs --watch --static dist --port 8787",
67
+ "demo": "npm run build && node scripts/demo.mjs",
68
+ "dev:fixture": "node scripts/dev-fixture.mjs",
69
+ "capture:demo": "npm run build && node scripts/capture-demo.mjs",
70
+ "typecheck": "tsc --noEmit && tsc -p tsconfig.test.json --noEmit",
71
+ "check:runtime": "node scripts/runtime-check.mjs",
72
+ "test": "node --test tests/*.test.mjs && npm run test:frontend && npm run typecheck && npm run check:runtime && npm run build",
73
+ "test:frontend": "tsx --test tests/frontend/*.test.ts",
74
+ "test:ui": "npm run build && node tests/ui-smoke.mjs",
75
+ "test:ui:scale": "npm run build && node tests/ui-scale-smoke.mjs",
76
+ "eval": "node tests/scale-eval.mjs && node tests/service-scale-eval.mjs",
77
+ "eval:service:100k": "node tests/service-scale-eval.mjs --size=100000 --watch",
78
+ "smoke:mcp": "node scripts/mcp-compat-smoke.mjs",
79
+ "smoke:package": "node scripts/package-smoke.mjs",
80
+ "check:public": "node scripts/public-readiness.mjs",
81
+ "check:release": "node scripts/release-readiness.mjs",
82
+ "clean": "node scripts/clean.mjs",
83
+ "prepack": "npm run build",
84
+ "prepublishOnly": "npm run check:release && npm run validate && npm run smoke:package",
85
+ "validate": "npm test && npm run eval && npm run test:ui && npm run test:ui:scale && npm run check:public"
86
+ },
87
+ "devDependencies": {
88
+ "@types/node": "^24.10.1",
89
+ "@types/react": "^19.2.7",
90
+ "@types/react-dom": "^19.2.3",
91
+ "@types/three": "^0.181.0",
92
+ "@vitejs/plugin-react": "^5.0.4",
93
+ "playwright": "^1.60.0",
94
+ "pngjs": "^7.0.0",
95
+ "react": "^19.2.0",
96
+ "react-dom": "^19.2.0",
97
+ "three": "^0.181.2",
98
+ "tsx": "^4.22.4",
99
+ "typescript": "^5.9.3",
100
+ "vite": "^7.2.4"
101
+ }
102
+ }
@@ -0,0 +1,201 @@
1
+ #!/usr/bin/env node
2
+ import crypto from "node:crypto";
3
+ import fs from "node:fs";
4
+ import os from "node:os";
5
+ import path from "node:path";
6
+ import { fileURLToPath } from "node:url";
7
+ import { DEFAULT_LOGSEQ_ROOT } from "./logseq/source-adapter.mjs";
8
+ import { createBrainService } from "./service.mjs";
9
+ import { createFixtureGraph } from "./fixture/create-fixture-graph.mjs";
10
+
11
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
12
+ const packageJson = JSON.parse(fs.readFileSync(path.resolve(__dirname, "..", "package.json"), "utf8"));
13
+
14
+ if (process.argv[1] && fs.realpathSync(process.argv[1]) === fileURLToPath(import.meta.url)) {
15
+ await main(process.argv.slice(2));
16
+ }
17
+
18
+ export async function main(argv = []) {
19
+ const args = parseArgs(argv);
20
+ if (args.help) {
21
+ printHelp();
22
+ return;
23
+ }
24
+ if (args.version) {
25
+ console.log(packageJson.version);
26
+ return;
27
+ }
28
+
29
+ const port = Number(args.port || process.env.LIVING_ATLAS_PORT || process.env.BRAIN_ATLAS_PORT || 8787);
30
+ const demoMode = Boolean(args.demo);
31
+ const rootInput = demoMode
32
+ ? createDemoGraphRoot()
33
+ : args.root || process.env.LOGSEQ_ROOT || DEFAULT_LOGSEQ_ROOT;
34
+ if (!rootInput) {
35
+ console.error("[living-atlas] LOGSEQ_ROOT or --root is required. Point it at a Logseq graph folder containing pages/.");
36
+ console.error("[living-atlas] Example: npx logseq-graph-living-atlas --root /path/to/logseq");
37
+ console.error("[living-atlas] Or try a public fixture: npx logseq-graph-living-atlas --demo");
38
+ console.error("[living-atlas] Run living-atlas --help for options.");
39
+ process.exitCode = 1;
40
+ return;
41
+ }
42
+
43
+ const root = path.resolve(rootInput);
44
+ const packagedStaticDir = path.resolve(__dirname, "..", "dist");
45
+ const staticDir = args["no-static"]
46
+ ? null
47
+ : args.static
48
+ ? path.resolve(__dirname, "..", args.static)
49
+ : fs.existsSync(path.join(packagedStaticDir, "index.html"))
50
+ ? packagedStaticDir
51
+ : null;
52
+ const cachePath = path.resolve(args.cache || process.env.LIVING_ATLAS_CACHE || process.env.BRAIN_ATLAS_CACHE || path.join(defaultCacheDirectory(), "snapshot.json"));
53
+ const debugPaths = Boolean(args["debug-paths"] || process.env.LIVING_ATLAS_DEBUG_PATHS === "1" || process.env.BRAIN_ATLAS_DEBUG_PATHS === "1");
54
+ const allowUnauthenticatedRead = Boolean(args["allow-unauthenticated-read"] || process.env.LIVING_ATLAS_ALLOW_UNAUTHENTICATED_READ === "1");
55
+ const configuredToken = args.token || process.env.LIVING_ATLAS_TOKEN || process.env.BRAIN_ATLAS_TOKEN || "";
56
+ const requireToken = Boolean(
57
+ args["require-token"] ||
58
+ process.env.LIVING_ATLAS_REQUIRE_TOKEN === "1" ||
59
+ (!demoMode && !allowUnauthenticatedRead)
60
+ );
61
+ if (requireToken && configuredToken && configuredToken.length < 16) {
62
+ console.error("[living-atlas] LIVING_ATLAS_TOKEN / --token must be at least 16 characters when read-token mode is enabled.");
63
+ process.exitCode = 1;
64
+ return;
65
+ }
66
+ const localToken = requireToken ? configuredToken || crypto.randomBytes(18).toString("base64url") : configuredToken;
67
+
68
+ let service;
69
+ try {
70
+ service = createBrainService({
71
+ root,
72
+ cachePath,
73
+ staticDir,
74
+ port,
75
+ watch: Boolean(args.watch),
76
+ debugPaths,
77
+ token: localToken,
78
+ requireToken,
79
+ allowUnauthenticatedRead: demoMode || allowUnauthenticatedRead,
80
+ allowUnauthenticatedReindex: Boolean(args["allow-unauthenticated-reindex"] || process.env.LIVING_ATLAS_ALLOW_UNAUTHENTICATED_REINDEX === "1"),
81
+ allowedOrigins: args["allowed-origin"] || process.env.LIVING_ATLAS_ALLOWED_ORIGINS || process.env.BRAIN_ATLAS_ALLOWED_ORIGINS || ""
82
+ });
83
+ const started = await service.listen();
84
+ console.log(`[living-atlas] root = ${debugPaths ? root : "configured Logseq graph"}`);
85
+ if (demoMode) console.log("[living-atlas] demo = public fixture graph");
86
+ console.log(`[living-atlas] snapshot = ${started.snapshot.totals.nodes} nodes / ${started.snapshot.totals.links} links`);
87
+ console.log(`[living-atlas] api = http://${started.bindHost}:${started.port}/api/snapshot`);
88
+ if (requireToken) {
89
+ const appPort = staticDir ? started.port : 5177;
90
+ console.log(`[living-atlas] token-protected reads = enabled`);
91
+ if (!configuredToken) console.log(`[living-atlas] session token = ${localToken}`);
92
+ console.log(`[living-atlas] app token URL = http://${started.bindHost}:${appPort}/#token=${encodeURIComponent(localToken)}`);
93
+ }
94
+ if (staticDir) console.log(`[living-atlas] app = http://${started.bindHost}:${started.port}/`);
95
+ } catch (error) {
96
+ failStartup(error, debugPaths);
97
+ return;
98
+ }
99
+
100
+ for (const signal of ["SIGINT", "SIGTERM"]) {
101
+ process.once(signal, async () => {
102
+ await service.close();
103
+ process.exit(0);
104
+ });
105
+ }
106
+ }
107
+
108
+ export function defaultCacheDirectory() {
109
+ if (process.env.XDG_CACHE_HOME) return path.join(process.env.XDG_CACHE_HOME, "logseq-graph-living-atlas");
110
+ if (process.platform === "darwin") return path.join(os.homedir(), "Library", "Caches", "logseq-graph-living-atlas");
111
+ if (process.platform === "win32") {
112
+ return path.join(process.env.LOCALAPPDATA || path.join(os.homedir(), "AppData", "Local"), "logseq-graph-living-atlas");
113
+ }
114
+ return path.join(os.homedir(), ".cache", "logseq-graph-living-atlas");
115
+ }
116
+
117
+ function createDemoGraphRoot() {
118
+ const cacheDirectory = defaultCacheDirectory();
119
+ fs.mkdirSync(cacheDirectory, { recursive: true });
120
+ return createFixtureGraph({ out: fs.mkdtempSync(path.join(cacheDirectory, "demo-logseq-graph-")) });
121
+ }
122
+
123
+ function failStartup(error, debugPaths) {
124
+ const message = String(error?.message || error || "Startup failed");
125
+ console.error(`[living-atlas] ${message}`);
126
+ console.error("[living-atlas] Expected --root to point at a Logseq graph folder containing pages/.");
127
+ console.error("[living-atlas] Try: living-atlas --root /path/to/logseq");
128
+ console.error("[living-atlas] Or run the public fixture: living-atlas --demo");
129
+ if (debugPaths) console.error(error?.stack || error);
130
+ process.exitCode = 1;
131
+ }
132
+
133
+ function parseArgs(argv) {
134
+ const parsed = {};
135
+ const valueFlags = new Set(["root", "cache", "port", "static", "token", "allowed-origin"]);
136
+ const booleanFlags = new Set([
137
+ "watch",
138
+ "help",
139
+ "version",
140
+ "debug-paths",
141
+ "no-static",
142
+ "demo",
143
+ "require-token",
144
+ "allow-unauthenticated-read",
145
+ "allow-unauthenticated-reindex"
146
+ ]);
147
+ for (let index = 0; index < argv.length; index += 1) {
148
+ const arg = argv[index];
149
+ if (!arg.startsWith("--")) continue;
150
+ const inline = arg.match(/^--([^=]+)=(.*)$/);
151
+ if (inline) {
152
+ parsed[inline[1]] = inline[2];
153
+ continue;
154
+ }
155
+ const key = arg.slice(2);
156
+ if (booleanFlags.has(key)) {
157
+ parsed[key] = true;
158
+ continue;
159
+ }
160
+ if (valueFlags.has(key)) {
161
+ parsed[key] = argv[index + 1];
162
+ index += 1;
163
+ }
164
+ }
165
+ return parsed;
166
+ }
167
+
168
+ function printHelp() {
169
+ console.log(`Living Atlas ${packageJson.version}
170
+
171
+ Usage:
172
+ living-atlas --root /path/to/logseq [options]
173
+ npx logseq-graph-living-atlas --root /path/to/logseq
174
+ npx logseq-graph-living-atlas --demo
175
+
176
+ Options:
177
+ --root <path> Logseq graph folder containing pages/. journals/ is optional.
178
+ --demo Run a public fixture graph without needing Logseq data.
179
+ --port <number> Local port. Defaults to 8787.
180
+ --cache <path> Snapshot cache path outside the graph.
181
+ --static <path> Static UI directory. Defaults to packaged dist/ when present.
182
+ --no-static Serve API only.
183
+ --watch Watch pages/ and journals/ for markdown changes.
184
+ --token <value> Local API token. Required for reads when token mode is enabled.
185
+ --require-token Require the token for every /api/* read and write route.
186
+ --allow-unauthenticated-read
187
+ Allow local API reads without a token for trusted development.
188
+ --allow-unauthenticated-reindex
189
+ Allow POST /api/reindex without a token for local development.
190
+ --allowed-origin <origin> Add a local browser origin for split dev CORS.
191
+ --debug-paths Include absolute diagnostic paths and detailed errors.
192
+ --version Print version.
193
+ --help Print this help.
194
+
195
+ Examples:
196
+ npx logseq-graph-living-atlas --demo
197
+ npx logseq-graph-living-atlas --root ~/Documents/Logseq
198
+ living-atlas --root ~/Documents/Logseq --port 8787 --watch
199
+ LIVING_ATLAS_TOKEN=<random-local-token> LIVING_ATLAS_ALLOWED_ORIGINS=http://127.0.0.1:5177 npm run dev:api -- --root ~/Documents/Logseq
200
+ `);
201
+ }