ltcai 4.0.1 → 4.2.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.
- package/README.md +33 -24
- package/desktop/electron/main.cjs +44 -0
- package/docs/CHANGELOG.md +84 -0
- package/docs/V4_1_FRONTEND_ARCHITECTURE_REVIEW.md +65 -0
- package/docs/V4_1_FRONTEND_MIGRATION_REPORT.md +70 -0
- package/docs/V4_1_VALIDATION_REPORT.md +47 -0
- package/docs/V4_2_BRAIN_CORE_ARCHITECTURE.md +97 -0
- package/docs/V4_2_STORAGE_MIGRATION_REPORT.md +91 -0
- package/docs/V4_2_VALIDATION_REPORT.md +89 -0
- package/docs/V4_DIGITAL_BRAIN_RECOVERY.md +31 -26
- package/frontend/index.html +24 -0
- package/frontend/openapi.json +14436 -0
- package/frontend/src/App.tsx +184 -0
- package/frontend/src/api/client.ts +320 -0
- package/frontend/src/api/openapi.ts +16921 -0
- package/frontend/src/components/primitives.tsx +204 -0
- package/frontend/src/components/ui/badge.tsx +27 -0
- package/frontend/src/components/ui/button.tsx +37 -0
- package/frontend/src/components/ui/card.tsx +22 -0
- package/frontend/src/components/ui/input.tsx +16 -0
- package/frontend/src/components/ui/textarea.tsx +16 -0
- package/frontend/src/lib/utils.ts +33 -0
- package/frontend/src/main.tsx +23 -0
- package/frontend/src/pages/Act.tsx +245 -0
- package/frontend/src/pages/Ask.tsx +200 -0
- package/frontend/src/pages/Brain.tsx +267 -0
- package/frontend/src/pages/Capture.tsx +158 -0
- package/frontend/src/pages/Library.tsx +187 -0
- package/frontend/src/pages/System.tsx +378 -0
- package/frontend/src/routes.ts +85 -0
- package/frontend/src/store/appStore.ts +54 -0
- package/frontend/src/styles.css +107 -0
- package/kg_schema.py +1 -1
- package/knowledge_graph.py +4 -4
- package/lattice_brain/__init__.py +70 -0
- package/lattice_brain/_kg_common.py +1 -0
- package/lattice_brain/archive.py +133 -0
- package/lattice_brain/context.py +3 -0
- package/lattice_brain/conversations.py +3 -0
- package/lattice_brain/core.py +82 -0
- package/lattice_brain/discovery.py +1 -0
- package/lattice_brain/documents.py +1 -0
- package/lattice_brain/embeddings.py +82 -0
- package/lattice_brain/identity.py +13 -0
- package/lattice_brain/ingest.py +1 -0
- package/lattice_brain/memory.py +3 -0
- package/lattice_brain/network.py +1 -0
- package/lattice_brain/projection.py +1 -0
- package/lattice_brain/provenance.py +1 -0
- package/lattice_brain/retrieval.py +1 -0
- package/lattice_brain/schema.py +1 -0
- package/lattice_brain/storage/__init__.py +22 -0
- package/lattice_brain/storage/base.py +72 -0
- package/lattice_brain/storage/docker.py +105 -0
- package/lattice_brain/storage/factory.py +31 -0
- package/lattice_brain/storage/migration.py +190 -0
- package/lattice_brain/storage/postgres.py +123 -0
- package/lattice_brain/storage/sqlite.py +128 -0
- package/lattice_brain/store.py +3 -0
- package/lattice_brain/write_master.py +1 -0
- package/latticeai/__init__.py +1 -1
- package/latticeai/api/portability.py +69 -0
- package/latticeai/api/setup.py +5 -4
- package/latticeai/api/static_routes.py +4 -4
- package/latticeai/app_factory.py +17 -10
- package/latticeai/brain/__init__.py +6 -6
- package/latticeai/brain/_kg_common.py +1 -1
- package/latticeai/brain/network.py +1 -1
- package/latticeai/brain/retrieval.py +15 -0
- package/latticeai/brain/store.py +22 -6
- package/latticeai/core/config.py +8 -0
- package/latticeai/core/marketplace.py +1 -1
- package/latticeai/core/multi_agent.py +1 -1
- package/latticeai/core/workspace_os.py +1 -1
- package/latticeai/services/kg_portability.py +82 -1
- package/package.json +55 -15
- package/scripts/build_frontend_assets.mjs +38 -0
- package/scripts/bump_version.py +4 -1
- package/scripts/export_openapi.py +31 -0
- package/scripts/lint_frontend.mjs +91 -0
- package/scripts/migrate_brain_storage.py +53 -0
- package/scripts/run_python.mjs +47 -0
- package/scripts/wheel_smoke.py +3 -0
- package/src-tauri/Cargo.lock +4833 -0
- package/src-tauri/Cargo.toml +19 -0
- package/src-tauri/build.rs +3 -0
- package/src-tauri/capabilities/default.json +7 -0
- package/src-tauri/src/main.rs +78 -0
- package/src-tauri/tauri.conf.json +39 -0
- package/static/app/asset-manifest.json +32 -0
- package/static/app/assets/core-CwxXejkd.js +2 -0
- package/static/app/assets/core-CwxXejkd.js.map +1 -0
- package/static/app/assets/index-CDjiH_se.css +2 -0
- package/static/app/assets/index-C_HAkbAg.js +333 -0
- package/static/app/assets/index-C_HAkbAg.js.map +1 -0
- package/static/app/index.html +25 -0
- package/static/manifest.json +2 -2
- package/static/sw.js +4 -4
- package/scripts/build_v3_assets.mjs +0 -170
- package/scripts/lint_v3.mjs +0 -120
- package/static/v3/asset-manifest.json +0 -63
- package/static/v3/css/lattice.base.49deefb5.css +0 -128
- package/static/v3/css/lattice.base.css +0 -128
- package/static/v3/css/lattice.components.cde18231.css +0 -472
- package/static/v3/css/lattice.components.css +0 -472
- package/static/v3/css/lattice.shell.29d36d85.css +0 -452
- package/static/v3/css/lattice.shell.css +0 -452
- package/static/v3/css/lattice.tokens.304cbc40.css +0 -135
- package/static/v3/css/lattice.tokens.css +0 -135
- package/static/v3/css/lattice.views.0a18b6c5.css +0 -360
- package/static/v3/css/lattice.views.css +0 -360
- package/static/v3/index.html +0 -68
- package/static/v3/js/app.c5c80c46.js +0 -26
- package/static/v3/js/app.js +0 -26
- package/static/v3/js/core/api.ba0fbf14.js +0 -625
- package/static/v3/js/core/api.js +0 -625
- package/static/v3/js/core/components.f25b3b93.js +0 -230
- package/static/v3/js/core/components.js +0 -230
- package/static/v3/js/core/dom.a2773eb0.js +0 -148
- package/static/v3/js/core/dom.js +0 -148
- package/static/v3/js/core/i18n.880e1fec.js +0 -575
- package/static/v3/js/core/i18n.js +0 -575
- package/static/v3/js/core/router.584570f2.js +0 -37
- package/static/v3/js/core/router.js +0 -37
- package/static/v3/js/core/routes.37522821.js +0 -101
- package/static/v3/js/core/routes.js +0 -101
- package/static/v3/js/core/shell.e3f6bbfa.js +0 -420
- package/static/v3/js/core/shell.js +0 -420
- package/static/v3/js/core/store.7b2aa044.js +0 -123
- package/static/v3/js/core/store.js +0 -123
- package/static/v3/js/views/account.eff40715.js +0 -143
- package/static/v3/js/views/account.js +0 -143
- package/static/v3/js/views/activity.0d271ef9.js +0 -67
- package/static/v3/js/views/activity.js +0 -67
- package/static/v3/js/views/admin-audit.660a1fb1.js +0 -185
- package/static/v3/js/views/admin-audit.js +0 -185
- package/static/v3/js/views/admin-permissions.a7ae5f09.js +0 -177
- package/static/v3/js/views/admin-permissions.js +0 -177
- package/static/v3/js/views/admin-policies.3658fd86.js +0 -102
- package/static/v3/js/views/admin-policies.js +0 -102
- package/static/v3/js/views/admin-private-vpc.7d342d36.js +0 -135
- package/static/v3/js/views/admin-private-vpc.js +0 -135
- package/static/v3/js/views/admin-security.07c66b72.js +0 -180
- package/static/v3/js/views/admin-security.js +0 -180
- package/static/v3/js/views/admin-users.f7ac7b43.js +0 -166
- package/static/v3/js/views/admin-users.js +0 -166
- package/static/v3/js/views/agents.17c5288d.js +0 -564
- package/static/v3/js/views/agents.js +0 -564
- package/static/v3/js/views/chat.e250e2cc.js +0 -624
- package/static/v3/js/views/chat.js +0 -624
- package/static/v3/js/views/files.adad14c1.js +0 -365
- package/static/v3/js/views/files.js +0 -365
- package/static/v3/js/views/graph-canvas.17c15d65.js +0 -509
- package/static/v3/js/views/graph-canvas.js +0 -509
- package/static/v3/js/views/home.24f8b8ae.js +0 -200
- package/static/v3/js/views/home.js +0 -200
- package/static/v3/js/views/hooks.37895880.js +0 -220
- package/static/v3/js/views/hooks.js +0 -220
- package/static/v3/js/views/hybrid-search.2fb63ed9.js +0 -194
- package/static/v3/js/views/hybrid-search.js +0 -194
- package/static/v3/js/views/knowledge-graph.4d09c537.js +0 -529
- package/static/v3/js/views/knowledge-graph.js +0 -529
- package/static/v3/js/views/marketplace.ab0583d4.js +0 -141
- package/static/v3/js/views/marketplace.js +0 -141
- package/static/v3/js/views/mcp.99b5c6a7.js +0 -114
- package/static/v3/js/views/mcp.js +0 -114
- package/static/v3/js/views/memory.4ebdf474.js +0 -147
- package/static/v3/js/views/memory.js +0 -147
- package/static/v3/js/views/models.a1ffa147.js +0 -256
- package/static/v3/js/views/models.js +0 -256
- package/static/v3/js/views/my-computer.d9d9ae1c.js +0 -463
- package/static/v3/js/views/my-computer.js +0 -463
- package/static/v3/js/views/network.52a4f181.js +0 -97
- package/static/v3/js/views/network.js +0 -97
- package/static/v3/js/views/pipeline.c522f1ce.js +0 -157
- package/static/v3/js/views/pipeline.js +0 -157
- package/static/v3/js/views/planning.4876fd77.js +0 -174
- package/static/v3/js/views/planning.js +0 -174
- package/static/v3/js/views/runs.b63b2afa.js +0 -144
- package/static/v3/js/views/runs.js +0 -144
- package/static/v3/js/views/settings.b7140634.js +0 -317
- package/static/v3/js/views/settings.js +0 -317
- package/static/v3/js/views/skills.c6c2f965.js +0 -109
- package/static/v3/js/views/skills.js +0 -109
- package/static/v3/js/views/snapshots.6f5db095.js +0 -135
- package/static/v3/js/views/snapshots.js +0 -135
- package/static/v3/js/views/tools.e4f11276.js +0 -108
- package/static/v3/js/views/tools.js +0 -108
- package/static/v3/js/views/workflows.7752225a.js +0 -213
- package/static/v3/js/views/workflows.js +0 -213
- package/static/v3/js/views/workspace-admin.c466029b.js +0 -156
- package/static/v3/js/views/workspace-admin.js +0 -156
|
@@ -28,6 +28,28 @@ class RestoreRequest(BaseModel):
|
|
|
28
28
|
verify: bool = True
|
|
29
29
|
|
|
30
30
|
|
|
31
|
+
class EncryptedArchiveRequest(BaseModel):
|
|
32
|
+
path: Optional[str] = None
|
|
33
|
+
passphrase: str
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class EncryptedRestoreRequest(BaseModel):
|
|
37
|
+
path: str
|
|
38
|
+
passphrase: str
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class DockerPostgresRequest(BaseModel):
|
|
42
|
+
consent: bool = False
|
|
43
|
+
dry_run: bool = False
|
|
44
|
+
port: int = 5432
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class SQLiteToPostgresRequest(BaseModel):
|
|
48
|
+
dsn: str
|
|
49
|
+
schema_name: str = "lattice_brain"
|
|
50
|
+
dry_run: bool = True
|
|
51
|
+
|
|
52
|
+
|
|
31
53
|
def create_portability_router(
|
|
32
54
|
*,
|
|
33
55
|
service: Any,
|
|
@@ -46,6 +68,12 @@ def create_portability_router(
|
|
|
46
68
|
_require_service()
|
|
47
69
|
return service.snapshot_metadata()
|
|
48
70
|
|
|
71
|
+
@router.get("/api/brain/storage")
|
|
72
|
+
async def brain_storage_status(request: Request):
|
|
73
|
+
require_user(request)
|
|
74
|
+
_require_service()
|
|
75
|
+
return service.storage_status()
|
|
76
|
+
|
|
49
77
|
@router.get("/api/knowledge-graph/provenance")
|
|
50
78
|
async def recent_provenance(request: Request, limit: int = 50, source_type: Optional[str] = None):
|
|
51
79
|
"""Recent ingestions (provenance trail) for the ingestion-sources UI."""
|
|
@@ -90,4 +118,45 @@ def create_portability_router(
|
|
|
90
118
|
except (ValueError, FileNotFoundError) as exc:
|
|
91
119
|
raise HTTPException(status_code=400, detail=str(exc))
|
|
92
120
|
|
|
121
|
+
@router.post("/api/knowledge-graph/archive")
|
|
122
|
+
async def encrypted_archive(req: EncryptedArchiveRequest, request: Request):
|
|
123
|
+
require_admin(request)
|
|
124
|
+
_require_service()
|
|
125
|
+
try:
|
|
126
|
+
return service.encrypted_archive(req.path, passphrase=req.passphrase)
|
|
127
|
+
except (ValueError, FileNotFoundError) as exc:
|
|
128
|
+
raise HTTPException(status_code=400, detail=str(exc))
|
|
129
|
+
|
|
130
|
+
@router.post("/api/knowledge-graph/archive/restore")
|
|
131
|
+
async def restore_encrypted_archive(req: EncryptedRestoreRequest, request: Request):
|
|
132
|
+
require_admin(request)
|
|
133
|
+
_require_service()
|
|
134
|
+
try:
|
|
135
|
+
return service.restore_encrypted_archive(req.path, passphrase=req.passphrase)
|
|
136
|
+
except (ValueError, FileNotFoundError) as exc:
|
|
137
|
+
raise HTTPException(status_code=400, detail=str(exc))
|
|
138
|
+
|
|
139
|
+
@router.post("/api/brain/storage/postgres/docker")
|
|
140
|
+
async def setup_postgres_docker(req: DockerPostgresRequest, request: Request):
|
|
141
|
+
require_admin(request)
|
|
142
|
+
_require_service()
|
|
143
|
+
return service.postgres_docker_setup(
|
|
144
|
+
consent=req.consent,
|
|
145
|
+
dry_run=req.dry_run,
|
|
146
|
+
port=req.port,
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
@router.post("/api/brain/storage/migrate-postgres")
|
|
150
|
+
async def migrate_sqlite_to_postgres(req: SQLiteToPostgresRequest, request: Request):
|
|
151
|
+
require_admin(request)
|
|
152
|
+
_require_service()
|
|
153
|
+
try:
|
|
154
|
+
return service.migrate_sqlite_to_postgres(
|
|
155
|
+
dsn=req.dsn,
|
|
156
|
+
schema=req.schema_name,
|
|
157
|
+
dry_run=req.dry_run,
|
|
158
|
+
)
|
|
159
|
+
except (ValueError, FileNotFoundError, RuntimeError) as exc:
|
|
160
|
+
raise HTTPException(status_code=400, detail=str(exc))
|
|
161
|
+
|
|
93
162
|
return router
|
package/latticeai/api/setup.py
CHANGED
|
@@ -19,15 +19,16 @@ from latticeai.models.router import parse_model_ref
|
|
|
19
19
|
from setup_wizard import get_recommendations, install_stream, open_url, scan_environment
|
|
20
20
|
|
|
21
21
|
|
|
22
|
+
class SetupInstallRequest(BaseModel):
|
|
23
|
+
items: List[Dict]
|
|
24
|
+
|
|
25
|
+
|
|
22
26
|
def create_setup_router(*, model_router, require_user) -> APIRouter:
|
|
23
27
|
api_router = APIRouter()
|
|
24
28
|
router = model_router
|
|
25
29
|
|
|
26
30
|
# ── Setup Wizard ─────────────────────────────────────────────────────────────
|
|
27
|
-
|
|
28
|
-
class SetupInstallRequest(BaseModel):
|
|
29
|
-
items: List[Dict]
|
|
30
|
-
|
|
31
|
+
|
|
31
32
|
def setup_auto_state() -> Dict[str, object]:
|
|
32
33
|
"""Return the PPT-aligned zero-config setup state used by setup UI/API."""
|
|
33
34
|
profile = auto_setup_probe()
|
|
@@ -84,7 +84,7 @@ def create_static_routes_router(
|
|
|
84
84
|
raise HTTPException(status_code=404)
|
|
85
85
|
return FileResponse(str(p), media_type="application/manifest+json")
|
|
86
86
|
|
|
87
|
-
@api_router.api_route("/favicon.ico", methods=["GET", "HEAD"])
|
|
87
|
+
@api_router.api_route("/favicon.ico", methods=["GET", "HEAD"], include_in_schema=False)
|
|
88
88
|
async def favicon():
|
|
89
89
|
ico = STATIC_DIR / "favicon.ico"
|
|
90
90
|
png = STATIC_DIR / "icons" / "favicon-32.png"
|
|
@@ -112,10 +112,10 @@ def create_static_routes_router(
|
|
|
112
112
|
|
|
113
113
|
@api_router.get("/app")
|
|
114
114
|
async def app_shell(request: Request):
|
|
115
|
-
"""
|
|
116
|
-
page = STATIC_DIR / "
|
|
115
|
+
"""React desktop single-page workspace shell."""
|
|
116
|
+
page = STATIC_DIR / "app" / "index.html"
|
|
117
117
|
if not page.exists():
|
|
118
|
-
raise HTTPException(status_code=404, detail="
|
|
118
|
+
raise HTTPException(status_code=404, detail="React shell not found.")
|
|
119
119
|
return ui_file_response(page)
|
|
120
120
|
|
|
121
121
|
|
package/latticeai/app_factory.py
CHANGED
|
@@ -60,7 +60,7 @@ def _build(config: "Optional[Config]" = None) -> Dict[str, Any]:
|
|
|
60
60
|
from pydantic import BaseModel
|
|
61
61
|
|
|
62
62
|
from latticeai.models.router import LLMRouter, normalize_branding
|
|
63
|
-
from knowledge_graph import
|
|
63
|
+
from knowledge_graph import set_llm_router
|
|
64
64
|
from local_knowledge_api import LocalKnowledgeWatcher
|
|
65
65
|
from latticeai.core.security import (
|
|
66
66
|
hash_password,
|
|
@@ -161,11 +161,12 @@ def _build(config: "Optional[Config]" = None) -> Dict[str, Any]:
|
|
|
161
161
|
from latticeai.api.portability import create_portability_router
|
|
162
162
|
from latticeai.services.memory_service import MemoryService
|
|
163
163
|
from latticeai.services.ingestion import IngestionItem, IngestionPipeline
|
|
164
|
-
from
|
|
165
|
-
from
|
|
166
|
-
from
|
|
167
|
-
from
|
|
168
|
-
from
|
|
164
|
+
from lattice_brain import BrainCore, ConversationStore
|
|
165
|
+
from lattice_brain.storage import storage_from_env
|
|
166
|
+
from lattice_brain.context import ContextAssembler
|
|
167
|
+
from lattice_brain.memory import BrainMemory
|
|
168
|
+
from lattice_brain.identity import DeviceIdentity
|
|
169
|
+
from lattice_brain.network import BrainNetwork
|
|
169
170
|
from latticeai.api.network import create_network_router
|
|
170
171
|
from latticeai.services.kg_portability import KGPortabilityService
|
|
171
172
|
# The aliased names below look unused but are part of the legacy
|
|
@@ -342,16 +343,22 @@ def _build(config: "Optional[Config]" = None) -> Dict[str, Any]:
|
|
|
342
343
|
)
|
|
343
344
|
if EMBEDDER.fell_back:
|
|
344
345
|
logging.warning("Embedding provider %s unavailable: %s", EMBEDDER.requested, EMBEDDER.detail)
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
DATA_DIR
|
|
346
|
+
STORAGE_ENGINE = storage_from_env(os.environ, data_dir=DATA_DIR) if ENABLE_GRAPH else None
|
|
347
|
+
BRAIN_CORE = BrainCore.from_paths(
|
|
348
|
+
DATA_DIR,
|
|
348
349
|
embedder=EMBEDDER.provider,
|
|
350
|
+
storage_engine=STORAGE_ENGINE,
|
|
349
351
|
) if ENABLE_GRAPH else None
|
|
352
|
+
KNOWLEDGE_GRAPH = BRAIN_CORE.knowledge if BRAIN_CORE is not None else None
|
|
350
353
|
# ── v4 durable conversation store: unbounded episodic memory in the same
|
|
351
354
|
# SQLite file as the graph (kg_portability backup/restore covers it for
|
|
352
355
|
# free). Legacy chat_history.json is imported once, idempotently, and the
|
|
353
356
|
# file is left untouched on disk as the import source.
|
|
354
|
-
CONVERSATIONS =
|
|
357
|
+
CONVERSATIONS = (
|
|
358
|
+
BRAIN_CORE.conversations
|
|
359
|
+
if BRAIN_CORE is not None
|
|
360
|
+
else ConversationStore(DATA_DIR / "knowledge_graph.sqlite")
|
|
361
|
+
)
|
|
355
362
|
CONVERSATIONS.import_legacy_json(HISTORY_FILE)
|
|
356
363
|
# Hooks registry is constructed here (ahead of the watcher) so folder-watch
|
|
357
364
|
# reindexes can fire the pre_index/post_index lifecycle hooks.
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
"""
|
|
2
|
-
|
|
3
|
-
v4 home for the brain's storage modules. The knowledge-graph store itself
|
|
4
|
-
still lives in the root ``knowledge_graph`` module pending its decomposition
|
|
5
|
-
(T3d); new brain components land here first.
|
|
6
|
-
"""
|
|
1
|
+
"""Compatibility namespace for the standalone :mod:`lattice_brain` package."""
|
|
7
2
|
|
|
3
|
+
from lattice_brain.core import BrainCore, BrainCoreConfig
|
|
8
4
|
from latticeai.brain.context import AssembledContext, ContextAssembler, ContextSection
|
|
9
5
|
from latticeai.brain.conversations import ConversationStore
|
|
10
6
|
from latticeai.brain.memory import BrainMemory
|
|
7
|
+
from latticeai.brain.store import KnowledgeGraphStore
|
|
11
8
|
|
|
12
9
|
__all__ = [
|
|
13
10
|
"AssembledContext",
|
|
11
|
+
"BrainCore",
|
|
12
|
+
"BrainCoreConfig",
|
|
14
13
|
"BrainMemory",
|
|
15
14
|
"ContextAssembler",
|
|
16
15
|
"ContextSection",
|
|
17
16
|
"ConversationStore",
|
|
17
|
+
"KnowledgeGraphStore",
|
|
18
18
|
]
|
|
@@ -33,7 +33,7 @@ except Exception: # pragma: no cover - v2 schema is optional at import time
|
|
|
33
33
|
EdgeType = None # type: ignore[assignment]
|
|
34
34
|
_exec_script = None # type: ignore[assignment]
|
|
35
35
|
|
|
36
|
-
from
|
|
36
|
+
from lattice_brain.embeddings import LocalEmbeddingModel
|
|
37
37
|
|
|
38
38
|
# Default read source for the graph queries: v2 reconstruction views.
|
|
39
39
|
# Override with LATTICEAI_KG_READ_V2=0 to fall back to the legacy tables.
|
|
@@ -23,7 +23,7 @@ import uuid
|
|
|
23
23
|
from pathlib import Path
|
|
24
24
|
from typing import Any, Dict, List, Optional
|
|
25
25
|
|
|
26
|
-
from
|
|
26
|
+
from lattice_brain.identity import DeviceIdentity, fingerprint_of, verify_signature
|
|
27
27
|
|
|
28
28
|
PEER_AUTH_WINDOW_SECONDS = 300
|
|
29
29
|
_NONCE_CACHE_MAX = 4096
|
|
@@ -813,6 +813,15 @@ class KnowledgeGraphRetrievalMixin:
|
|
|
813
813
|
raise
|
|
814
814
|
|
|
815
815
|
def index_status(self) -> Dict[str, Any]:
|
|
816
|
+
storage_capabilities = None
|
|
817
|
+
try:
|
|
818
|
+
storage_capabilities = self.storage_engine.capabilities().as_dict()
|
|
819
|
+
except Exception as exc:
|
|
820
|
+
storage_capabilities = {
|
|
821
|
+
"engine": "sqlite",
|
|
822
|
+
"available": False,
|
|
823
|
+
"reason": str(exc),
|
|
824
|
+
}
|
|
816
825
|
with self._connect() as conn:
|
|
817
826
|
vector_counts = {
|
|
818
827
|
row["item_type"]: row["count"]
|
|
@@ -864,6 +873,12 @@ class KnowledgeGraphRetrievalMixin:
|
|
|
864
873
|
# Honest capability report: trigram FTS5 keyword index, or
|
|
865
874
|
# LIKE-scan fallback when this SQLite build lacks it.
|
|
866
875
|
"fts_enabled": bool(getattr(self, "_fts_enabled", False)),
|
|
876
|
+
"engine": storage_capabilities,
|
|
877
|
+
"vector_search_backend": (
|
|
878
|
+
storage_capabilities.get("vector_backend")
|
|
879
|
+
if isinstance(storage_capabilities, dict)
|
|
880
|
+
else "bruteforce-cosine"
|
|
881
|
+
),
|
|
867
882
|
},
|
|
868
883
|
"source_items": len(source_items),
|
|
869
884
|
"indexed_items": sum(vector_counts.values()),
|
package/latticeai/brain/store.py
CHANGED
|
@@ -21,11 +21,31 @@ class KnowledgeGraphStore(
|
|
|
21
21
|
KnowledgeGraphDocumentsMixin,
|
|
22
22
|
KnowledgeGraphRetrievalMixin,
|
|
23
23
|
):
|
|
24
|
-
def __init__(
|
|
24
|
+
def __init__(
|
|
25
|
+
self,
|
|
26
|
+
db_path: Path,
|
|
27
|
+
blob_dir: Path,
|
|
28
|
+
embedder: Any = None,
|
|
29
|
+
storage_engine: Any = None,
|
|
30
|
+
):
|
|
25
31
|
self.db_path = Path(db_path)
|
|
26
32
|
self.blob_dir = Path(blob_dir)
|
|
27
33
|
self.db_path.parent.mkdir(parents=True, exist_ok=True)
|
|
28
34
|
self.blob_dir.mkdir(parents=True, exist_ok=True)
|
|
35
|
+
if storage_engine is None:
|
|
36
|
+
from lattice_brain.storage import SQLiteEngine
|
|
37
|
+
|
|
38
|
+
storage_engine = SQLiteEngine(self.db_path)
|
|
39
|
+
storage_caps = storage_engine.capabilities()
|
|
40
|
+
if not storage_caps.available:
|
|
41
|
+
raise RuntimeError(storage_caps.reason or "Brain storage is unavailable.")
|
|
42
|
+
if storage_caps.engine != "sqlite":
|
|
43
|
+
raise RuntimeError(
|
|
44
|
+
"KnowledgeGraphStore currently requires SQLiteEngine. "
|
|
45
|
+
"Explicit non-SQLite storage must use the migration/scale tooling; "
|
|
46
|
+
"no SQLite fallback is attempted."
|
|
47
|
+
)
|
|
48
|
+
self.storage_engine = storage_engine
|
|
29
49
|
# The embedder is swappable behind a fixed interface
|
|
30
50
|
# (model_id/dim/embed/encode/decode/similarity). Defaults to the
|
|
31
51
|
# deterministic, offline hash model so the store works with no config;
|
|
@@ -49,11 +69,7 @@ class KnowledgeGraphStore(
|
|
|
49
69
|
return ("nodes", "edges")
|
|
50
70
|
|
|
51
71
|
def _connect(self) -> sqlite3.Connection:
|
|
52
|
-
|
|
53
|
-
conn.row_factory = sqlite3.Row
|
|
54
|
-
conn.execute("PRAGMA journal_mode=WAL")
|
|
55
|
-
conn.execute("PRAGMA foreign_keys=ON")
|
|
56
|
-
return conn
|
|
72
|
+
return self.storage_engine.connect()
|
|
57
73
|
|
|
58
74
|
def _init_db(self) -> None:
|
|
59
75
|
with self._connect() as conn:
|
package/latticeai/core/config.py
CHANGED
|
@@ -104,6 +104,11 @@ class Config:
|
|
|
104
104
|
embedding_timeout: int
|
|
105
105
|
embedding_custom_target: str
|
|
106
106
|
|
|
107
|
+
# ── brain storage ───────────────────────────────────────────────
|
|
108
|
+
storage_engine: str
|
|
109
|
+
postgres_dsn: str
|
|
110
|
+
postgres_schema: str
|
|
111
|
+
|
|
107
112
|
# ── SSO / OIDC ──────────────────────────────────────────────────
|
|
108
113
|
sso_discovery_url: str
|
|
109
114
|
sso_client_id: str
|
|
@@ -185,6 +190,9 @@ class Config:
|
|
|
185
190
|
embedding_dim=_int(env, "LATTICEAI_VECTOR_DIM", 0),
|
|
186
191
|
embedding_timeout=_int(env, "LATTICEAI_EMBEDDING_TIMEOUT", 30),
|
|
187
192
|
embedding_custom_target=_value(env, "LATTICEAI_EMBEDDING_CUSTOM_TARGET", ""),
|
|
193
|
+
storage_engine=_value(env, "LATTICEAI_STORAGE_ENGINE", "sqlite").strip().lower() or "sqlite",
|
|
194
|
+
postgres_dsn=_value(env, "LATTICEAI_POSTGRES_DSN", ""),
|
|
195
|
+
postgres_schema=_value(env, "LATTICEAI_POSTGRES_SCHEMA", "lattice_brain"),
|
|
188
196
|
sso_discovery_url=_value(env, "OIDC_DISCOVERY_URL", ""),
|
|
189
197
|
sso_client_id=_value(env, "OIDC_CLIENT_ID", ""),
|
|
190
198
|
sso_client_secret=_value(env, "OIDC_CLIENT_SECRET", ""),
|
|
@@ -14,7 +14,7 @@ from datetime import datetime
|
|
|
14
14
|
from typing import Any, Callable, Dict, List, Optional
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
MULTI_AGENT_VERSION = "4.0
|
|
17
|
+
MULTI_AGENT_VERSION = "4.2.0"
|
|
18
18
|
|
|
19
19
|
AGENT_ROLES = ("researcher", "planner", "executor", "reviewer", "release")
|
|
20
20
|
CORE_PIPELINE = ("planner", "executor", "reviewer")
|
|
@@ -19,7 +19,7 @@ from pathlib import Path
|
|
|
19
19
|
from typing import Any, Callable, Dict, Iterable, List, Optional
|
|
20
20
|
|
|
21
21
|
|
|
22
|
-
WORKSPACE_OS_VERSION = "4.0
|
|
22
|
+
WORKSPACE_OS_VERSION = "4.2.0"
|
|
23
23
|
|
|
24
24
|
# Workspace types separate single-user Personal workspaces from shared
|
|
25
25
|
# Organization workspaces. Both keep the same local-first JSON store; the type
|
|
@@ -22,6 +22,13 @@ from datetime import datetime, timezone
|
|
|
22
22
|
from pathlib import Path
|
|
23
23
|
from typing import Any, Dict, Optional
|
|
24
24
|
|
|
25
|
+
from lattice_brain.archive import BrainArchivePaths, EncryptedBrainArchive
|
|
26
|
+
from lattice_brain.storage import (
|
|
27
|
+
DockerPostgresWizard,
|
|
28
|
+
PostgresEngine,
|
|
29
|
+
SQLiteToPostgresMigrator,
|
|
30
|
+
)
|
|
31
|
+
|
|
25
32
|
FORMAT = "latticeai.kg.export"
|
|
26
33
|
FORMAT_VERSION = 1
|
|
27
34
|
BACKUP_FORMAT = "latticeai.kg.backup"
|
|
@@ -95,7 +102,7 @@ class KGPortabilityService:
|
|
|
95
102
|
origin = "unsigned-legacy"
|
|
96
103
|
signature = artifact.get("signature")
|
|
97
104
|
if signature:
|
|
98
|
-
from
|
|
105
|
+
from lattice_brain.identity import verify_manifest
|
|
99
106
|
|
|
100
107
|
if not verify_manifest(artifact.get("header") or {}, signature):
|
|
101
108
|
raise ValueError("Bundle signature verification failed — refusing to import.")
|
|
@@ -189,6 +196,36 @@ class KGPortabilityService:
|
|
|
189
196
|
"nodes": sum(stats.get("nodes", {}).values()),
|
|
190
197
|
}
|
|
191
198
|
|
|
199
|
+
# ── encrypted .latticebrain archive ───────────────────────────────────
|
|
200
|
+
def encrypted_archive(self, dest_path=None, *, passphrase: str) -> Dict[str, Any]:
|
|
201
|
+
self._require()
|
|
202
|
+
self._exports_dir.mkdir(parents=True, exist_ok=True)
|
|
203
|
+
dest = Path(dest_path) if dest_path else self._exports_dir / f"brain-{_stamp()}.latticebrain"
|
|
204
|
+
archive = EncryptedBrainArchive(
|
|
205
|
+
BrainArchivePaths(
|
|
206
|
+
db_path=Path(self._kg.db_path),
|
|
207
|
+
blob_dir=Path(self._kg.blob_dir),
|
|
208
|
+
)
|
|
209
|
+
)
|
|
210
|
+
return archive.create(dest, passphrase=passphrase)
|
|
211
|
+
|
|
212
|
+
def restore_encrypted_archive(self, archive_path, *, passphrase: str) -> Dict[str, Any]:
|
|
213
|
+
self._require()
|
|
214
|
+
archive = EncryptedBrainArchive(
|
|
215
|
+
BrainArchivePaths(
|
|
216
|
+
db_path=Path(self._kg.db_path),
|
|
217
|
+
blob_dir=Path(self._kg.blob_dir),
|
|
218
|
+
)
|
|
219
|
+
)
|
|
220
|
+
return archive.restore(
|
|
221
|
+
Path(archive_path),
|
|
222
|
+
passphrase=passphrase,
|
|
223
|
+
target=BrainArchivePaths(
|
|
224
|
+
db_path=Path(self._kg.db_path),
|
|
225
|
+
blob_dir=Path(self._kg.blob_dir),
|
|
226
|
+
),
|
|
227
|
+
)
|
|
228
|
+
|
|
192
229
|
# ── status surface ───────────────────────────────────────────────────────
|
|
193
230
|
def snapshot_metadata(self) -> Dict[str, Any]:
|
|
194
231
|
if not self.available():
|
|
@@ -198,8 +235,52 @@ class KGPortabilityService:
|
|
|
198
235
|
**self._kg.schema_versions(),
|
|
199
236
|
"stats": self._kg.stats(),
|
|
200
237
|
"provenance": self._kg.provenance_stats(),
|
|
238
|
+
"storage": (
|
|
239
|
+
self._kg.storage_engine.capabilities().as_dict()
|
|
240
|
+
if getattr(self._kg, "storage_engine", None) is not None
|
|
241
|
+
else {"engine": "sqlite", "available": True}
|
|
242
|
+
),
|
|
201
243
|
}
|
|
202
244
|
|
|
245
|
+
def storage_status(self) -> Dict[str, Any]:
|
|
246
|
+
if not self.available():
|
|
247
|
+
return {"available": False}
|
|
248
|
+
return {
|
|
249
|
+
"available": True,
|
|
250
|
+
"active": (
|
|
251
|
+
self._kg.storage_engine.capabilities().as_dict()
|
|
252
|
+
if getattr(self._kg, "storage_engine", None) is not None
|
|
253
|
+
else {"engine": "sqlite", "available": True}
|
|
254
|
+
),
|
|
255
|
+
"postgres": PostgresEngine("", schema="lattice_brain").capabilities().as_dict(),
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
def postgres_docker_setup(
|
|
259
|
+
self,
|
|
260
|
+
*,
|
|
261
|
+
consent: bool,
|
|
262
|
+
dry_run: bool = False,
|
|
263
|
+
port: int = 5432,
|
|
264
|
+
) -> Dict[str, Any]:
|
|
265
|
+
wizard = DockerPostgresWizard(self._data_dir / "postgres", port=port)
|
|
266
|
+
return wizard.start(consent=consent, dry_run=dry_run)
|
|
267
|
+
|
|
268
|
+
def migrate_sqlite_to_postgres(
|
|
269
|
+
self,
|
|
270
|
+
*,
|
|
271
|
+
dsn: str,
|
|
272
|
+
schema: str = "lattice_brain",
|
|
273
|
+
dry_run: bool = True,
|
|
274
|
+
) -> Dict[str, Any]:
|
|
275
|
+
self._require()
|
|
276
|
+
if not dsn:
|
|
277
|
+
raise ValueError("Postgres DSN is required for SQLite to Postgres migration.")
|
|
278
|
+
migrator = SQLiteToPostgresMigrator(
|
|
279
|
+
Path(self._kg.db_path),
|
|
280
|
+
PostgresEngine(dsn, schema=schema),
|
|
281
|
+
)
|
|
282
|
+
return migrator.migrate(dry_run=dry_run)
|
|
283
|
+
|
|
203
284
|
def recent_ingestions(self, *, limit: int = 50, source_type: Optional[str] = None) -> Dict[str, Any]:
|
|
204
285
|
"""Recent provenance records (newest first) for the ingestion-sources UI."""
|
|
205
286
|
if not self.available():
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ltcai",
|
|
3
|
-
"version": "4.0
|
|
3
|
+
"version": "4.2.0",
|
|
4
4
|
"description": "Lattice AI — local-first Digital Brain Platform (knowledge graph, durable memory, hybrid search, agents, signed brain exchange)",
|
|
5
5
|
"homepage": "https://github.com/TaeSooPark-PTS/LatticeAI#readme",
|
|
6
6
|
"repository": {
|
|
@@ -18,29 +18,36 @@
|
|
|
18
18
|
"start": "LTCAI",
|
|
19
19
|
"dev": "python3 ltcai_cli.py --reload",
|
|
20
20
|
"build": "npm run build:assets && npm run build:python",
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
21
|
+
"frontend:dev": "vite --host 127.0.0.1",
|
|
22
|
+
"frontend:openapi": "node scripts/run_python.mjs scripts/export_openapi.py frontend/openapi.json && npx openapi-typescript frontend/openapi.json -o frontend/src/api/openapi.ts",
|
|
23
|
+
"build:assets": "vite build && node scripts/build_frontend_assets.mjs",
|
|
24
|
+
"build:python": "node scripts/run_python.mjs -m build",
|
|
25
|
+
"check:python": "node scripts/run_python.mjs scripts/check_python.py",
|
|
26
|
+
"lint": "node --check tests/visual/mock_server.cjs && node --check tests/visual/v3.spec.js && npm run lint:frontend",
|
|
27
|
+
"lint:frontend": "node scripts/lint_frontend.mjs",
|
|
28
|
+
"typecheck": "npm run typecheck:frontend && cd vscode-extension && npm run build",
|
|
29
|
+
"typecheck:frontend": "npx tsc -p tsconfig.json --noEmit",
|
|
30
|
+
"test": "node scripts/run_python.mjs -m pytest tests/ -v",
|
|
31
|
+
"test:unit": "node scripts/run_python.mjs -m pytest tests/unit/ -v",
|
|
32
|
+
"test:integration": "node scripts/run_python.mjs -m pytest tests/integration/ -v",
|
|
30
33
|
"test:visual": "playwright test",
|
|
31
34
|
"capture:workspace": "node scripts/capture/capture_workspace.js",
|
|
32
35
|
"capture:graph": "node scripts/capture/capture_graph.js",
|
|
33
36
|
"capture:skills": "node scripts/capture/capture_skills.js",
|
|
34
37
|
"capture:enterprise": "node scripts/capture/capture_enterprise.js",
|
|
35
38
|
"capture:onboarding": "node scripts/capture/capture_onboarding.js",
|
|
39
|
+
"desktop:tauri": "tauri dev",
|
|
40
|
+
"desktop:tauri:build": "tauri build",
|
|
41
|
+
"desktop:tauri:check": "cd src-tauri && cargo check",
|
|
42
|
+
"desktop:electron": "electron desktop/electron/main.cjs",
|
|
36
43
|
"package:vsix": "node scripts/build_vsix.mjs",
|
|
37
44
|
"release:artifacts": "npm run build:assets && npm run build:python && npm pack && npm run package:vsix",
|
|
38
|
-
"release:validate": "
|
|
45
|
+
"release:validate": "node scripts/run_python.mjs scripts/validate_release_artifacts.py $npm_package_version --require-vsix --require-tgz",
|
|
39
46
|
"publish:npm": "npm pack && npm publish ltcai-$npm_package_version.tgz --access public",
|
|
40
|
-
"publish:pypi": "npm run build:python &&
|
|
47
|
+
"publish:pypi": "npm run build:python && node scripts/run_python.mjs -m twine upload --skip-existing dist/ltcai-$npm_package_version.tar.gz dist/ltcai-$npm_package_version-py3-none-any.whl",
|
|
41
48
|
"publish:vscode": "cd vscode-extension && npm run package:vsix && npm run publish:vscode",
|
|
42
49
|
"publish:openvsx": "cd vscode-extension && npm run package:vsix && npm run publish:openvsx",
|
|
43
|
-
"publish:all": "npm run release:artifacts && npm run release:validate && npm publish ltcai-$npm_package_version.tgz --access public &&
|
|
50
|
+
"publish:all": "npm run release:artifacts && npm run release:validate && npm publish ltcai-$npm_package_version.tgz --access public && node scripts/run_python.mjs -m twine upload --skip-existing dist/ltcai-$npm_package_version.tar.gz dist/ltcai-$npm_package_version-py3-none-any.whl && cd vscode-extension && npm run publish:vscode && npm run publish:openvsx"
|
|
44
51
|
},
|
|
45
52
|
"keywords": [
|
|
46
53
|
"ltcai",
|
|
@@ -73,12 +80,14 @@
|
|
|
73
80
|
"tools/",
|
|
74
81
|
"mcp_registry.py",
|
|
75
82
|
"latticeai/**/*.py",
|
|
83
|
+
"lattice_brain/**/*.py",
|
|
76
84
|
"skills/",
|
|
77
85
|
"static/favicon.ico",
|
|
78
86
|
"static/manifest.json",
|
|
79
87
|
"static/sw.js",
|
|
80
88
|
"static/css/",
|
|
81
|
-
"
|
|
89
|
+
"frontend/",
|
|
90
|
+
"static/app/",
|
|
82
91
|
"static/icons/",
|
|
83
92
|
"plugins/",
|
|
84
93
|
"scripts/",
|
|
@@ -89,6 +98,12 @@
|
|
|
89
98
|
"setup_wizard.py",
|
|
90
99
|
"knowledge_graph_api.py",
|
|
91
100
|
"static/vendor/",
|
|
101
|
+
"src-tauri/",
|
|
102
|
+
"!src-tauri/gen/",
|
|
103
|
+
"!src-tauri/gen/**",
|
|
104
|
+
"!src-tauri/target/",
|
|
105
|
+
"!src-tauri/target/**",
|
|
106
|
+
"desktop/electron/",
|
|
92
107
|
"docs/*.md",
|
|
93
108
|
"!docs/assets/",
|
|
94
109
|
"!docs/images/"
|
|
@@ -97,6 +112,31 @@
|
|
|
97
112
|
"access": "public"
|
|
98
113
|
},
|
|
99
114
|
"devDependencies": {
|
|
100
|
-
"@playwright/test": "^1.60.0"
|
|
115
|
+
"@playwright/test": "^1.60.0",
|
|
116
|
+
"@tailwindcss/postcss": "^4.3.0",
|
|
117
|
+
"@tanstack/react-query": "^5.101.0",
|
|
118
|
+
"@tauri-apps/api": "^2.0.0",
|
|
119
|
+
"@tauri-apps/cli": "^2.0.0",
|
|
120
|
+
"@types/cytoscape": "^3.21.9",
|
|
121
|
+
"@types/react": "^19.2.17",
|
|
122
|
+
"@types/react-dom": "^19.2.3",
|
|
123
|
+
"@vitejs/plugin-react": "^6.0.2",
|
|
124
|
+
"autoprefixer": "^10.5.0",
|
|
125
|
+
"class-variance-authority": "^0.7.1",
|
|
126
|
+
"clsx": "^2.1.1",
|
|
127
|
+
"cytoscape": "^3.34.0",
|
|
128
|
+
"electron": "^42.4.0",
|
|
129
|
+
"lucide-react": "^1.17.0",
|
|
130
|
+
"openapi-fetch": "^0.17.0",
|
|
131
|
+
"openapi-typescript": "^7.13.0",
|
|
132
|
+
"postcss": "^8.5.15",
|
|
133
|
+
"react": "^19.2.7",
|
|
134
|
+
"react-dom": "^19.2.7",
|
|
135
|
+
"reactflow": "^11.11.4",
|
|
136
|
+
"tailwind-merge": "^3.6.0",
|
|
137
|
+
"tailwindcss": "^4.3.0",
|
|
138
|
+
"typescript": "^5.9.3",
|
|
139
|
+
"vite": "^8.0.16",
|
|
140
|
+
"zustand": "^5.0.14"
|
|
101
141
|
}
|
|
102
142
|
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
|
|
5
|
+
const repo = join(import.meta.dirname, "..");
|
|
6
|
+
const appDir = join(repo, "static", "app");
|
|
7
|
+
const nestedViteManifest = join(appDir, ".vite", "asset-manifest.json");
|
|
8
|
+
const publicManifest = join(appDir, "asset-manifest.json");
|
|
9
|
+
const pkg = JSON.parse(readFileSync(join(repo, "package.json"), "utf8"));
|
|
10
|
+
|
|
11
|
+
const viteManifest = existsSync(nestedViteManifest) ? nestedViteManifest : publicManifest;
|
|
12
|
+
if (!existsSync(viteManifest)) {
|
|
13
|
+
console.error("Vite manifest missing. Run `vite build` before build_frontend_assets.mjs.");
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const raw = JSON.parse(readFileSync(viteManifest, "utf8"));
|
|
18
|
+
const assets = {};
|
|
19
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
20
|
+
if (value && typeof value === "object") {
|
|
21
|
+
if (value.file) assets[key] = `/static/app/${value.file}`;
|
|
22
|
+
for (const css of value.css || []) assets[css] = `/static/app/${css}`;
|
|
23
|
+
for (const asset of value.assets || []) assets[asset] = `/static/app/${asset}`;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const manifest = {
|
|
28
|
+
version: pkg.version,
|
|
29
|
+
generated_at: "vite",
|
|
30
|
+
entrypoints: {
|
|
31
|
+
app: assets["frontend/index.html"] || "/static/app/index.html",
|
|
32
|
+
},
|
|
33
|
+
assets,
|
|
34
|
+
vite: raw,
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
writeFileSync(publicManifest, JSON.stringify(manifest, null, 2) + "\n", "utf8");
|
|
38
|
+
console.log(`wrote static/app/asset-manifest.json with ${Object.keys(assets).length} assets`);
|
package/scripts/bump_version.py
CHANGED
|
@@ -23,6 +23,7 @@ REPO = Path(__file__).resolve().parents[1]
|
|
|
23
23
|
# (path, kind, pattern) — pattern groups: (prefix, version)
|
|
24
24
|
TARGETS = [
|
|
25
25
|
("latticeai/__init__.py", "regex", r'(__version__ = ")([^"]+)(")'),
|
|
26
|
+
("lattice_brain/__init__.py", "regex", r'(__version__ = ")([^"]+)(")'),
|
|
26
27
|
("latticeai/core/workspace_os.py", "regex", r'(WORKSPACE_OS_VERSION = ")([^"]+)(")'),
|
|
27
28
|
("latticeai/core/marketplace.py", "regex", r'(MARKETPLACE_VERSION = ")([^"]+)(")'),
|
|
28
29
|
("latticeai/core/multi_agent.py", "regex", r'(MULTI_AGENT_VERSION = ")([^"]+)(")'),
|
|
@@ -31,7 +32,9 @@ TARGETS = [
|
|
|
31
32
|
("package-lock.json", "package-lock", None),
|
|
32
33
|
("vscode-extension/package.json", "json", "version"),
|
|
33
34
|
("vscode-extension/package-lock.json", "package-lock", None),
|
|
34
|
-
("
|
|
35
|
+
("src-tauri/Cargo.toml", "regex", r'(^version = ")([^"]+)(")'),
|
|
36
|
+
("src-tauri/tauri.conf.json", "json", "version"),
|
|
37
|
+
("static/app/asset-manifest.json", "json", "version"),
|
|
35
38
|
]
|
|
36
39
|
|
|
37
40
|
|