logseq-matryca-parser 1.2.2__tar.gz → 1.3.0__tar.gz
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.
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/CHANGELOG.md +14 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/CONTRIBUTING.md +1 -1
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/PKG-INFO +46 -9
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/README.md +45 -8
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/SECURITY.md +1 -1
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/ARCHITECTURE.md +16 -8
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/CODEQL.md +1 -1
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/logseq_ast_primer.md +1 -1
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/roadmaps/ROADMAP_INCREMENTAL_WATCHER.md +2 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/roadmaps/ROADMAP_UUID_AND_GRAPH_SUPERPOWERS.md +2 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/examples/run_demo.py +3 -2
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/legacy/local_digestor.py +6 -9
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/pyproject.toml +22 -1
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/src/logseq_matryca_parser/__init__.py +26 -5
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/src/logseq_matryca_parser/forge.py +1 -4
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/src/logseq_matryca_parser/graph.py +100 -18
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/src/logseq_matryca_parser/kinetic.py +104 -57
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/src/logseq_matryca_parser/lens.py +9 -6
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/src/logseq_matryca_parser/logos_core.py +5 -5
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/src/logseq_matryca_parser/logos_parser.py +37 -8
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/src/logseq_matryca_parser/logseq_paths.py +17 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/src/logseq_matryca_parser/synapse.py +134 -45
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/tests/test_agent_writer.py +5 -1
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/tests/test_graph.py +65 -1
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/tests/test_kinetic.py +27 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/tests/test_lens.py +9 -1
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/tests/test_logos_parser.py +34 -9
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/tests/test_logseq_paths.py +2 -2
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/tests/test_package_version.py +17 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/tests/test_synapse.py +70 -6
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/uv.lock +96 -80
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/.cursorignore +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/.github/CODEOWNERS +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/.github/FUNDING.yml +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/.github/dependabot.yml +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/.github/workflows/ci.yml +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/.github/workflows/daily-metrics.yml +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/.github/workflows/github_release.yml +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/.github/workflows/pypi_publish.yml +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/.gitignore +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/.pre-commit-config.yaml +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/.repomixignore +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/CODE_OF_CONDUCT.md +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/LICENSE +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/Makefile +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/NOTICE +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/claude-skill-logseq-read/SKILL.md +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/claude-skill-logseq-read/scripts/parse_logseq.py +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/RELEASE_PROCESS.md +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/design-docs/ARCHITECTURE_BLUEPRINT.md +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/design-docs/CODE_SCAFFOLD.md +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/design-docs/LOGSEQ_ASSET_RESOLUTION_SPEC.md +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/design-docs/LOGSEQ_DATASCRIPT_MAPPING.md +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/design-docs/LOGSEQ_TEMPORAL_ONTOLOGY.md +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/design-docs/OFFICIAL_MLDOC_SPECS.md +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/design-docs/REFERENCE_SPEC.md +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/error_log.md +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/roadmaps/ROADMAP_AGENT_NATIVE_XRAY.md +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/roadmaps/ROADMAP_CLI_HYDRATION_AND_ENRICHMENT.md +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/roadmaps/ROADMAP_CONTEXT_SYNTHESIS_AND_SCOPING.md +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/roadmaps/ROADMAP_EMBED_EXPANSION_AND_FLUENT_QUERIES.md +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/roadmaps/ROADMAP_GRAPH_RAG_SEMANTICS.md +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/roadmaps/ROADMAP_HEADLESS_WRITER.md +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/roadmaps/ROADMAP_INLINE_SHIELD_AND_NAMESPACES.md +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/roadmaps/ROADMAP_OBSIDIAN_ADAPTER.md +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/roadmaps/ROADMAP_ROBUSTNESS_AND_SOFT_BREAKS.md +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/roadmaps/ROADMAP_TOML_FIX_AND_PYPI_DISTRIBUTION.md +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/examples/demo_logseq_journal.md +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/lib/bindings/utils.js +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/lib/tom-select/tom-select.complete.min.js +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/lib/tom-select/tom-select.css +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/lib/vis-9.1.2/vis-network.css +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/lib/vis-9.1.2/vis-network.min.js +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/metrics/history.json +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/repomix-output-parser.xml +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/scripts/debug_pre_release.py +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/scripts/extract_changelog.py +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/src/logseq_matryca_parser/.gitignore +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/src/logseq_matryca_parser/NOTICE +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/src/logseq_matryca_parser/__main__.py +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/src/logseq_matryca_parser/agent_press.py +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/src/logseq_matryca_parser/agent_writer.py +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/src/logseq_matryca_parser/exceptions.py +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/src/logseq_matryca_parser/logseq_markdown.py +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/src/logseq_matryca_parser/pyproject.toml +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/tests/test_agent_press.py +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/tests/test_forge.py +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/tests/test_logseq_markdown.py +0 -0
- {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/tests/test_pre_release_roundtrip.py +0 -0
|
@@ -7,6 +7,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.3.0] - 2026-06-19
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- **Sprint 1 architectural quick wins** — **`discover_graph_files`** moved from `kinetic.py` to `logseq_paths.py` (decouples CLI from `LogseqGraph`); KINETIC optional-dependency errors now recommend **`uv sync --extra ai|viz`**; **`lens.py`** lazy-imports NetworkX/PyVis; **SYNAPSE** exports vector-store-safe metadata via **`SynapseMetadata`** / **`build_synapse_metadata`** (`task_priority`, temporal epochs, `source_uuid`, joined `path`/`refs`); explicit **`[tool.ruff]`** config in `pyproject.toml`.
|
|
15
|
+
- **Sprint 2 runtime robustness** — **`LogseqGraphWatcher`** debounces filesystem events (~500ms) and ignores editor temp/swap files; **`StackMachineParser(strict_refs=True)`** raises **`BlockReferenceError`** for unresolved same-page `((uuid))` refs (default off); **KINETIC** adds **`@app.callback()`** with **`--verbose`** / **`--graph`**, **`rich_markup_mode="rich"`**, and shared graph-path resolution.
|
|
16
|
+
- **Sprint 3 architecture** — **`LogseqGraph`** uses **`validate_assignment=True`** (no frozen/`object.__setattr__` hack); **SYNAPSE** **`LlamaIndexVisitor`** adds **`SOURCE`**, **`NEXT`**, and **`PREVIOUS`** relationships; package root **`__init__.py`** exports **`SynapseAdapter`**, **`SessionAliasRegistry`**, **`GraphVisualizer`**, and core LOGOS symbols via explicit **`__all__`**.
|
|
17
|
+
- **Optional AI stack** — `llama-index-core` bumped to `0.14.22` via lock refresh.
|
|
18
|
+
- **Documentation** — README, ARCHITECTURE, CONTRIBUTING, SECURITY, CODEQL, AST primer, and roadmaps updated for **1.3.0** (public API, watcher debounce, `strict_refs`, LlamaIndex spatial edges, `uv` install).
|
|
19
|
+
|
|
20
|
+
### Security
|
|
21
|
+
|
|
22
|
+
- **Transitive dependency hardening** — `uv` constraints pin `aiohttp>=3.14.1` (11 Dependabot alerts); `nltk` overridden to `v3.10.0-rc1` from upstream Git until NLTK 3.10.0 ships on PyPI (GHSA-p4gq-832x-fm9v). Affects optional `[ai]` / `[all]` extras only; core install unchanged.
|
|
23
|
+
|
|
10
24
|
## [1.2.2] - 2026-06-18
|
|
11
25
|
|
|
12
26
|
### Fixed
|
|
@@ -15,7 +15,7 @@ User-facing behavior is documented in:
|
|
|
15
15
|
- [`README.md`](README.md) — overview, quickstart, and feature matrix
|
|
16
16
|
- [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) — LOGOS, SYNAPSE, `LogseqGraph`, agents, and data flow
|
|
17
17
|
- [`docs/logseq_ast_primer.md`](docs/logseq_ast_primer.md) — Logseq Spatial Markdown domain rules
|
|
18
|
-
- [`CHANGELOG.md`](CHANGELOG.md) — shipped releases (current: **1.
|
|
18
|
+
- [`CHANGELOG.md`](CHANGELOG.md) — shipped releases (current: **1.3.0**) and **Unreleased** changes (Keep a Changelog)
|
|
19
19
|
- [`docs/RELEASE_PROCESS.md`](docs/RELEASE_PROCESS.md) — version bump, tag, and PyPI publish checklist
|
|
20
20
|
- [`docs/CODEQL.md`](docs/CODEQL.md) — CodeQL default setup (no custom `codeql.yml`)
|
|
21
21
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: logseq-matryca-parser
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.0
|
|
4
4
|
Summary: The Logos Protocol: Deterministic Logseq AST parsing for Matryca.ai.
|
|
5
5
|
Project-URL: Homepage, https://github.com/MarcoPorcellato/logseq-matryca-parser
|
|
6
6
|
Project-URL: Repository, https://github.com/MarcoPorcellato/logseq-matryca-parser
|
|
@@ -53,7 +53,7 @@ Description-Content-Type: text/markdown
|
|
|
53
53
|
[](#)
|
|
54
54
|

|
|
55
55
|
|
|
56
|
-
**v1.
|
|
56
|
+
**v1.3.0** — Architecture & runtime hardening (see [CHANGELOG](CHANGELOG.md)) — **244 tests**, public API exports, watcher debounce, `strict_refs`, LlamaIndex spatial edges; SAST via GitHub CodeQL **default setup** ([`docs/CODEQL.md`](docs/CODEQL.md)).
|
|
57
57
|
|
|
58
58
|
> *Turning a forest of local plain-text files into a unified semantic powerhouse.*
|
|
59
59
|
|
|
@@ -147,6 +147,23 @@ Logseq Matryca Parser is a deterministic **Stack-Machine engine** that acts as t
|
|
|
147
147
|
|
|
148
148
|
---
|
|
149
149
|
|
|
150
|
+
## ⚡ Release highlights (v1.3.0)
|
|
151
|
+
|
|
152
|
+
Minor release — architectural quick wins, runtime robustness, and expanded public API. No breaking changes to default parser behavior.
|
|
153
|
+
|
|
154
|
+
| Area | Change |
|
|
155
|
+
| :--- | :--- |
|
|
156
|
+
| **Public API** | Root **`logseq_matryca_parser`** exports **`SynapseAdapter`**, **`SessionAliasRegistry`**, **`GraphVisualizer`**, **`discover_graph_files`**, and core LOGOS symbols via explicit **`__all__`**. |
|
|
157
|
+
| **Graph model** | **`LogseqGraph`** uses **`validate_assignment=True`** instead of frozen/`object.__setattr__` for incremental reloads. |
|
|
158
|
+
| **Live watcher** | **`start_watching()`** debounces filesystem events (~500ms) and ignores editor temp/swap files (`.swp`, `~`, `.tmp`, `.DS_Store`). |
|
|
159
|
+
| **Strict refs** | **`StackMachineParser(strict_refs=True)`** raises **`BlockReferenceError`** for unresolved same-page `((uuid))` refs (default off). |
|
|
160
|
+
| **SYNAPSE** | **`SynapseMetadata`** / **`build_synapse_metadata`** for vector-store-safe fields; **LlamaIndex** adds **`SOURCE`**, **`NEXT`**, **`PREVIOUS`** relationships. |
|
|
161
|
+
| **KINETIC CLI** | Global **`--verbose`** / **`--graph`** via **`@app.callback()`**; optional-dependency hints recommend **`uv sync --extra ai\|viz`**. |
|
|
162
|
+
| **LENS** | Lazy-imports NetworkX/PyVis so core installs stay lightweight. |
|
|
163
|
+
| **Security** | Transitive **`aiohttp`** / **`nltk`** constraints for optional **`[ai]`** extras. |
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
150
167
|
## ⚡ Release highlights (v1.2.2)
|
|
151
168
|
|
|
152
169
|
Patch release — fixes a failing CodeQL GitHub Actions workflow; **no parser or public API changes**.
|
|
@@ -236,7 +253,7 @@ matryca-parse export /path/to/logseq/graph /path/to/obsidian/vault --format obsi
|
|
|
236
253
|
> **Note:** Wikilinks currently use the **Logseq page title** (e.g. `[[Target#^…]]`). Vault files may live under namespace folders (`Projects/AI/Demo.md`). Obsidian usually resolves unique titles; aligning link text to folder paths is a possible future refinement.
|
|
237
254
|
|
|
238
255
|
### Live incremental watcher
|
|
239
|
-
`LogseqGraph` supports **surgical file invalidation** (optional dependency: `
|
|
256
|
+
`LogseqGraph` supports **surgical file invalidation** (optional dependency: `uv sync --extra watch`). `start_watching()` runs a recursive **watchdog** observer with **~500ms debounce** and ignores editor temp/swap files: on `created` / `modified` under `pages/` or `journals/`, only that file is re-parsed; stale synthetic UUIDs are purged from `_node_registry` and scrubbed from `_backlink_registry`—no full-graph cold reload.
|
|
240
257
|
|
|
241
258
|
### Fluent topological queries
|
|
242
259
|
Filter the global node registry with a **chainable** API (tags, task state, ancestry under a parent UUID):
|
|
@@ -315,12 +332,17 @@ Marker syntax (`[#A]`, `SCHEDULED: <...>`, `DEADLINE: <...>`) is stripped from `
|
|
|
315
332
|
## 🛠️ Quickstart
|
|
316
333
|
|
|
317
334
|
```bash
|
|
318
|
-
# Install from PyPI (latest: v1.
|
|
319
|
-
pip install logseq-matryca-parser
|
|
335
|
+
# Install from PyPI (latest: v1.3.0)
|
|
336
|
+
uv pip install logseq-matryca-parser
|
|
320
337
|
|
|
321
338
|
# Optional: filesystem watcher for live incremental graph updates
|
|
322
|
-
pip install 'logseq-matryca-parser[watch]'
|
|
339
|
+
uv pip install 'logseq-matryca-parser[watch]'
|
|
340
|
+
|
|
341
|
+
# Or clone and sync all extras locally
|
|
342
|
+
uv sync --all-extras
|
|
343
|
+
```
|
|
323
344
|
|
|
345
|
+
```bash
|
|
324
346
|
# 1. Visualize your local graph (LENS)
|
|
325
347
|
matryca-parse visualize /path/to/logseq/graph my-map.html
|
|
326
348
|
|
|
@@ -332,13 +354,23 @@ matryca-parse export /path/to/logseq/graph output --format langchain-enriched
|
|
|
332
354
|
|
|
333
355
|
# 4. Obsidian vault (YAML frontmatter + ^ block ids)
|
|
334
356
|
matryca-parse export /path/to/logseq/graph output --format obsidian
|
|
357
|
+
|
|
358
|
+
# Global options (all subcommands): --verbose, --graph /path/to/vault
|
|
359
|
+
matryca-parse --graph /path/to/logseq/graph --verbose export output --format json
|
|
335
360
|
```
|
|
336
361
|
|
|
337
362
|
### Python API
|
|
363
|
+
|
|
364
|
+
Prefer the package root for stable imports (see **`__all__`** in **`logseq_matryca_parser`**):
|
|
365
|
+
|
|
338
366
|
```python
|
|
339
|
-
from logseq_matryca_parser
|
|
340
|
-
|
|
341
|
-
|
|
367
|
+
from logseq_matryca_parser import (
|
|
368
|
+
LogseqGraph,
|
|
369
|
+
LogosParser,
|
|
370
|
+
SynapseAdapter,
|
|
371
|
+
SessionAliasRegistry,
|
|
372
|
+
discover_graph_files,
|
|
373
|
+
)
|
|
342
374
|
|
|
343
375
|
# Parse a single page to AST (YAML or native frontmatter; utf-8-sig BOM-safe)
|
|
344
376
|
page = LogosParser().parse_page_file("page.md")
|
|
@@ -352,6 +384,11 @@ effective = graph.get_effective_properties(page_obj.root_nodes[0].uuid)
|
|
|
352
384
|
|
|
353
385
|
# Export to LangChain with lineage metadata
|
|
354
386
|
docs = SynapseAdapter.to_langchain_documents(page.root_nodes, source_name=page.title)
|
|
387
|
+
|
|
388
|
+
# Optional strict same-page block-ref validation at parse time
|
|
389
|
+
from logseq_matryca_parser import StackMachineParser
|
|
390
|
+
|
|
391
|
+
strict_page = StackMachineParser(strict_refs=True).parse_page_file("page.md")
|
|
355
392
|
```
|
|
356
393
|
|
|
357
394
|
### 🤖 Agentic Write Access (Append-Only)
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
[](#)
|
|
13
13
|

|
|
14
14
|
|
|
15
|
-
**v1.
|
|
15
|
+
**v1.3.0** — Architecture & runtime hardening (see [CHANGELOG](CHANGELOG.md)) — **244 tests**, public API exports, watcher debounce, `strict_refs`, LlamaIndex spatial edges; SAST via GitHub CodeQL **default setup** ([`docs/CODEQL.md`](docs/CODEQL.md)).
|
|
16
16
|
|
|
17
17
|
> *Turning a forest of local plain-text files into a unified semantic powerhouse.*
|
|
18
18
|
|
|
@@ -106,6 +106,23 @@ Logseq Matryca Parser is a deterministic **Stack-Machine engine** that acts as t
|
|
|
106
106
|
|
|
107
107
|
---
|
|
108
108
|
|
|
109
|
+
## ⚡ Release highlights (v1.3.0)
|
|
110
|
+
|
|
111
|
+
Minor release — architectural quick wins, runtime robustness, and expanded public API. No breaking changes to default parser behavior.
|
|
112
|
+
|
|
113
|
+
| Area | Change |
|
|
114
|
+
| :--- | :--- |
|
|
115
|
+
| **Public API** | Root **`logseq_matryca_parser`** exports **`SynapseAdapter`**, **`SessionAliasRegistry`**, **`GraphVisualizer`**, **`discover_graph_files`**, and core LOGOS symbols via explicit **`__all__`**. |
|
|
116
|
+
| **Graph model** | **`LogseqGraph`** uses **`validate_assignment=True`** instead of frozen/`object.__setattr__` for incremental reloads. |
|
|
117
|
+
| **Live watcher** | **`start_watching()`** debounces filesystem events (~500ms) and ignores editor temp/swap files (`.swp`, `~`, `.tmp`, `.DS_Store`). |
|
|
118
|
+
| **Strict refs** | **`StackMachineParser(strict_refs=True)`** raises **`BlockReferenceError`** for unresolved same-page `((uuid))` refs (default off). |
|
|
119
|
+
| **SYNAPSE** | **`SynapseMetadata`** / **`build_synapse_metadata`** for vector-store-safe fields; **LlamaIndex** adds **`SOURCE`**, **`NEXT`**, **`PREVIOUS`** relationships. |
|
|
120
|
+
| **KINETIC CLI** | Global **`--verbose`** / **`--graph`** via **`@app.callback()`**; optional-dependency hints recommend **`uv sync --extra ai\|viz`**. |
|
|
121
|
+
| **LENS** | Lazy-imports NetworkX/PyVis so core installs stay lightweight. |
|
|
122
|
+
| **Security** | Transitive **`aiohttp`** / **`nltk`** constraints for optional **`[ai]`** extras. |
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
109
126
|
## ⚡ Release highlights (v1.2.2)
|
|
110
127
|
|
|
111
128
|
Patch release — fixes a failing CodeQL GitHub Actions workflow; **no parser or public API changes**.
|
|
@@ -195,7 +212,7 @@ matryca-parse export /path/to/logseq/graph /path/to/obsidian/vault --format obsi
|
|
|
195
212
|
> **Note:** Wikilinks currently use the **Logseq page title** (e.g. `[[Target#^…]]`). Vault files may live under namespace folders (`Projects/AI/Demo.md`). Obsidian usually resolves unique titles; aligning link text to folder paths is a possible future refinement.
|
|
196
213
|
|
|
197
214
|
### Live incremental watcher
|
|
198
|
-
`LogseqGraph` supports **surgical file invalidation** (optional dependency: `
|
|
215
|
+
`LogseqGraph` supports **surgical file invalidation** (optional dependency: `uv sync --extra watch`). `start_watching()` runs a recursive **watchdog** observer with **~500ms debounce** and ignores editor temp/swap files: on `created` / `modified` under `pages/` or `journals/`, only that file is re-parsed; stale synthetic UUIDs are purged from `_node_registry` and scrubbed from `_backlink_registry`—no full-graph cold reload.
|
|
199
216
|
|
|
200
217
|
### Fluent topological queries
|
|
201
218
|
Filter the global node registry with a **chainable** API (tags, task state, ancestry under a parent UUID):
|
|
@@ -274,12 +291,17 @@ Marker syntax (`[#A]`, `SCHEDULED: <...>`, `DEADLINE: <...>`) is stripped from `
|
|
|
274
291
|
## 🛠️ Quickstart
|
|
275
292
|
|
|
276
293
|
```bash
|
|
277
|
-
# Install from PyPI (latest: v1.
|
|
278
|
-
pip install logseq-matryca-parser
|
|
294
|
+
# Install from PyPI (latest: v1.3.0)
|
|
295
|
+
uv pip install logseq-matryca-parser
|
|
279
296
|
|
|
280
297
|
# Optional: filesystem watcher for live incremental graph updates
|
|
281
|
-
pip install 'logseq-matryca-parser[watch]'
|
|
298
|
+
uv pip install 'logseq-matryca-parser[watch]'
|
|
299
|
+
|
|
300
|
+
# Or clone and sync all extras locally
|
|
301
|
+
uv sync --all-extras
|
|
302
|
+
```
|
|
282
303
|
|
|
304
|
+
```bash
|
|
283
305
|
# 1. Visualize your local graph (LENS)
|
|
284
306
|
matryca-parse visualize /path/to/logseq/graph my-map.html
|
|
285
307
|
|
|
@@ -291,13 +313,23 @@ matryca-parse export /path/to/logseq/graph output --format langchain-enriched
|
|
|
291
313
|
|
|
292
314
|
# 4. Obsidian vault (YAML frontmatter + ^ block ids)
|
|
293
315
|
matryca-parse export /path/to/logseq/graph output --format obsidian
|
|
316
|
+
|
|
317
|
+
# Global options (all subcommands): --verbose, --graph /path/to/vault
|
|
318
|
+
matryca-parse --graph /path/to/logseq/graph --verbose export output --format json
|
|
294
319
|
```
|
|
295
320
|
|
|
296
321
|
### Python API
|
|
322
|
+
|
|
323
|
+
Prefer the package root for stable imports (see **`__all__`** in **`logseq_matryca_parser`**):
|
|
324
|
+
|
|
297
325
|
```python
|
|
298
|
-
from logseq_matryca_parser
|
|
299
|
-
|
|
300
|
-
|
|
326
|
+
from logseq_matryca_parser import (
|
|
327
|
+
LogseqGraph,
|
|
328
|
+
LogosParser,
|
|
329
|
+
SynapseAdapter,
|
|
330
|
+
SessionAliasRegistry,
|
|
331
|
+
discover_graph_files,
|
|
332
|
+
)
|
|
301
333
|
|
|
302
334
|
# Parse a single page to AST (YAML or native frontmatter; utf-8-sig BOM-safe)
|
|
303
335
|
page = LogosParser().parse_page_file("page.md")
|
|
@@ -311,6 +343,11 @@ effective = graph.get_effective_properties(page_obj.root_nodes[0].uuid)
|
|
|
311
343
|
|
|
312
344
|
# Export to LangChain with lineage metadata
|
|
313
345
|
docs = SynapseAdapter.to_langchain_documents(page.root_nodes, source_name=page.title)
|
|
346
|
+
|
|
347
|
+
# Optional strict same-page block-ref validation at parse time
|
|
348
|
+
from logseq_matryca_parser import StackMachineParser
|
|
349
|
+
|
|
350
|
+
strict_page = StackMachineParser(strict_refs=True).parse_page_file("page.md")
|
|
314
351
|
```
|
|
315
352
|
|
|
316
353
|
### 🤖 Agentic Write Access (Append-Only)
|
|
@@ -6,7 +6,7 @@ Security fixes are provided **only for the latest released version** on [PyPI](h
|
|
|
6
6
|
|
|
7
7
|
| Version | Supported |
|
|
8
8
|
| ------- | --------- |
|
|
9
|
-
| **1.
|
|
9
|
+
| **1.3.0** (latest) | Yes |
|
|
10
10
|
| Older releases | No |
|
|
11
11
|
|
|
12
12
|
We recommend always running the current release and upgrading promptly when a security advisory is published.
|
|
@@ -82,7 +82,7 @@ title Logseq Matryca Parser — C4 Level 2 (Containers)
|
|
|
82
82
|
Person(knowledgeWorker, "Knowledge Worker", "Local operator of a sovereign Logseq graph.")
|
|
83
83
|
|
|
84
84
|
System_Boundary(matrycaEcosystem, "Matryca.ai Ecosystem") {
|
|
85
|
-
Container(kinetic, "KINETIC", "Typer / Rich CLI", "CLI — export (json, markdown, langchain, langchain-enriched, obsidian), visualize, demo, graph scans, `agent-read` / `agent-write` (X-Ray + headless splice), weekly append (`append`).")
|
|
85
|
+
Container(kinetic, "KINETIC", "Typer / Rich CLI", "CLI — global `--verbose` / `--graph` callback; export (json, markdown, langchain, langchain-enriched, obsidian), visualize, demo, graph scans, `agent-read` / `agent-write` (X-Ray + headless splice), weekly append (`append`).")
|
|
86
86
|
Container(logos, "LOGOS", "Python / Pydantic", "Stack-Machine AST engine — LogseqPage and LogseqNode models.")
|
|
87
87
|
Container(synapse, "SYNAPSE", "LangChain / LlamaIndex", "Framework-native exporters with parent-child metadata.")
|
|
88
88
|
Container(lens, "LENS", "NetworkX / PyVis", "Reference-topology visualization to interactive HTML.")
|
|
@@ -258,7 +258,9 @@ classDiagram
|
|
|
258
258
|
|
|
259
259
|
- **LangChain.** [`LangChainVisitor`](../src/logseq_matryca_parser/synapse.py) emits one **`Document`** per node with `page_content=node.clean_text` and metadata unioning **`node.properties`** with lineage fields (`uuid`, `parent_id`, `indent_level`, `source`, **`path`** — the UUID ancestry chain — `left_id`, `refs`, `task_status`, repeater, `created_at`). The underlying **`LogseqNode`** additionally carries **`task_priority`**, **`scheduled_at`**, and **`deadline_at`** (§3.1); adapters or custom visitors can project those into metadata when feeding **downstream graph databases** or **GraphRAG** filters. This preserves **parent context** explicitly in retrieval filters and re-ranking.
|
|
260
260
|
|
|
261
|
-
- **LlamaIndex.** [`LlamaIndexVisitor`](../src/logseq_matryca_parser/synapse.py) constructs **`TextNode`** instances keyed by **`id_=node.uuid`**. It wires **`NodeRelationship.PARENT`** and **`CHILD`** via **`RelatedNodeInfo`**, back-linking when the parent appears earlier in preorder traversal — encoding **topology as first-class edges** beyond flat metadata dictionaries.
|
|
261
|
+
- **LlamaIndex.** [`LlamaIndexVisitor`](../src/logseq_matryca_parser/synapse.py) constructs **`TextNode`** instances keyed by **`id_=node.uuid`**. It wires **`NodeRelationship.PARENT`** and **`CHILD`** via **`RelatedNodeInfo`**, back-linking when the parent appears earlier in preorder traversal — encoding **topology as first-class edges** beyond flat metadata dictionaries. From **v1.3.0**, it also emits **`SOURCE`** (page-level anchor via **`page_source_node_id`**), **`NEXT`**, and **`PREVIOUS`** sibling edges for spatial traversal in vector stores.
|
|
262
|
+
|
|
263
|
+
- **Vector-store metadata.** **`SynapseMetadata`** and **`build_synapse_metadata`** project **`task_priority`**, temporal epoch fields, **`source_uuid`**, and joined **`path`** / **`refs`** strings into LangChain/LlamaIndex metadata without leaking raw Python list reprs.
|
|
262
264
|
|
|
263
265
|
Together, adapters guarantee that **embedding units align with intentional block boundaries**, not splitter accidents.
|
|
264
266
|
|
|
@@ -276,7 +278,7 @@ The KINETIC **`export --format langchain-enriched`** path serializes these docum
|
|
|
276
278
|
|
|
277
279
|
### 3.3 LENS — NetworkX topology + PyVis interactive visualization
|
|
278
280
|
|
|
279
|
-
**LENS** (`logseq_matryca_parser.lens.GraphVisualizer`) builds a **`networkx.Graph`** over **page ⇄ wiki/tag reference** projections using `NetworkXVisitor` during AST preorder walks. Nodes receive **degree-based sizing** (“sun” hotspots) and subgroup classification (`page`, `tag`, `journal`, etc.).
|
|
281
|
+
**LENS** (`logseq_matryca_parser.lens.GraphVisualizer`) builds a **`networkx.Graph`** over **page ⇄ wiki/tag reference** projections using `NetworkXVisitor` during AST preorder walks. Nodes receive **degree-based sizing** (“sun” hotspots) and subgroup classification (`page`, `tag`, `journal`, etc.). **NetworkX** and **PyVis** are **lazy-imported** (optional **`[viz]`** extra) so core installs avoid pulling visualization dependencies until `GraphVisualizer` is used.
|
|
280
282
|
|
|
281
283
|
Visualization export uses **`pyvis`** with **`force_atlas_2based`** physics, fullscreen canvas, HUD filters, glassmorphism control chrome, and stabilized layout configuration suitable for **large graphs at interactive frame rates** in the browser (product positioning targets fluid exploration of graphs on the order of **10⁴ nodes**).
|
|
282
284
|
|
|
@@ -296,14 +298,14 @@ Both paths keep **existing topology intact** relative to their contract: append-
|
|
|
296
298
|
|
|
297
299
|
### 3.6 `LogseqGraph` — namespace scoping, O(1) invalidation, live watch
|
|
298
300
|
|
|
299
|
-
The **in-memory graph** ([`graph.py`](../src/logseq_matryca_parser/graph.py)) is the runtime **RAM image** of the sovereign vault: `pages: dict[str, LogseqPage]`, a private **`_node_registry`** keyed by synthetic block UUID, and a **`_backlink_registry`** mapping normalized link targets to source node UUIDs.
|
|
301
|
+
The **in-memory graph** ([`graph.py`](../src/logseq_matryca_parser/graph.py)) is the runtime **RAM image** of the sovereign vault: `pages: dict[str, LogseqPage]`, a private **`_node_registry`** keyed by synthetic block UUID, and a **`_backlink_registry`** mapping normalized link targets to source node UUIDs. **`LogseqGraph`** uses **`ConfigDict(strict=True, validate_assignment=True)`** (not frozen) so **`invalidate_and_reload_page`** can mutate registries and page maps without `object.__setattr__` workarounds.
|
|
300
302
|
|
|
301
303
|
#### Page title overrides and alias indexing (`_enrich_pages_index`)
|
|
302
304
|
|
|
303
305
|
After every bulk or incremental parse, the graph applies a **post-parse enrichment pass** before backlink construction:
|
|
304
306
|
|
|
305
307
|
1. **Filename → canonical title.** Each markdown file is first keyed by **`derive_page_title_from_source_path`** (see §3.9).
|
|
306
|
-
2. **`title::` override.** If page frontmatter contains a non-empty string **`title`**, the
|
|
308
|
+
2. **`title::` override.** If page frontmatter contains a non-empty string **`title`**, the `LogseqPage` is updated via **`model_copy(update={"title": custom})`**, the old filename key is removed from **`pages`**, and the page is re-inserted under the custom title (collision with another file’s title is skipped with a debug log).
|
|
307
309
|
3. **Alias injection.** For each canonical dict entry where **`dict_key == page.title`**, values from **`alias::`** and **`aliases::`** are normalized (comma-separated strings or Python lists; `[[Page]]` / `#tag` adornments stripped using the same rules as [`logseq_markdown.py`](../src/logseq_matryca_parser/logseq_markdown.py)) and registered as **additional keys** pointing at the **same `LogseqPage` instance** — e.g. `pages["Dev"]` and `pages["Development"]` share identity.
|
|
308
310
|
4. **Backlinks.** **`_build_backlink_registry`** walks **unique pages** (`id(page)` deduplication) so alias keys do not double-count outgoing links. Incoming wikilinks such as **`[[Dev]]`** normalize to lowercase registry keys and resolve through **`get_backlinks("Dev")`** like any other page title.
|
|
309
311
|
|
|
@@ -341,7 +343,11 @@ This keeps **global indexes consistent** without rebuilding the entire graph —
|
|
|
341
343
|
|
|
342
344
|
#### Live filesystem watcher (`start_watching`)
|
|
343
345
|
|
|
344
|
-
**`LogseqGraph.start_watching(callback=None)`** (optional **`watchdog`** install) returns a **`LogseqGraphWatcher`** that schedules a recursive **`Observer`** on the graph root. **`on_modified` / `on_created`** events for tracked Markdown call **`invalidate_and_reload_page`**, then optionally invoke **`callback(path)`** — the intended hook for **vector store patch**, **re-embedding**, or UI refresh. Event routing ignores directories and non-tracked extensions so the hot path stays tight.
|
|
346
|
+
**`LogseqGraph.start_watching(callback=None, debounce_seconds=0.5)`** (optional **`watchdog`** install) returns a **`LogseqGraphWatcher`** that schedules a recursive **`Observer`** on the graph root. **`on_modified` / `on_created`** events for tracked Markdown call **`invalidate_and_reload_page`**, then optionally invoke **`callback(path)`** — the intended hook for **vector store patch**, **re-embedding**, or UI refresh. **`_DebouncedGraphEventRouter`** coalesces rapid save bursts (~500ms default) and ignores editor temp/swap artifacts (`.swp`, `~`, `.tmp`, `.DS_Store`). Event routing ignores directories and non-tracked extensions so the hot path stays tight.
|
|
347
|
+
|
|
348
|
+
#### Parse-time reference validation (`strict_refs`)
|
|
349
|
+
|
|
350
|
+
**`StackMachineParser(..., strict_refs=False)`** (default) resolves same-page `((uuid))` block refs leniently. When **`strict_refs=True`**, unresolved refs raise **`BlockReferenceError`** at parse time — complementary to **`LogseqGraph.get_broken_references()`**, which scans the loaded graph post-hoc.
|
|
345
351
|
|
|
346
352
|
#### Fluent topological queries (`GraphQuery`)
|
|
347
353
|
|
|
@@ -404,6 +410,8 @@ The compound CLI commands **`agent_read`** and **`agent_write`** in [`kinetic.py
|
|
|
404
410
|
|
|
405
411
|
Rich styling injects **ANSI escape sequences** that waste tokens and can cause models to **hallucinate markup** as content. `agent-read` is **stdout-pure** so shell pipelines, MCP tools, and headless agents receive **unescaped plain text** only. Human-oriented commands (`scan`, `export`, `visualize`) keep Rich; the **machine-native read/write paths** opt out where token fidelity matters.
|
|
406
412
|
|
|
413
|
+
**Global CLI options (v1.3.0).** [`kinetic.py`](../src/logseq_matryca_parser/kinetic.py) registers **`@app.callback()`** with **`--verbose`** and **`--graph`** so every subcommand shares graph-path resolution and debug logging. Optional extras (`[ai]`, `[viz]`) print **`uv sync --extra …`** hints on import failure.
|
|
414
|
+
|
|
407
415
|
This complements §3.4 **AGENT WRITER** (weekly append + headless splice) and §3.2 **SYNAPSE** (human/RAG chunking): one stack, multiple projections — **enriched chunks for vectors**, **X-Ray + alias state for agent context**, **append / splice for durable writes**.
|
|
408
416
|
|
|
409
417
|
### 3.8 Bidirectional I/O and Logseq Layouts
|
|
@@ -459,7 +467,7 @@ Logseq namespaces use **`/`** in titles (e.g. `Projects/AI`). On disk, each segm
|
|
|
459
467
|
|
|
460
468
|
#### Graph discovery filters
|
|
461
469
|
|
|
462
|
-
When scanning a vault root, **`is_excluded_graph_path`** drops noise directories — notably **`.recycle`**, **`.git`**, and the internal **`logseq`** config tree — so incremental watchers and bulk loaders never ingest backup blobs or VCS metadata as pages. This keeps **`LogseqGraph.load_directory`** and **`invalidate_and_reload_page`** focused on sovereign content under `pages/` and `journals/`.
|
|
470
|
+
When scanning a vault root, **`discover_graph_files`** (in [`logseq_paths.py`](../src/logseq_matryca_parser/logseq_paths.py), shared by **`LogseqGraph.load_directory`** and **KINETIC**) enumerates `pages/` and `journals/` markdown. **`is_excluded_graph_path`** drops noise directories — notably **`.recycle`**, **`.git`**, and the internal **`logseq`** config tree — so incremental watchers and bulk loaders never ingest backup blobs or VCS metadata as pages. This keeps **`LogseqGraph.load_directory`** and **`invalidate_and_reload_page`** focused on sovereign content under `pages/` and `journals/`.
|
|
463
471
|
|
|
464
472
|
---
|
|
465
473
|
|
|
@@ -528,4 +536,4 @@ Recursive and character-budget chunkers assume **approximately flat prose**. Log
|
|
|
528
536
|
|
|
529
537
|
---
|
|
530
538
|
|
|
531
|
-
*This document reflects the implementations in `src/logseq_matryca_parser/logos_parser.py`, `synapse.py`, `graph.py`, `forge.py`, `lens.py`, `logos_core.py`, `agent_writer.py`, `agent_press.py`, `logseq_markdown.py`, and `
|
|
539
|
+
*This document reflects the implementations in `src/logseq_matryca_parser/logos_parser.py`, `synapse.py`, `graph.py`, `forge.py`, `lens.py`, `logos_core.py`, `agent_writer.py`, `agent_press.py`, `logseq_markdown.py`, `logseq_paths.py`, `kinetic.py`, and the public exports in `__init__.py`, and complements narrative primers such as [`logseq_ast_primer.md`](logseq_ast_primer.md).*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# CodeQL code scanning
|
|
2
2
|
|
|
3
|
-
**Logseq Matryca Parser** (v1.
|
|
3
|
+
**Logseq Matryca Parser** (v1.3.0+) uses **GitHub CodeQL default setup** for static analysis (SAST) on Python.
|
|
4
4
|
|
|
5
5
|
## Why there is no `codeql.yml` workflow
|
|
6
6
|
|
|
@@ -214,4 +214,4 @@ If you feed Logseq Markdown into `RecursiveCharacterTextSplitter` (LangChain) or
|
|
|
214
214
|
|
|
215
215
|
The **Logos Protocol** solves this by walking the AST deterministically, isolating properties, shielding dead-zone literals, and using the `SYNAPSE` adapter to export native LangChain `Document` or LlamaIndex `TextNode` objects. Every generated object retains its exact hierarchical lineage in the metadata, feeding your local LLM perfectly structured data.
|
|
216
216
|
|
|
217
|
-
For vault-wide navigation (aliases, backlinks, namespace shadowing, assets), load the graph with **`LogseqGraph`** — see the [README](../README.md) and [CHANGELOG](../CHANGELOG.md) (graph parity from **v1.2.0**; **v1.
|
|
217
|
+
For vault-wide navigation (aliases, backlinks, namespace shadowing, assets), load the graph with **`LogseqGraph`** — see the [README](../README.md) and [CHANGELOG](../CHANGELOG.md) (graph parity from **v1.2.0**; **v1.3.0** adds watcher debounce, `strict_refs`, public API exports, and LlamaIndex spatial relationships).
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# 📜 Architectural Contract: Live Incremental Invalidation & File Watcher
|
|
2
2
|
**Contract Status:** Wave 7 — Implemented (incremental invalidation + lazy watchdog watcher)
|
|
3
|
+
|
|
4
|
+
> **Implementation note (v1.3.0):** `LogseqGraph` now uses `validate_assignment=True` (not `frozen=True`); the watcher debounces events (~500ms) and ignores editor temp files. Historical spec text below describes the original contract.
|
|
3
5
|
**Target Stack:** Python 3.12+ | Pydantic V2 | Watchdog (Optional/Lazy Dependency)
|
|
4
6
|
**Inspiration Architectures:**
|
|
5
7
|
- `Microsoft/language-server-protocol` (Incremental text document synchronization and dependency invalidation)
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# 📜 Architectural Contract: Synthetic UUID Hardening & Graph Orchestration Module
|
|
2
2
|
**Contract Status:** Completed (Autonomous Execution)
|
|
3
|
+
|
|
4
|
+
> **Implementation note (v1.3.0):** `discover_graph_files` lives in `logseq_paths.py` (not `kinetic.py`); `LogseqGraph` uses `validate_assignment=True` instead of `frozen=True`. Historical spec text below describes the original contract.
|
|
3
5
|
**Target Stack:** Python 3.12+ | Pydantic V2 (Strict/Frozen Models) | Local-First No-DB
|
|
4
6
|
|
|
5
7
|
**Execution checklist**
|
|
@@ -11,10 +11,11 @@ root_dir = Path(__file__).parent.parent
|
|
|
11
11
|
sys.path.append(str(root_dir / "src"))
|
|
12
12
|
|
|
13
13
|
try:
|
|
14
|
-
from logseq_matryca_parser.logos_parser import LogosParser
|
|
15
|
-
from logseq_matryca_parser.forge import ForgeExporter
|
|
16
14
|
from rich.console import Console
|
|
17
15
|
from rich.panel import Panel
|
|
16
|
+
|
|
17
|
+
from logseq_matryca_parser.forge import ForgeExporter
|
|
18
|
+
from logseq_matryca_parser.logos_parser import LogosParser
|
|
18
19
|
except ImportError as e:
|
|
19
20
|
print(f"Errore: Assicurati di aver installato le dipendenze (pip install rich typer pydantic). {e}")
|
|
20
21
|
sys.exit(1)
|
|
@@ -5,10 +5,9 @@ import re
|
|
|
5
5
|
import shutil
|
|
6
6
|
import urllib.request
|
|
7
7
|
from datetime import datetime
|
|
8
|
-
from typing import Any,
|
|
8
|
+
from typing import Any, Literal, TypeVar
|
|
9
9
|
|
|
10
10
|
from pydantic import BaseModel, ValidationError
|
|
11
|
-
|
|
12
11
|
from smart_router.core.ingestion_engine import IngestionEngine
|
|
13
12
|
from smart_router.core.librarian_models import (
|
|
14
13
|
EntityNodeSchema,
|
|
@@ -31,7 +30,7 @@ async def emit_note_package(
|
|
|
31
30
|
slug: str,
|
|
32
31
|
content: str,
|
|
33
32
|
ontology_class: NodeType,
|
|
34
|
-
metadata:
|
|
33
|
+
metadata: dict[str, str],
|
|
35
34
|
indentation_level: int,
|
|
36
35
|
) -> None:
|
|
37
36
|
package = SovereignNotePackage(
|
|
@@ -90,9 +89,7 @@ class LogseqASTParser:
|
|
|
90
89
|
trees.append("\n".join(current_tree))
|
|
91
90
|
current_tree = [line]
|
|
92
91
|
else:
|
|
93
|
-
if current_tree:
|
|
94
|
-
current_tree.append(line)
|
|
95
|
-
elif line.strip():
|
|
92
|
+
if current_tree or line.strip():
|
|
96
93
|
current_tree.append(line)
|
|
97
94
|
if current_tree:
|
|
98
95
|
trees.append("\n".join(current_tree))
|
|
@@ -122,7 +119,7 @@ T = TypeVar("T", bound=BaseModel)
|
|
|
122
119
|
def call_local_llm(
|
|
123
120
|
system_prompt: str, user_content: str, response_model: type[T]
|
|
124
121
|
) -> T | None:
|
|
125
|
-
payload:
|
|
122
|
+
payload: dict[str, Any] = {
|
|
126
123
|
"model": "local-model",
|
|
127
124
|
"messages": [
|
|
128
125
|
{"role": "system", "content": system_prompt},
|
|
@@ -204,7 +201,7 @@ async def main() -> None:
|
|
|
204
201
|
if filename.startswith("."):
|
|
205
202
|
continue
|
|
206
203
|
filepath = os.path.join(INBOX_DIR, filename)
|
|
207
|
-
with open(filepath,
|
|
204
|
+
with open(filepath, encoding="utf-8") as f:
|
|
208
205
|
global_skeleton = f.read()
|
|
209
206
|
macro_buckets = LogseqASTParser.chunk_into_buckets(
|
|
210
207
|
global_skeleton, max_chars=15000
|
|
@@ -247,7 +244,7 @@ async def main() -> None:
|
|
|
247
244
|
if not note_filename.endswith(".md"):
|
|
248
245
|
note_filename += ".md"
|
|
249
246
|
try:
|
|
250
|
-
metadata:
|
|
247
|
+
metadata: dict[str, str] = {
|
|
251
248
|
"source_filename": filename,
|
|
252
249
|
"confidence": str(extracted_base.confidence),
|
|
253
250
|
"extracted_at": datetime.now().isoformat(),
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "logseq-matryca-parser"
|
|
7
|
-
version = "1.
|
|
7
|
+
version = "1.3.0"
|
|
8
8
|
description = "The Logos Protocol: Deterministic Logseq AST parsing for Matryca.ai."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.12"
|
|
@@ -76,6 +76,14 @@ dev = [
|
|
|
76
76
|
"ruff>=0.15.12",
|
|
77
77
|
]
|
|
78
78
|
|
|
79
|
+
[tool.uv]
|
|
80
|
+
constraint-dependencies = [
|
|
81
|
+
"aiohttp>=3.14.1",
|
|
82
|
+
]
|
|
83
|
+
override-dependencies = [
|
|
84
|
+
"nltk @ git+https://github.com/nltk/nltk@v3.10.0-rc1",
|
|
85
|
+
]
|
|
86
|
+
|
|
79
87
|
[tool.pytest.ini_options]
|
|
80
88
|
testpaths = ["tests"]
|
|
81
89
|
|
|
@@ -95,3 +103,16 @@ module = [
|
|
|
95
103
|
"watchdog.*",
|
|
96
104
|
]
|
|
97
105
|
ignore_missing_imports = true
|
|
106
|
+
|
|
107
|
+
[tool.ruff]
|
|
108
|
+
target-version = "py312"
|
|
109
|
+
line-length = 100
|
|
110
|
+
exclude = ["legacy", "examples", "scripts"]
|
|
111
|
+
|
|
112
|
+
[tool.ruff.lint]
|
|
113
|
+
select = ["E", "F", "I", "UP", "B", "SIM"]
|
|
114
|
+
ignore = ["E501"]
|
|
115
|
+
|
|
116
|
+
[tool.ruff.lint.per-file-ignores]
|
|
117
|
+
"src/logseq_matryca_parser/kinetic.py" = ["B008"]
|
|
118
|
+
"tests/**" = ["SIM117"]
|
{logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/src/logseq_matryca_parser/__init__.py
RENAMED
|
@@ -4,8 +4,9 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import sys
|
|
6
6
|
|
|
7
|
-
__version__ = "1.
|
|
7
|
+
__version__ = "1.3.0"
|
|
8
8
|
|
|
9
|
+
from .agent_press import SessionAliasRegistry
|
|
9
10
|
from .agent_writer import LogseqConfigReader, logseq_agent_write
|
|
10
11
|
from .exceptions import BlockReferenceError, LogseqIndentationError, LogseqParserError
|
|
11
12
|
from .forge import (
|
|
@@ -16,7 +17,15 @@ from .forge import (
|
|
|
16
17
|
ObsidianForgeVisitor,
|
|
17
18
|
)
|
|
18
19
|
from .graph import LogseqGraph
|
|
19
|
-
from .logos_core import ASTVisitor, LogseqNode, LogseqPage,
|
|
20
|
+
from .logos_core import ASTVisitor, LogosNode, LogseqNode, LogseqPage, SovereignNotePackage
|
|
21
|
+
from .logos_parser import (
|
|
22
|
+
LOGSEQ_PATTERNS,
|
|
23
|
+
LogosParser,
|
|
24
|
+
PageRegistry,
|
|
25
|
+
StackMachineParser,
|
|
26
|
+
clean_node_content,
|
|
27
|
+
is_system_block,
|
|
28
|
+
)
|
|
20
29
|
from .logseq_markdown import (
|
|
21
30
|
format_logseq_block_property_lines,
|
|
22
31
|
format_logseq_page_properties,
|
|
@@ -26,12 +35,19 @@ from .logseq_markdown import (
|
|
|
26
35
|
from .logseq_paths import (
|
|
27
36
|
decode_page_title_segment,
|
|
28
37
|
derive_page_title_from_source_path,
|
|
38
|
+
discover_graph_files,
|
|
29
39
|
encode_page_title_segment,
|
|
30
40
|
filename_to_page_title,
|
|
31
41
|
is_excluded_graph_path,
|
|
32
42
|
page_title_to_filename,
|
|
33
43
|
page_title_to_relative_path,
|
|
34
44
|
)
|
|
45
|
+
from .synapse import SynapseAdapter, page_source_node_id
|
|
46
|
+
|
|
47
|
+
try:
|
|
48
|
+
from .lens import GraphVisualizer
|
|
49
|
+
except ImportError: # optional [viz] extra (networkx / pyvis)
|
|
50
|
+
GraphVisualizer = None # type: ignore[misc, assignment]
|
|
35
51
|
|
|
36
52
|
|
|
37
53
|
def ensure_aot_compatibility() -> None:
|
|
@@ -46,6 +62,7 @@ __all__ = [
|
|
|
46
62
|
"BlockReferenceError",
|
|
47
63
|
"FlatListForgeVisitor",
|
|
48
64
|
"ForgeExporter",
|
|
65
|
+
"GraphVisualizer",
|
|
49
66
|
"JSONForgeVisitor",
|
|
50
67
|
"LOGSEQ_PATTERNS",
|
|
51
68
|
"LogosNode",
|
|
@@ -56,22 +73,26 @@ __all__ = [
|
|
|
56
73
|
"LogseqNode",
|
|
57
74
|
"LogseqPage",
|
|
58
75
|
"LogseqParserError",
|
|
76
|
+
"MarkdownForgeVisitor",
|
|
77
|
+
"ObsidianForgeVisitor",
|
|
59
78
|
"PageRegistry",
|
|
79
|
+
"SessionAliasRegistry",
|
|
60
80
|
"SovereignNotePackage",
|
|
61
81
|
"StackMachineParser",
|
|
82
|
+
"SynapseAdapter",
|
|
62
83
|
"clean_node_content",
|
|
63
|
-
"ensure_aot_compatibility",
|
|
64
84
|
"decode_page_title_segment",
|
|
65
85
|
"derive_page_title_from_source_path",
|
|
86
|
+
"discover_graph_files",
|
|
66
87
|
"encode_page_title_segment",
|
|
88
|
+
"ensure_aot_compatibility",
|
|
67
89
|
"filename_to_page_title",
|
|
68
90
|
"format_logseq_block_property_lines",
|
|
69
91
|
"format_logseq_page_properties",
|
|
70
92
|
"is_excluded_graph_path",
|
|
71
93
|
"is_system_block",
|
|
72
94
|
"logseq_agent_write",
|
|
73
|
-
"
|
|
74
|
-
"ObsidianForgeVisitor",
|
|
95
|
+
"page_source_node_id",
|
|
75
96
|
"page_title_to_filename",
|
|
76
97
|
"page_title_to_relative_path",
|
|
77
98
|
"serialize_logseq_page",
|
{logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/src/logseq_matryca_parser/forge.py
RENAMED
|
@@ -179,10 +179,7 @@ def _replace_block_refs_in_text(
|
|
|
179
179
|
|
|
180
180
|
def _obsidian_line_source(node: LogseqNode) -> str:
|
|
181
181
|
"""Prefer the first line of ``content`` so ``((uuid))`` survives when stripped from ``clean_text``."""
|
|
182
|
-
if node.content
|
|
183
|
-
first = node.content.split("\n", 1)[0]
|
|
184
|
-
else:
|
|
185
|
-
first = node.clean_text
|
|
182
|
+
first = node.content.split("\n", 1)[0] if node.content else node.clean_text
|
|
186
183
|
stripped = LOGSEQ_PATTERNS["inline_uuid_prop"].sub("", first)
|
|
187
184
|
return stripped.replace("\n", " ").strip()
|
|
188
185
|
|