anchor-kb 0.2.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.
- anchor_kb-0.2.0/.gitignore +67 -0
- anchor_kb-0.2.0/.importlinter +67 -0
- anchor_kb-0.2.0/EXTENSIONS.md +283 -0
- anchor_kb-0.2.0/LICENSE +21 -0
- anchor_kb-0.2.0/OIP.md +33 -0
- anchor_kb-0.2.0/PKG-INFO +323 -0
- anchor_kb-0.2.0/README.md +286 -0
- anchor_kb-0.2.0/conftest.py +9 -0
- anchor_kb-0.2.0/docs/README.md +42 -0
- anchor_kb-0.2.0/docs/assets/README.md +34 -0
- anchor_kb-0.2.0/pyproject.toml +110 -0
- anchor_kb-0.2.0/scripts/dev.sh +16 -0
- anchor_kb-0.2.0/src/anchor/__init__.py +8 -0
- anchor_kb-0.2.0/src/anchor/__main__.py +5 -0
- anchor_kb-0.2.0/src/anchor/adapters/__init__.py +0 -0
- anchor_kb-0.2.0/src/anchor/adapters/cli/__init__.py +0 -0
- anchor_kb-0.2.0/src/anchor/adapters/cli/extensions.py +301 -0
- anchor_kb-0.2.0/src/anchor/adapters/cli/install.py +234 -0
- anchor_kb-0.2.0/src/anchor/adapters/cli/main.py +1517 -0
- anchor_kb-0.2.0/src/anchor/adapters/http/__init__.py +0 -0
- anchor_kb-0.2.0/src/anchor/adapters/http/app.py +135 -0
- anchor_kb-0.2.0/src/anchor/adapters/http/deps.py +25 -0
- anchor_kb-0.2.0/src/anchor/adapters/http/routers/__init__.py +0 -0
- anchor_kb-0.2.0/src/anchor/adapters/http/routers/edges.py +45 -0
- anchor_kb-0.2.0/src/anchor/adapters/http/routers/nodes.py +68 -0
- anchor_kb-0.2.0/src/anchor/adapters/http/routers/sse.py +46 -0
- anchor_kb-0.2.0/src/anchor/adapters/http/routers/workspaces.py +239 -0
- anchor_kb-0.2.0/src/anchor/adapters/http/schemas.py +111 -0
- anchor_kb-0.2.0/src/anchor/adapters/mcp/__init__.py +0 -0
- anchor_kb-0.2.0/src/anchor/adapters/mcp/handlers_canvas.py +519 -0
- anchor_kb-0.2.0/src/anchor/adapters/mcp/server.py +198 -0
- anchor_kb-0.2.0/src/anchor/adapters/mcp/stdio_main.py +106 -0
- anchor_kb-0.2.0/src/anchor/core/__init__.py +0 -0
- anchor_kb-0.2.0/src/anchor/core/clock.py +27 -0
- anchor_kb-0.2.0/src/anchor/core/docs/__init__.py +0 -0
- anchor_kb-0.2.0/src/anchor/core/docs/tags.py +67 -0
- anchor_kb-0.2.0/src/anchor/core/events/__init__.py +28 -0
- anchor_kb-0.2.0/src/anchor/core/events/canvas.py +114 -0
- anchor_kb-0.2.0/src/anchor/core/events/envelope.py +27 -0
- anchor_kb-0.2.0/src/anchor/core/ids.py +67 -0
- anchor_kb-0.2.0/src/anchor/core/ports/__init__.py +13 -0
- anchor_kb-0.2.0/src/anchor/core/ports/event_bus.py +14 -0
- anchor_kb-0.2.0/src/anchor/core/ports/snapshot.py +58 -0
- anchor_kb-0.2.0/src/anchor/core/ports/workspace_store.py +23 -0
- anchor_kb-0.2.0/src/anchor/core/services/__init__.py +0 -0
- anchor_kb-0.2.0/src/anchor/core/services/workspace_service.py +551 -0
- anchor_kb-0.2.0/src/anchor/core/upload_safety.py +88 -0
- anchor_kb-0.2.0/src/anchor/core/workspace/__init__.py +23 -0
- anchor_kb-0.2.0/src/anchor/core/workspace/align.py +150 -0
- anchor_kb-0.2.0/src/anchor/core/workspace/edges.py +31 -0
- anchor_kb-0.2.0/src/anchor/core/workspace/layout.py +221 -0
- anchor_kb-0.2.0/src/anchor/core/workspace/node_types.py +81 -0
- anchor_kb-0.2.0/src/anchor/core/workspace/nodes.py +47 -0
- anchor_kb-0.2.0/src/anchor/core/workspace/reducer.py +110 -0
- anchor_kb-0.2.0/src/anchor/core/workspace/workspace.py +117 -0
- anchor_kb-0.2.0/src/anchor/extensions/__init__.py +0 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_cad/__init__.py +0 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_cad/adapters/__init__.py +0 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_cad/adapters/http/__init__.py +0 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_cad/adapters/http/cad_routes.py +118 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_cad/core/__init__.py +0 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_cad/core/events.py +30 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_cad/core/ports.py +34 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_cad/core/schemas.py +108 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_cad/core/services.py +129 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_cad/extension.py +130 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_cad/infra/__init__.py +0 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_cad/infra/fs_store.py +80 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_cad/infra/memory_store.py +37 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_cad/infra/naive_inspector.py +65 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_cad/infra/trimesh_inspector.py +79 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_cad/mcp_handlers.py +79 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_fmus/__init__.py +0 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_fmus/adapters/__init__.py +0 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_fmus/adapters/http/__init__.py +0 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_fmus/adapters/http/fmu_routes.py +111 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_fmus/core/__init__.py +0 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_fmus/core/events.py +43 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_fmus/core/ports.py +54 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_fmus/core/schemas.py +128 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_fmus/core/services.py +135 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_fmus/extension.py +131 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_fmus/infra/__init__.py +0 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_fmus/infra/fake_runtime.py +70 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_fmus/infra/fmpy_runtime.py +123 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_fmus/infra/fs_store.py +101 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_fmus/infra/memory_store.py +60 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_fmus/mcp_handlers.py +112 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_pdfs/__init__.py +0 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_pdfs/adapters/__init__.py +0 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_pdfs/adapters/http/__init__.py +0 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_pdfs/adapters/http/documents.py +209 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_pdfs/adapters/http/upload.py +89 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_pdfs/adapters/mcp/__init__.py +0 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_pdfs/core/__init__.py +0 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_pdfs/core/events.py +68 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_pdfs/core/ingest/__init__.py +0 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_pdfs/core/ports/__init__.py +0 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_pdfs/core/ports/doc_store.py +58 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_pdfs/core/ports/embedder.py +8 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_pdfs/core/ports/md_polisher.py +16 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_pdfs/core/ports/pdf_extractor.py +13 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_pdfs/core/ports/pdf_renderer.py +21 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_pdfs/core/ports/region_extractor.py +17 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_pdfs/core/ports/synopsis_renderer.py +30 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_pdfs/core/search.py +54 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_pdfs/core/services.py +334 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_pdfs/core/silver.py +373 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_pdfs/core/synopsis.py +276 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_pdfs/infra/__init__.py +0 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_pdfs/infra/fs_doc_store.py +208 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_pdfs/infra/llm/__init__.py +0 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_pdfs/infra/llm/local_sentence_transformer_embedder.py +45 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_pdfs/infra/llm/openai_embedder.py +21 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_pdfs/infra/llm/openai_md_polisher.py +48 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_pdfs/infra/llm/openai_region_extractor.py +59 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_pdfs/infra/memory_doc_store.py +106 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_pdfs/infra/pdf/__init__.py +0 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_pdfs/infra/pdf/docling_extractor.py +76 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_pdfs/infra/pdf/pymupdf_renderer.py +56 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_pdfs/infra/synopsis_renderers.py +179 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_pdfs/mcp_handlers.py +330 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_sysml/README.md +58 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_sysml/__init__.py +0 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_sysml/adapters/__init__.py +0 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_sysml/adapters/http/__init__.py +0 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_sysml/adapters/http/sysml_routes.py +57 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_sysml/core/__init__.py +0 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_sysml/core/events.py +32 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_sysml/core/ports.py +42 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_sysml/core/schemas.py +195 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_sysml/core/services.py +187 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_sysml/extension.py +119 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_sysml/infra/__init__.py +0 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_sysml/infra/canvas_layout.py +138 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_sysml/infra/canvas_mapper.py +252 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_sysml/infra/canvas_resolver.py +183 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_sysml/infra/lexer.py +239 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_sysml/infra/lexer_tables.py +145 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_sysml/infra/parser.py +153 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_sysml/infra/parser_grammar.py +264 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_sysml/infra/parser_helpers.py +291 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_sysml/infra/parser_requirements.py +125 -0
- anchor_kb-0.2.0/src/anchor/extensions/anchor_sysml/mcp_handlers.py +83 -0
- anchor_kb-0.2.0/src/anchor/infra/__init__.py +0 -0
- anchor_kb-0.2.0/src/anchor/infra/bus/__init__.py +0 -0
- anchor_kb-0.2.0/src/anchor/infra/bus/event_tailer.py +116 -0
- anchor_kb-0.2.0/src/anchor/infra/bus/memory_bus.py +53 -0
- anchor_kb-0.2.0/src/anchor/infra/bus/replay.py +67 -0
- anchor_kb-0.2.0/src/anchor/infra/config.py +53 -0
- anchor_kb-0.2.0/src/anchor/infra/locks.py +18 -0
- anchor_kb-0.2.0/src/anchor/infra/snapshot/__init__.py +3 -0
- anchor_kb-0.2.0/src/anchor/infra/snapshot/headless_chromium_snapshotter.py +120 -0
- anchor_kb-0.2.0/src/anchor/infra/stores/__init__.py +0 -0
- anchor_kb-0.2.0/src/anchor/infra/stores/fs_workspace_store.py +161 -0
- anchor_kb-0.2.0/src/anchor/infra/stores/memory_stores.py +9 -0
- anchor_kb-0.2.0/src/anchor/infra/stores/memory_workspace_store.py +63 -0
- anchor_kb-0.2.0/tests/__init__.py +0 -0
- anchor_kb-0.2.0/tests/adapters/__init__.py +0 -0
- anchor_kb-0.2.0/tests/adapters/test_cli_demo.py +101 -0
- anchor_kb-0.2.0/tests/adapters/test_cli_extensions.py +153 -0
- anchor_kb-0.2.0/tests/adapters/test_cli_install.py +91 -0
- anchor_kb-0.2.0/tests/adapters/test_http_workspace_snapshot.py +88 -0
- anchor_kb-0.2.0/tests/adapters/test_http_workspaces.py +339 -0
- anchor_kb-0.2.0/tests/adapters/test_mcp_canvas_snapshot.py +103 -0
- anchor_kb-0.2.0/tests/adapters/test_mcp_canvas_tools.py +367 -0
- anchor_kb-0.2.0/tests/core/__init__.py +0 -0
- anchor_kb-0.2.0/tests/core/test_align.py +156 -0
- anchor_kb-0.2.0/tests/core/test_ingest_service.py +88 -0
- anchor_kb-0.2.0/tests/core/test_layout.py +173 -0
- anchor_kb-0.2.0/tests/core/test_node_types_registry.py +106 -0
- anchor_kb-0.2.0/tests/core/test_silver_bbox_helpers.py +68 -0
- anchor_kb-0.2.0/tests/core/test_silver_build_index.py +78 -0
- anchor_kb-0.2.0/tests/core/test_silver_render.py +89 -0
- anchor_kb-0.2.0/tests/core/test_tags.py +64 -0
- anchor_kb-0.2.0/tests/core/test_workspace_align.py +137 -0
- anchor_kb-0.2.0/tests/core/test_workspace_apply.py +168 -0
- anchor_kb-0.2.0/tests/core/test_workspace_organize.py +241 -0
- anchor_kb-0.2.0/tests/core/test_workspace_service.py +300 -0
- anchor_kb-0.2.0/tests/core/test_workspace_slug_validation.py +117 -0
- anchor_kb-0.2.0/tests/core/test_workspace_snapshot.py +73 -0
- anchor_kb-0.2.0/tests/core/test_workspace_sub_canvas.py +89 -0
- anchor_kb-0.2.0/tests/extensions/__init__.py +0 -0
- anchor_kb-0.2.0/tests/extensions/anchor_cad/__init__.py +0 -0
- anchor_kb-0.2.0/tests/extensions/anchor_cad/test_service.py +130 -0
- anchor_kb-0.2.0/tests/extensions/anchor_sysml/__init__.py +0 -0
- anchor_kb-0.2.0/tests/extensions/anchor_sysml/fixtures/drone_base_architecture.sysml +52 -0
- anchor_kb-0.2.0/tests/extensions/anchor_sysml/fixtures/lkh_pump.sysml +47 -0
- anchor_kb-0.2.0/tests/extensions/anchor_sysml/fixtures/mining_frigate.sysml +94 -0
- anchor_kb-0.2.0/tests/extensions/anchor_sysml/test_canvas_mapper.py +161 -0
- anchor_kb-0.2.0/tests/extensions/anchor_sysml/test_lexer.py +91 -0
- anchor_kb-0.2.0/tests/extensions/anchor_sysml/test_parser.py +201 -0
- anchor_kb-0.2.0/tests/extensions/anchor_sysml/test_service.py +128 -0
- anchor_kb-0.2.0/tests/extensions/test_fmu_extension.py +265 -0
- anchor_kb-0.2.0/tests/fixtures/__init__.py +0 -0
- anchor_kb-0.2.0/tests/fixtures/fakes.py +121 -0
- anchor_kb-0.2.0/tests/fixtures/services.py +59 -0
- anchor_kb-0.2.0/tests/fixtures/tiny.png +0 -0
- anchor_kb-0.2.0/tests/infra/__init__.py +0 -0
- anchor_kb-0.2.0/tests/infra/test_fs_doc_store.py +114 -0
- anchor_kb-0.2.0/tests/infra/test_fs_workspace_store.py +108 -0
- anchor_kb-0.2.0/tests/infra/test_headless_chromium_snapshotter.py +93 -0
- anchor_kb-0.2.0/tests/infra/test_memory_bus.py +61 -0
- anchor_kb-0.2.0/web/.gitignore +3 -0
- anchor_kb-0.2.0/web/components.json +18 -0
- anchor_kb-0.2.0/web/dist/assets/index-Ce48iBrU.js +4457 -0
- anchor_kb-0.2.0/web/dist/assets/index-DlLwITRi.css +1 -0
- anchor_kb-0.2.0/web/dist/index.html +13 -0
- anchor_kb-0.2.0/web/eslint.config.js +52 -0
- anchor_kb-0.2.0/web/index.html +12 -0
- anchor_kb-0.2.0/web/package.json +62 -0
- anchor_kb-0.2.0/web/pnpm-lock.yaml +5537 -0
- anchor_kb-0.2.0/web/postcss.config.mjs +6 -0
- anchor_kb-0.2.0/web/src/App.tsx +22 -0
- anchor_kb-0.2.0/web/src/api/cad.ts +45 -0
- anchor_kb-0.2.0/web/src/api/canvases.ts +157 -0
- anchor_kb-0.2.0/web/src/api/client.ts +38 -0
- anchor_kb-0.2.0/web/src/api/documents.ts +46 -0
- anchor_kb-0.2.0/web/src/api/fmu.ts +31 -0
- anchor_kb-0.2.0/web/src/canvas/ActivityToast.tsx +37 -0
- anchor_kb-0.2.0/web/src/canvas/CanvasGraph.tsx +1167 -0
- anchor_kb-0.2.0/web/src/canvas/DirectionalConnectors.tsx +700 -0
- anchor_kb-0.2.0/web/src/canvas/EdgeContextMenu.tsx +290 -0
- anchor_kb-0.2.0/web/src/canvas/EdgeContextToolbar.tsx +496 -0
- anchor_kb-0.2.0/web/src/canvas/FillPicker.tsx +34 -0
- anchor_kb-0.2.0/web/src/canvas/NodeContextMenu.tsx +408 -0
- anchor_kb-0.2.0/web/src/canvas/NodeContextToolbar.tsx +615 -0
- anchor_kb-0.2.0/web/src/canvas/PaintGhost.test.tsx +153 -0
- anchor_kb-0.2.0/web/src/canvas/PaintGhost.tsx +147 -0
- anchor_kb-0.2.0/web/src/canvas/PlaceholderChip.tsx +21 -0
- anchor_kb-0.2.0/web/src/canvas/QuickAddPopover.tsx +301 -0
- anchor_kb-0.2.0/web/src/canvas/StrokePicker.tsx +33 -0
- anchor_kb-0.2.0/web/src/canvas/Swatches.tsx +125 -0
- anchor_kb-0.2.0/web/src/canvas/TextPicker.tsx +194 -0
- anchor_kb-0.2.0/web/src/canvas/WaypointEditor.tsx +203 -0
- anchor_kb-0.2.0/web/src/canvas/align.test.ts +121 -0
- anchor_kb-0.2.0/web/src/canvas/align.ts +150 -0
- anchor_kb-0.2.0/web/src/canvas/breadcrumb.ts +89 -0
- anchor_kb-0.2.0/web/src/canvas/colors.test.ts +121 -0
- anchor_kb-0.2.0/web/src/canvas/colors.ts +179 -0
- anchor_kb-0.2.0/web/src/canvas/edges/AnchoredEdge.tsx +133 -0
- anchor_kb-0.2.0/web/src/canvas/edges/EdgeMarkerDefs.tsx +144 -0
- anchor_kb-0.2.0/web/src/canvas/edges/FloatingEdge.tsx +151 -0
- anchor_kb-0.2.0/web/src/canvas/edges/RoutedEdge.tsx +213 -0
- anchor_kb-0.2.0/web/src/canvas/edges/edge-mode.test.ts +128 -0
- anchor_kb-0.2.0/web/src/canvas/edges/edge-mode.ts +108 -0
- anchor_kb-0.2.0/web/src/canvas/edges/edge-style.test.ts +84 -0
- anchor_kb-0.2.0/web/src/canvas/edges/edge-style.ts +129 -0
- anchor_kb-0.2.0/web/src/canvas/edges/floatingGeometry.ts +100 -0
- anchor_kb-0.2.0/web/src/canvas/edges/markers.test.ts +81 -0
- anchor_kb-0.2.0/web/src/canvas/edges/markers.ts +152 -0
- anchor_kb-0.2.0/web/src/canvas/icons/index.tsx +151 -0
- anchor_kb-0.2.0/web/src/canvas/placeholder.ts +36 -0
- anchor_kb-0.2.0/web/src/canvas/primitives/DocumentPrimitive.tsx +391 -0
- anchor_kb-0.2.0/web/src/canvas/primitives/Model3DPrimitive.tsx +152 -0
- anchor_kb-0.2.0/web/src/canvas/primitives/SubCanvasPrimitive.test.tsx +153 -0
- anchor_kb-0.2.0/web/src/canvas/primitives/SubCanvasPrimitive.tsx +173 -0
- anchor_kb-0.2.0/web/src/canvas/primitives/SysmlBlockPrimitive.tsx +222 -0
- anchor_kb-0.2.0/web/src/canvas/primitives/SysmlPackagePrimitive.tsx +70 -0
- anchor_kb-0.2.0/web/src/canvas/primitives/SysmlRequirementPrimitive.tsx +118 -0
- anchor_kb-0.2.0/web/src/canvas/primitives/TablePrimitive.test.tsx +127 -0
- anchor_kb-0.2.0/web/src/canvas/primitives/TablePrimitive.tsx +551 -0
- anchor_kb-0.2.0/web/src/canvas/primitives/_shared/Compartment.tsx +33 -0
- anchor_kb-0.2.0/web/src/canvas/primitives/viewers/PageWithBboxViewer.tsx +343 -0
- anchor_kb-0.2.0/web/src/canvas/registry.ts +335 -0
- anchor_kb-0.2.0/web/src/canvas/shapes/AreaNode.tsx +151 -0
- anchor_kb-0.2.0/web/src/canvas/shapes/ConceptNode.test.tsx +251 -0
- anchor_kb-0.2.0/web/src/canvas/shapes/ConceptNode.tsx +118 -0
- anchor_kb-0.2.0/web/src/canvas/shapes/EntityNode.tsx +100 -0
- anchor_kb-0.2.0/web/src/canvas/shapes/FactNode.tsx +120 -0
- anchor_kb-0.2.0/web/src/canvas/shapes/FunnelNode.test.tsx +118 -0
- anchor_kb-0.2.0/web/src/canvas/shapes/FunnelNode.tsx +152 -0
- anchor_kb-0.2.0/web/src/canvas/shapes/NoteNode.tsx +166 -0
- anchor_kb-0.2.0/web/src/canvas/useInlineField.ts +286 -0
- anchor_kb-0.2.0/web/src/canvas/useInlineLabel.ts +35 -0
- anchor_kb-0.2.0/web/src/canvas/useLiveResize.ts +70 -0
- anchor_kb-0.2.0/web/src/canvas/useWorkspacesList.ts +88 -0
- anchor_kb-0.2.0/web/src/components/ChatPanel.tsx +86 -0
- anchor_kb-0.2.0/web/src/components/ui/button.tsx +52 -0
- anchor_kb-0.2.0/web/src/components/ui/context-menu.tsx +146 -0
- anchor_kb-0.2.0/web/src/components/ui/dropdown-menu.tsx +101 -0
- anchor_kb-0.2.0/web/src/components/ui/popover.tsx +47 -0
- anchor_kb-0.2.0/web/src/components/ui/sheet.tsx +143 -0
- anchor_kb-0.2.0/web/src/components/ui/tabs.tsx +77 -0
- anchor_kb-0.2.0/web/src/components/ui/tooltip.tsx +40 -0
- anchor_kb-0.2.0/web/src/index.css +67 -0
- anchor_kb-0.2.0/web/src/lib/cn.ts +6 -0
- anchor_kb-0.2.0/web/src/main.tsx +14 -0
- anchor_kb-0.2.0/web/src/pages/CanvasListPage.tsx +80 -0
- anchor_kb-0.2.0/web/src/pages/CanvasPage.tsx +130 -0
- anchor_kb-0.2.0/web/src/pages/CanvasTree.test.tsx +145 -0
- anchor_kb-0.2.0/web/src/pages/CanvasTree.tsx +241 -0
- anchor_kb-0.2.0/web/src/pages/MonitorPage.tsx +41 -0
- anchor_kb-0.2.0/web/src/realtime/sseClient.ts +60 -0
- anchor_kb-0.2.0/web/src/search/embedder.test.ts +156 -0
- anchor_kb-0.2.0/web/src/search/embedder.ts +163 -0
- anchor_kb-0.2.0/web/src/search/embedder.worker.ts +95 -0
- anchor_kb-0.2.0/web/src/search/searchClient.ts +48 -0
- anchor_kb-0.2.0/web/src/shell/CanvasShell.tsx +57 -0
- anchor_kb-0.2.0/web/src/shell/CanvasesPanel.test.tsx +151 -0
- anchor_kb-0.2.0/web/src/shell/CanvasesPanel.tsx +185 -0
- anchor_kb-0.2.0/web/src/shell/LeftToolRail.tsx +596 -0
- anchor_kb-0.2.0/web/src/shell/Library.tsx +160 -0
- anchor_kb-0.2.0/web/src/shell/LibraryDrawer.tsx +78 -0
- anchor_kb-0.2.0/web/src/shell/PropertiesPanel.dispatch.test.ts +57 -0
- anchor_kb-0.2.0/web/src/shell/PropertiesPanel.dispatch.ts +40 -0
- anchor_kb-0.2.0/web/src/shell/PropertiesPanel.tsx +112 -0
- anchor_kb-0.2.0/web/src/shell/editors/DocumentReadonly.tsx +60 -0
- anchor_kb-0.2.0/web/src/shell/editors/JsonEscapeHatch.tsx +86 -0
- anchor_kb-0.2.0/web/src/shell/editors/LabelEditor.tsx +49 -0
- anchor_kb-0.2.0/web/src/shell/editors/MarkdownEditor.tsx +57 -0
- anchor_kb-0.2.0/web/src/shell/editors/OrganizeEditor.test.tsx +121 -0
- anchor_kb-0.2.0/web/src/shell/editors/OrganizeEditor.tsx +182 -0
- anchor_kb-0.2.0/web/src/shell/editors/SpecEditor.tsx +157 -0
- anchor_kb-0.2.0/web/src/shell/editors/_types.ts +20 -0
- anchor_kb-0.2.0/web/src/shell/editors/_usePatchNode.ts +61 -0
- anchor_kb-0.2.0/web/src/stores/canvasStore.test.ts +168 -0
- anchor_kb-0.2.0/web/src/stores/canvasStore.ts +275 -0
- anchor_kb-0.2.0/web/src/stores/uiStore.test.ts +178 -0
- anchor_kb-0.2.0/web/src/stores/uiStore.ts +226 -0
- anchor_kb-0.2.0/web/tsconfig.json +24 -0
- anchor_kb-0.2.0/web/vite.config.ts +43 -0
- anchor_kb-0.2.0/web/vitest.config.ts +13 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Build / cache
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.pyc
|
|
4
|
+
.pytest_cache/
|
|
5
|
+
.import_linter_cache/
|
|
6
|
+
.venv/
|
|
7
|
+
*.egg-info/
|
|
8
|
+
dist/
|
|
9
|
+
build/
|
|
10
|
+
*.tsbuildinfo
|
|
11
|
+
|
|
12
|
+
# Frontend
|
|
13
|
+
node_modules/
|
|
14
|
+
web/dist/
|
|
15
|
+
|
|
16
|
+
# User data — never tracked, lives in --data-dir / ANCHOR_DATA_DIR
|
|
17
|
+
data/
|
|
18
|
+
# Note: top-level docs/ IS tracked — the architecture documentation lives
|
|
19
|
+
# there. User-data canvases/ live inside `data/` which is already ignored.
|
|
20
|
+
|
|
21
|
+
# Local config / env files — never commit credentials
|
|
22
|
+
.env
|
|
23
|
+
.env.local
|
|
24
|
+
.env.*.local
|
|
25
|
+
|
|
26
|
+
# Editor
|
|
27
|
+
.vscode/
|
|
28
|
+
.idea/
|
|
29
|
+
|
|
30
|
+
# OS
|
|
31
|
+
.DS_Store
|
|
32
|
+
.playwright-cli/
|
|
33
|
+
.next/
|
|
34
|
+
|
|
35
|
+
# Legacy v1 working-tree leftovers at the repo root. These directories /
|
|
36
|
+
# files existed before v2 was promoted; they survive locally as untracked
|
|
37
|
+
# entries after pulling this commit. Full history is on the
|
|
38
|
+
# `archive/pre-v2` branch / `pre-v2-cutoff` tag.
|
|
39
|
+
#
|
|
40
|
+
# Leading slashes restrict the patterns to the repo root so they don't
|
|
41
|
+
# shadow legitimate files of the same name inside `web/`.
|
|
42
|
+
/backend/
|
|
43
|
+
/backend2/
|
|
44
|
+
/packages/
|
|
45
|
+
/paperx/
|
|
46
|
+
/paper/
|
|
47
|
+
/posters/
|
|
48
|
+
/public/
|
|
49
|
+
/mydata/
|
|
50
|
+
/uploads/
|
|
51
|
+
/tmp/
|
|
52
|
+
/Untitled/
|
|
53
|
+
/v2/
|
|
54
|
+
/src/components/
|
|
55
|
+
/src/app/
|
|
56
|
+
/2026-*-hi.txt
|
|
57
|
+
/output_bboxes.txt
|
|
58
|
+
/metadata.json
|
|
59
|
+
/package.json
|
|
60
|
+
/package-lock.json
|
|
61
|
+
/pnpm-lock.yaml
|
|
62
|
+
/postcss.config.cjs
|
|
63
|
+
/tailwind.config.cjs
|
|
64
|
+
/tsconfig.json
|
|
65
|
+
/next.config.ts
|
|
66
|
+
/next-env.d.ts
|
|
67
|
+
/todos.md
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
[importlinter]
|
|
2
|
+
root_package = anchor
|
|
3
|
+
include_external_packages = True
|
|
4
|
+
|
|
5
|
+
[importlinter:contract:layered]
|
|
6
|
+
name = Hexagonal layering — adapters → infra → core
|
|
7
|
+
type = layers
|
|
8
|
+
layers =
|
|
9
|
+
anchor.adapters
|
|
10
|
+
anchor.infra
|
|
11
|
+
anchor.core
|
|
12
|
+
|
|
13
|
+
[importlinter:contract:core_purity]
|
|
14
|
+
name = Core has no I/O / framework dependencies
|
|
15
|
+
type = forbidden
|
|
16
|
+
source_modules =
|
|
17
|
+
anchor.core
|
|
18
|
+
forbidden_modules =
|
|
19
|
+
httpx
|
|
20
|
+
fastapi
|
|
21
|
+
openai
|
|
22
|
+
mcp
|
|
23
|
+
pymupdf
|
|
24
|
+
docling
|
|
25
|
+
uvicorn
|
|
26
|
+
starlette
|
|
27
|
+
typer
|
|
28
|
+
aiofiles
|
|
29
|
+
sse_starlette
|
|
30
|
+
|
|
31
|
+
[importlinter:contract:infra_no_transport]
|
|
32
|
+
name = Infra implements ports, not transport
|
|
33
|
+
type = forbidden
|
|
34
|
+
source_modules =
|
|
35
|
+
anchor.infra
|
|
36
|
+
forbidden_modules =
|
|
37
|
+
fastapi
|
|
38
|
+
mcp
|
|
39
|
+
uvicorn
|
|
40
|
+
starlette
|
|
41
|
+
typer
|
|
42
|
+
sse_starlette
|
|
43
|
+
|
|
44
|
+
[importlinter:contract:canvas_no_extensions]
|
|
45
|
+
name = Canvas primitive does not depend on extensions
|
|
46
|
+
type = forbidden
|
|
47
|
+
source_modules =
|
|
48
|
+
anchor.core
|
|
49
|
+
anchor.infra
|
|
50
|
+
forbidden_modules =
|
|
51
|
+
anchor.extensions
|
|
52
|
+
|
|
53
|
+
[importlinter:contract:extension_layered]
|
|
54
|
+
name = Extensions follow the same layering as the canvas
|
|
55
|
+
type = layers
|
|
56
|
+
layers =
|
|
57
|
+
anchor.extensions.anchor_pdfs.adapters
|
|
58
|
+
anchor.extensions.anchor_pdfs.infra
|
|
59
|
+
anchor.extensions.anchor_pdfs.core
|
|
60
|
+
|
|
61
|
+
[importlinter:contract:anchor_sysml_layered]
|
|
62
|
+
name = anchor_sysml: layered, anchor_sysml.adapters → anchor_sysml.infra → anchor_sysml.core
|
|
63
|
+
type = layers
|
|
64
|
+
layers =
|
|
65
|
+
anchor.extensions.anchor_sysml.adapters
|
|
66
|
+
anchor.extensions.anchor_sysml.infra
|
|
67
|
+
anchor.extensions.anchor_sysml.core
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
# Anchor extensions — the contract
|
|
2
|
+
|
|
3
|
+
Anchor's canvas primitive is domain-agnostic. **Extensions** layer specific
|
|
4
|
+
ingestion pipelines, node types, edge styles, and UI components on top of it.
|
|
5
|
+
Today the PDF medallion pipeline (Docling + VLM region extraction + spec
|
|
6
|
+
tables with page+bbox provenance) lives inside the same wheel as the canvas;
|
|
7
|
+
this document describes the contract every extension follows so future
|
|
8
|
+
extensions — transcription, code regions, web pages, your own — can ship
|
|
9
|
+
either in-tree or as separate `anchor-canvas-*` packages.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## What an extension provides
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
from anchor.canvas import CanvasCore, NodeType, ToolDef, SourceRefKind
|
|
17
|
+
|
|
18
|
+
class AnchorExtension(Protocol):
|
|
19
|
+
NAME: str # machine identifier, used as namespace prefix.
|
|
20
|
+
# e.g. "anchor_pdfs", "anchor_transcribe"
|
|
21
|
+
DISPLAY_NAME: str # human-friendly label for UI
|
|
22
|
+
VERSION: str # extension version (semver)
|
|
23
|
+
REQUIRES_CANVAS: str # canvas-core compat range, e.g. ">=0.2,<0.3"
|
|
24
|
+
|
|
25
|
+
def configure(self, canvas: CanvasCore) -> None:
|
|
26
|
+
"""Called once at canvas startup. Register everything here."""
|
|
27
|
+
canvas.node_types.register_many([
|
|
28
|
+
NodeType("pdf:document", data_schema=DocumentData),
|
|
29
|
+
NodeType("pdf:spec_table", data_schema=SpecTableData),
|
|
30
|
+
...
|
|
31
|
+
])
|
|
32
|
+
canvas.source_ref_kinds.register(
|
|
33
|
+
SourceRefKind("pdf-page-bbox", schema=PdfPageBboxRef,
|
|
34
|
+
renderer_hint="open_pdf_at_bbox"),
|
|
35
|
+
)
|
|
36
|
+
canvas.mcp_tools.register_namespace("pdf", [
|
|
37
|
+
ToolDef("ingest", schema=...),
|
|
38
|
+
ToolDef("list_documents", schema=...),
|
|
39
|
+
...
|
|
40
|
+
])
|
|
41
|
+
canvas.http.mount_router("/api/pdfs", router)
|
|
42
|
+
canvas.events.register([DocBronzed, DocSilvered, DocIngested, ...])
|
|
43
|
+
canvas.services.provide("pdfs.ingest_service", IngestService(...))
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**Frontend half** (parallel contract for the React app):
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
import { registerExtension } from "@anchor/canvas/extensions";
|
|
50
|
+
import { SpecTableNode, DocumentNode } from "./nodes";
|
|
51
|
+
|
|
52
|
+
registerExtension({
|
|
53
|
+
name: "anchor_pdfs",
|
|
54
|
+
nodeTypes: {
|
|
55
|
+
"pdf:document": DocumentNode,
|
|
56
|
+
"pdf:spec_table": SpecTableNode,
|
|
57
|
+
},
|
|
58
|
+
edgeStyles: {
|
|
59
|
+
"pdf:evidence": { stroke: "#FF8E2B", dasharray: "4 4" },
|
|
60
|
+
},
|
|
61
|
+
sourceRefHandlers: {
|
|
62
|
+
"pdf-page-bbox": openPdfAtBbox,
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Naming convention
|
|
70
|
+
|
|
71
|
+
- **Node types:** `<extension_name_short>:<type>` (e.g. `pdf:spec_table`,
|
|
72
|
+
`transcribe:segment`, `code:region`). The `:` prefix prevents collisions.
|
|
73
|
+
- **MCP tools:** prefixed namespaces (`pdf.ingest`, `pdf.list_documents`,
|
|
74
|
+
`transcribe.ingest_audio`).
|
|
75
|
+
- **HTTP routes:** `/api/<extension_short>/...` (`/api/pdfs/...`,
|
|
76
|
+
`/api/transcribe/...`).
|
|
77
|
+
- **Source-ref kinds:** `<short>-<address-shape>` (`pdf-page-bbox`,
|
|
78
|
+
`audio-timestamp`, `code-line-range`).
|
|
79
|
+
- **On-disk substrates:** `data/<short>/...` (`data/bronze/`, `data/silver/`,
|
|
80
|
+
`data/gold/` for PDFs; would be `data/transcripts/` for transcription).
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## What the canvas core provides
|
|
85
|
+
|
|
86
|
+
The canvas core is the **substrate**. Extensions consume:
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
core/
|
|
90
|
+
workspace/ # Workspace aggregate, Node, Edge, reducer, validator
|
|
91
|
+
events/canvas.py # NodeAdded, NodeMoved, EdgeAdded, …
|
|
92
|
+
ports/ # WorkspaceStore, EventBus, AssetStore
|
|
93
|
+
services/ # WorkspaceService — generic CRUD over canvases
|
|
94
|
+
|
|
95
|
+
infra/
|
|
96
|
+
stores/fs_workspace_store.py
|
|
97
|
+
bus/memory_bus.py
|
|
98
|
+
|
|
99
|
+
adapters/
|
|
100
|
+
http/routers/{workspaces, nodes, edges, sse}.py
|
|
101
|
+
mcp/{server, handlers_canvas, stdio_main}.py
|
|
102
|
+
cli/main.py # the `anchor` binary, with extension subcommands
|
|
103
|
+
|
|
104
|
+
Built-in node types: concept, entity, fact, area, note
|
|
105
|
+
Built-in edge types: floating, anchored
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Every extension can use these without re-inventing them. Extensions only
|
|
109
|
+
add what's specific to their domain.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Three ways to ship an extension
|
|
114
|
+
|
|
115
|
+
### 1. In-tree (`extensions/` folder, recommended for the curated set)
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
v2/extensions/
|
|
119
|
+
└── anchor_pdfs/
|
|
120
|
+
├── pyproject.toml
|
|
121
|
+
├── src/anchor_pdfs/
|
|
122
|
+
│ ├── extension.py # AnchorExtension implementation
|
|
123
|
+
│ ├── core/, infra/, adapters/ # backend code
|
|
124
|
+
│ └── ...
|
|
125
|
+
├── web/
|
|
126
|
+
│ ├── package.json
|
|
127
|
+
│ └── src/index.ts # registerExtension(...)
|
|
128
|
+
└── tests/
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Discovery: the canvas runner walks `extensions/` at startup, imports each
|
|
132
|
+
`extension:Extension` class, calls `configure(canvas)`. Frontend imports each
|
|
133
|
+
`extensions/*/web/dist/index.js` at canvas mount.
|
|
134
|
+
|
|
135
|
+
**Status today:** PDF ingestion lives inside `src/anchor/` directly, not yet
|
|
136
|
+
extracted into `extensions/anchor_pdfs/`. The split lands as a refactor pass
|
|
137
|
+
once the API surface is stable. Use `extensions/` for genuinely new
|
|
138
|
+
extensions you'd contribute upstream.
|
|
139
|
+
|
|
140
|
+
### 2. Out-of-tree pip-installable package
|
|
141
|
+
|
|
142
|
+
Anyone publishes their own `anchor-canvas-<name>` package to PyPI:
|
|
143
|
+
|
|
144
|
+
```toml
|
|
145
|
+
# my-anchor-ext/pyproject.toml
|
|
146
|
+
[project]
|
|
147
|
+
name = "anchor-canvas-mermaid"
|
|
148
|
+
dependencies = ["anchor-canvas>=0.2"]
|
|
149
|
+
|
|
150
|
+
[project.entry-points."anchor.extensions"]
|
|
151
|
+
mermaid = "anchor_canvas_mermaid.extension:MermaidExtension"
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Discovery: the canvas runner reads Python entry points
|
|
155
|
+
(`importlib.metadata.entry_points(group='anchor.extensions')`) and loads each
|
|
156
|
+
registered class.
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
uv tool install --with anchor-canvas-mermaid anchor-canvas
|
|
160
|
+
anchor serve --data-dir ~/anchor-data # picks up mermaid automatically
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### 3. Local / editable (for extension developers)
|
|
164
|
+
|
|
165
|
+
Set `ANCHOR_EXTENSIONS_PATH` to a colon-separated list of directories
|
|
166
|
+
containing extension source code. Canvas runner walks each path, finds the
|
|
167
|
+
`extension.py` entry point, loads the extension without packaging.
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
export ANCHOR_EXTENSIONS_PATH=~/dev/my-ext:~/dev/another-ext
|
|
171
|
+
anchor serve --data-dir ~/anchor-data
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Useful for iterating on a new extension without `pip install -e .` round-trips.
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Per-project extension pinning (planned)
|
|
179
|
+
|
|
180
|
+
For reproducible extension sets bound to a `--data-dir`:
|
|
181
|
+
|
|
182
|
+
```toml
|
|
183
|
+
# ~/anchor-data/cooling-system/anchor.toml
|
|
184
|
+
[anchor]
|
|
185
|
+
canvas_version = ">=0.2,<0.3"
|
|
186
|
+
|
|
187
|
+
[[extensions]]
|
|
188
|
+
name = "anchor-canvas-pdfs"
|
|
189
|
+
version = ">=0.2"
|
|
190
|
+
|
|
191
|
+
[[extensions]]
|
|
192
|
+
git = "https://github.com/someone/anchor-canvas-mermaid"
|
|
193
|
+
ref = "v0.1"
|
|
194
|
+
|
|
195
|
+
[[extensions]]
|
|
196
|
+
path = "/Users/me/dev/my-custom-ext"
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
`anchor serve --data-dir <dir>` reads `<dir>/anchor.toml`, ensures every
|
|
200
|
+
listed extension is available (or fails loudly with install instructions),
|
|
201
|
+
loads them, starts. Lands in v0.4.
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## What lives in the canvas core vs. an extension
|
|
206
|
+
|
|
207
|
+
| Concern | Canvas core | Extension |
|
|
208
|
+
|---|---|---|
|
|
209
|
+
| Workspace, Node, Edge, reducer | ✓ | |
|
|
210
|
+
| Generic node types: concept, entity, fact, area, note | ✓ | |
|
|
211
|
+
| Generic edge types: floating, anchored | ✓ | |
|
|
212
|
+
| EventBus, SSE, WebSocket | ✓ | |
|
|
213
|
+
| Asset upload + serve | ✓ | |
|
|
214
|
+
| Screenshot mechanism (browser-as-screenshotter) | ✓ | |
|
|
215
|
+
| Viewport math (fit, visibility) | ✓ | |
|
|
216
|
+
| Lock state on nodes | ✓ | |
|
|
217
|
+
| `data.locked`, `data.visible`, `data.layer`, `data.opacity` | ✓ | |
|
|
218
|
+
| Domain-specific node types (pdf:spec_table, transcribe:segment, …) | | ✓ |
|
|
219
|
+
| Domain-specific schemas in `Node.data` | | ✓ |
|
|
220
|
+
| Domain-specific source-ref kinds | | ✓ |
|
|
221
|
+
| Ingestion pipelines (Docling, Whisper, tree-sitter, …) | | ✓ |
|
|
222
|
+
| Domain-specific React renderers | | ✓ |
|
|
223
|
+
| Domain-specific edge styling (e.g. `pdf:evidence` orange-dashed) | | ✓ |
|
|
224
|
+
| MCP tools for domain operations | | ✓ |
|
|
225
|
+
|
|
226
|
+
**The principle:** if the canvas core needs to know about a domain to
|
|
227
|
+
function, it doesn't belong in core. Canvas core only knows registries.
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## Honest gotchas for extension authors
|
|
232
|
+
|
|
233
|
+
1. **Frontend bundling is the harder problem.** Extensions need to ship JS
|
|
234
|
+
bundles that load into the canvas's React app. Today (in-tree) we glob
|
|
235
|
+
`extensions/*/web/src/index.ts` at build time. Out-of-tree extensions
|
|
236
|
+
eventually need Module Federation. We'll ship that path when there's
|
|
237
|
+
demand.
|
|
238
|
+
|
|
239
|
+
2. **`Node.data` is not type-safe across the wire.** Validators in the
|
|
240
|
+
`NodeTypeRegistry` enforce schemas at command time, but anyone reading the
|
|
241
|
+
stored JSON has to revalidate. Keep your schemas backwards-compatible.
|
|
242
|
+
|
|
243
|
+
3. **Source-ref kinds need to be unique.** If two extensions both register
|
|
244
|
+
`"page-bbox"` you'll get an error at startup. Always namespace
|
|
245
|
+
(`"pdf-page-bbox"`, not `"page-bbox"`).
|
|
246
|
+
|
|
247
|
+
4. **Don't fight the layer rules.** Your extension's `core/` may not import
|
|
248
|
+
`httpx`/`fastapi`/`openai`/etc. Same hexagonal discipline applies. Run
|
|
249
|
+
`lint-imports` on your extension.
|
|
250
|
+
|
|
251
|
+
5. **Test against the canvas's in-memory implementations.** The canvas
|
|
252
|
+
core ships `MemoryWorkspaceStore`, `MemoryDocStore`, `MemoryEventBus` —
|
|
253
|
+
use them in your unit tests so you don't need a real filesystem.
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## Status of the contract
|
|
258
|
+
|
|
259
|
+
**Stable today:**
|
|
260
|
+
- Canvas core's domain model (Workspace, Node, Edge, reducer, events)
|
|
261
|
+
- `NodeTypeRegistry` for runtime node-type registration
|
|
262
|
+
- HTTP/MCP/CLI/SSE adapter shape
|
|
263
|
+
|
|
264
|
+
**In flux (will stabilise as we extract the canvas primitive):**
|
|
265
|
+
- The `AnchorExtension` Protocol class itself (today: implicit in how PDF
|
|
266
|
+
code is wired; tomorrow: an explicit class)
|
|
267
|
+
- Frontend `registerExtension(...)` API
|
|
268
|
+
- Source-ref kind registry
|
|
269
|
+
- Edge-style registry
|
|
270
|
+
|
|
271
|
+
**Not yet implemented but documented here:**
|
|
272
|
+
- Out-of-tree extension discovery via Python entry points
|
|
273
|
+
- `anchor.toml` per-project extension pinning
|
|
274
|
+
- `ANCHOR_EXTENSIONS_PATH` for editable-install paths
|
|
275
|
+
- `anchor extensions {list, install, remove}` CLI subcommand
|
|
276
|
+
|
|
277
|
+
If you're writing an extension *today*, your safest bet is to clone v2,
|
|
278
|
+
add it under `extensions/`, follow the patterns in the existing PDF code
|
|
279
|
+
(see `src/anchor/core/services/ingest_service.py`,
|
|
280
|
+
`src/anchor/adapters/mcp/handlers_ingest.py`,
|
|
281
|
+
`src/anchor/infra/llm/`). The contract above is the target shape; the
|
|
282
|
+
move from "implicit in v2" to "explicit Protocol" is a follow-up
|
|
283
|
+
refactor.
|
anchor_kb-0.2.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Christoffer Björkskog, Lamin Jatta, and contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
anchor_kb-0.2.0/OIP.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# OIP — Open Ingestion Protocol
|
|
2
|
+
|
|
3
|
+
The OIP specification has moved to its own repository:
|
|
4
|
+
|
|
5
|
+
**📦 https://github.com/Novia-RDI-Seafaring/OIP**
|
|
6
|
+
|
|
7
|
+
That repo is the single source of truth for the protocol, manifest schema,
|
|
8
|
+
and discovery rules. It also ships a CLI (`uvx oip`) for validating
|
|
9
|
+
producer manifests and inspecting compliant on-disk trees.
|
|
10
|
+
|
|
11
|
+
## What OIP is, in one paragraph
|
|
12
|
+
|
|
13
|
+
OIP is a small, governance-neutral specification for ingestion tools that
|
|
14
|
+
produce structured, source-grounded knowledge. Any tool that conforms to
|
|
15
|
+
OIP can be consumed by any OIP-aware application — the same way any
|
|
16
|
+
LSP-compliant language server works in any LSP-aware editor. Anchor is the
|
|
17
|
+
first reference consumer; Anchor's PDF medallion pipeline is the first
|
|
18
|
+
reference producer. Both can be replaced.
|
|
19
|
+
|
|
20
|
+
## Anchor's relationship to OIP
|
|
21
|
+
|
|
22
|
+
- **Anchor's canvas** is an OIP **consumer**: it reads OIP-compliant gold
|
|
23
|
+
regions from disk and renders them as canvas nodes with row-level
|
|
24
|
+
provenance.
|
|
25
|
+
- **Anchor's bundled extensions** (`anchor_pdfs`, `anchor_fmus`,
|
|
26
|
+
`anchor_cad`, `anchor_sysml`) are OIP **producers**: each declares an
|
|
27
|
+
OIP manifest, writes to the OIP-fixed artefact tree, and exposes
|
|
28
|
+
ingest/list/get operations the canvas can discover.
|
|
29
|
+
|
|
30
|
+
For the manifest schema, the on-disk tree, the discovery rules, and the
|
|
31
|
+
list of source-kinds, **read the OIP repo's spec**. This file used to
|
|
32
|
+
contain a draft of that spec; the draft is now superseded by the
|
|
33
|
+
versioned spec in the OIP repo and is no longer maintained here.
|