ltcai 3.4.0 → 3.5.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 +175 -225
- package/docs/RUNTIME_HOOK_COVERAGE_v3.5.0.md +56 -0
- package/docs/assets/v3.4.1/e2e_runtime_log.txt +42 -0
- package/docs/assets/v3.4.1/hooks-dispatch.png +0 -0
- package/docs/assets/v3.4.1/local-agent.png +0 -0
- package/latticeai/__init__.py +1 -1
- package/latticeai/api/auth.py +37 -9
- package/latticeai/api/chat.py +6 -1
- package/latticeai/api/computer_use.py +21 -8
- package/latticeai/api/local_files.py +76 -10
- package/latticeai/api/tools.py +35 -35
- package/latticeai/core/agent.py +13 -2
- package/latticeai/core/builtin_hooks.py +106 -0
- package/latticeai/core/config.py +3 -0
- package/latticeai/core/hooks.py +76 -2
- package/latticeai/core/marketplace.py +1 -1
- package/latticeai/core/multi_agent.py +1 -1
- package/latticeai/core/oidc.py +205 -0
- package/latticeai/core/security.py +59 -5
- package/latticeai/core/workflow_engine.py +3 -3
- package/latticeai/core/workspace_os.py +1 -1
- package/latticeai/server_app.py +22 -34
- package/latticeai/services/platform_runtime.py +18 -6
- package/latticeai/services/tool_dispatch.py +2 -0
- package/latticeai/services/upload_service.py +24 -4
- package/local_knowledge_api.py +27 -1
- package/package.json +3 -3
- package/requirements.txt +1 -0
- package/scripts/check_python.py +87 -0
- package/static/css/reference/account.css +1 -1
- package/static/css/reference/admin.css +1 -1
- package/static/css/reference/base.css +8 -5
- package/static/css/reference/chat.css +8 -8
- package/static/css/reference/graph.css +2 -2
- package/static/css/responsive.css +2 -2
- package/static/v3/asset-manifest.json +9 -9
- package/static/v3/css/{lattice.shell.6ceea7c8.css → lattice.shell.8fcc9d33.css} +2 -1
- package/static/v3/css/lattice.shell.css +2 -1
- package/static/v3/js/{app.c4acfdd8.js → app.d086489d.js} +1 -1
- package/static/v3/js/core/{components.35f02e4c.js → components.f25b3b93.js} +1 -1
- package/static/v3/js/core/components.js +1 -1
- package/static/v3/js/core/{shell.80a6ad82.js → shell.d05266f5.js} +1 -1
- package/static/v3/js/views/{hooks.13845954.js → hooks.37895880.js} +12 -7
- package/static/v3/js/views/hooks.js +12 -7
- package/static/v3/js/views/{my-computer.c3ef5283.js → my-computer.d9d9ae1c.js} +7 -4
- package/static/v3/js/views/my-computer.js +7 -4
- package/static/workspace.css +1 -1
- package/tools/__init__.py +276 -0
- package/tools/commands.py +188 -0
- package/tools/computer.py +185 -0
- package/tools/documents.py +243 -0
- package/tools/filesystem.py +560 -0
- package/tools/knowledge.py +97 -0
- package/tools/local_files.py +69 -0
- package/tools/network.py +66 -0
- package/tools.py +0 -1525
|
@@ -37,6 +37,16 @@ async def process_uploaded_document(
|
|
|
37
37
|
if not bytes_match_extension(contents, suffix):
|
|
38
38
|
raise HTTPException(status_code=400, detail=f"파일 내용이 확장자({suffix})와 일치하지 않습니다.")
|
|
39
39
|
|
|
40
|
+
# ── pre_upload hook ── may gate the upload before any work happens.
|
|
41
|
+
if hooks is not None:
|
|
42
|
+
pre_up = hooks.fire_hook(
|
|
43
|
+
"pre_upload", "document.upload",
|
|
44
|
+
payload={"filename": file.filename, "ext": suffix, "bytes": len(contents)},
|
|
45
|
+
user_email=current_user,
|
|
46
|
+
)
|
|
47
|
+
if pre_up.get("blocked"):
|
|
48
|
+
raise HTTPException(status_code=403, detail=pre_up.get("block_reason") or "Upload blocked by a pre_upload hook.")
|
|
49
|
+
|
|
40
50
|
with tempfile.NamedTemporaryFile(suffix=suffix, delete=False) as tmp:
|
|
41
51
|
tmp.write(contents)
|
|
42
52
|
tmp_path = tmp.name
|
|
@@ -52,6 +62,12 @@ async def process_uploaded_document(
|
|
|
52
62
|
},
|
|
53
63
|
-1,
|
|
54
64
|
)
|
|
65
|
+
# ── pre_index / post_index hooks bracket the KG ingest (chunk → embed →
|
|
66
|
+
# graph-build), the actual indexing step.
|
|
67
|
+
if hooks is not None:
|
|
68
|
+
hooks.fire_hook("pre_index", "document.index",
|
|
69
|
+
payload={"filename": file.filename, "chars": result.get("chars")},
|
|
70
|
+
user_email=current_user)
|
|
55
71
|
try:
|
|
56
72
|
if not (enable_graph and knowledge_graph):
|
|
57
73
|
raise RuntimeError("graph disabled")
|
|
@@ -70,6 +86,12 @@ async def process_uploaded_document(
|
|
|
70
86
|
except Exception as graph_error:
|
|
71
87
|
logging.warning("knowledge graph document ingest failed: %s", graph_error)
|
|
72
88
|
result["knowledge_graph"] = {"error": str(graph_error)}
|
|
89
|
+
if hooks is not None:
|
|
90
|
+
_kg = result.get("knowledge_graph") or {}
|
|
91
|
+
hooks.fire_hook("post_index", "document.index",
|
|
92
|
+
payload={"filename": file.filename, "graph_node": _kg.get("node_id"),
|
|
93
|
+
"indexed": bool(_kg.get("node_id")), "error": _kg.get("error")},
|
|
94
|
+
user_email=current_user)
|
|
73
95
|
|
|
74
96
|
append_audit_event(
|
|
75
97
|
"document_upload",
|
|
@@ -93,13 +115,11 @@ async def process_uploaded_document(
|
|
|
93
115
|
except OSError:
|
|
94
116
|
pass
|
|
95
117
|
|
|
96
|
-
# ──
|
|
97
|
-
# this document; fire the pipeline lifecycle hooks so downstream automation
|
|
98
|
-
# (index-status publishing, custom reindex triggers) executes.
|
|
118
|
+
# ── post_upload hook ── the whole upload → parse → index pipeline finished.
|
|
99
119
|
if hooks is not None:
|
|
100
120
|
kg = result.get("knowledge_graph") or {}
|
|
101
121
|
hooks.fire_hook(
|
|
102
|
-
"
|
|
122
|
+
"post_upload", "document.uploaded",
|
|
103
123
|
payload={
|
|
104
124
|
"filename": file.filename,
|
|
105
125
|
"chars": result.get("chars"),
|
package/local_knowledge_api.py
CHANGED
|
@@ -51,9 +51,10 @@ class _LocalWatchHandler:
|
|
|
51
51
|
class LocalKnowledgeWatcher:
|
|
52
52
|
"""Debounced watchdog wrapper for approved local knowledge sources."""
|
|
53
53
|
|
|
54
|
-
def __init__(self, get_graph: Callable[[], Any], *, debounce_seconds: float = 5.0):
|
|
54
|
+
def __init__(self, get_graph: Callable[[], Any], *, debounce_seconds: float = 5.0, hooks: Any = None):
|
|
55
55
|
self._get_graph = get_graph
|
|
56
56
|
self._debounce_seconds = debounce_seconds
|
|
57
|
+
self._hooks = hooks
|
|
57
58
|
self._lock = threading.Lock()
|
|
58
59
|
self._watched: Dict[str, Dict[str, Any]] = {}
|
|
59
60
|
self._observer_cls = None
|
|
@@ -187,6 +188,10 @@ class LocalKnowledgeWatcher:
|
|
|
187
188
|
if graph is None:
|
|
188
189
|
return
|
|
189
190
|
consent = source.get("consent") or {}
|
|
191
|
+
root = source.get("root_path")
|
|
192
|
+
if self._hooks is not None:
|
|
193
|
+
self._hooks.fire_hook("pre_index", "folder.reindex",
|
|
194
|
+
payload={"source_id": source_id, "root_path": root, "trigger": "watch"})
|
|
190
195
|
try:
|
|
191
196
|
graph.index_local_folder(
|
|
192
197
|
Path(source["root_path"]),
|
|
@@ -199,11 +204,17 @@ class LocalKnowledgeWatcher:
|
|
|
199
204
|
if source_id in self._watched:
|
|
200
205
|
self._watched[source_id]["last_indexed_at"] = _now_seconds()
|
|
201
206
|
self._watched[source_id]["last_error"] = None
|
|
207
|
+
if self._hooks is not None:
|
|
208
|
+
self._hooks.fire_hook("post_index", "folder.reindex",
|
|
209
|
+
payload={"source_id": source_id, "root_path": root, "trigger": "watch", "status": "ok"})
|
|
202
210
|
except Exception as exc:
|
|
203
211
|
logging.warning("local knowledge watcher reindex failed for %s: %s", source_id, exc)
|
|
204
212
|
with self._lock:
|
|
205
213
|
if source_id in self._watched:
|
|
206
214
|
self._watched[source_id]["last_error"] = str(exc)
|
|
215
|
+
if self._hooks is not None:
|
|
216
|
+
self._hooks.fire_hook("post_index", "folder.reindex",
|
|
217
|
+
payload={"source_id": source_id, "root_path": root, "trigger": "watch", "status": "error", "error": str(exc)})
|
|
207
218
|
|
|
208
219
|
|
|
209
220
|
def _now_seconds() -> float:
|
|
@@ -221,6 +232,7 @@ def create_local_knowledge_router(
|
|
|
221
232
|
local_permission_response: Callable[..., dict],
|
|
222
233
|
require_local_approval: Callable[..., None],
|
|
223
234
|
watcher: Optional[LocalKnowledgeWatcher] = None,
|
|
235
|
+
hooks: Any = None,
|
|
224
236
|
) -> APIRouter:
|
|
225
237
|
router = APIRouter()
|
|
226
238
|
|
|
@@ -293,6 +305,10 @@ def create_local_knowledge_router(
|
|
|
293
305
|
if not req.approved:
|
|
294
306
|
return local_permission_response(req.path, "read", current_user)
|
|
295
307
|
require_local_approval(token=req.approval_token, path=req.path, action="read", user_email=current_user)
|
|
308
|
+
if hooks is not None:
|
|
309
|
+
hooks.fire_hook("pre_index", "folder.index",
|
|
310
|
+
payload={"root_path": req.path, "trigger": "connect", "watch": req.watch_enabled},
|
|
311
|
+
user_email=current_user)
|
|
296
312
|
try:
|
|
297
313
|
result = kg.index_local_folder(
|
|
298
314
|
Path(req.path),
|
|
@@ -303,7 +319,17 @@ def create_local_knowledge_router(
|
|
|
303
319
|
max_files=req.max_files,
|
|
304
320
|
)
|
|
305
321
|
except ValueError as exc:
|
|
322
|
+
if hooks is not None:
|
|
323
|
+
hooks.fire_hook("post_index", "folder.index",
|
|
324
|
+
payload={"root_path": req.path, "trigger": "connect", "status": "error", "error": str(exc)},
|
|
325
|
+
user_email=current_user)
|
|
306
326
|
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
|
327
|
+
if hooks is not None:
|
|
328
|
+
_idx = (result.get("index") or {}) if isinstance(result, dict) else {}
|
|
329
|
+
hooks.fire_hook("post_index", "folder.index",
|
|
330
|
+
payload={"root_path": req.path, "trigger": "connect", "status": "ok",
|
|
331
|
+
"indexed": _idx.get("indexed") or (result or {}).get("indexed")},
|
|
332
|
+
user_email=current_user)
|
|
307
333
|
|
|
308
334
|
if watcher:
|
|
309
335
|
if req.watch_enabled:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ltcai",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.5.0",
|
|
4
4
|
"description": "Lattice AI v3 local-first AI workspace platform with knowledge graph, vector index, hybrid search, agents, and workspace modes.",
|
|
5
5
|
"homepage": "https://github.com/TaeSooPark-PTS/LatticeAI#readme",
|
|
6
6
|
"repository": {
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"build": "npm run build:assets && npm run build:python",
|
|
21
21
|
"build:assets": "node scripts/build_v3_assets.mjs",
|
|
22
22
|
"build:python": "python3 -m build",
|
|
23
|
-
"check:python": "python3
|
|
23
|
+
"check:python": "python3 scripts/check_python.py",
|
|
24
24
|
"lint": "node --check static/scripts/account.js && node --check static/scripts/admin.js && node --check static/scripts/chat.js && node --check static/scripts/graph.js && node --check static/scripts/platform.js && node --check static/scripts/ux.js && node --check static/scripts/workspace.js && node --check tests/visual/mock_server.cjs && node --check tests/visual/v3.spec.js && npm run lint:v3",
|
|
25
25
|
"lint:v3": "node scripts/lint_v3.mjs",
|
|
26
26
|
"typecheck": "cd vscode-extension && npm run build",
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
"llm_router.py",
|
|
71
71
|
"p_reinforce.py",
|
|
72
72
|
"telegram_bot.py",
|
|
73
|
-
"tools
|
|
73
|
+
"tools/",
|
|
74
74
|
"codex_telegram_bot.py",
|
|
75
75
|
"mcp_registry.py",
|
|
76
76
|
"latticeai/**/*.py",
|
package/requirements.txt
CHANGED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Discover-and-compile every first-party Python module.
|
|
3
|
+
|
|
4
|
+
Replaces the hand-maintained ``py_compile`` enumeration in CI and
|
|
5
|
+
``package.json``: walks the repository, skips vendored / virtualenv / build /
|
|
6
|
+
cache / generated directories, and byte-compiles everything that remains. New
|
|
7
|
+
modules are picked up automatically — there is nothing to update when a file is
|
|
8
|
+
added, so the syntax gate can never silently fall behind the codebase.
|
|
9
|
+
|
|
10
|
+
Usage::
|
|
11
|
+
|
|
12
|
+
python scripts/check_python.py # compile all discovered modules
|
|
13
|
+
python scripts/check_python.py --list # just print what would be compiled
|
|
14
|
+
|
|
15
|
+
Exit code is non-zero if any module fails to compile.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
import py_compile
|
|
21
|
+
import sys
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
|
|
24
|
+
ROOT = Path(__file__).resolve().parent.parent
|
|
25
|
+
|
|
26
|
+
# Directory names excluded anywhere in the tree: virtualenvs, build/cache
|
|
27
|
+
# artifacts, generated agent output, and vendored snapshots of older releases.
|
|
28
|
+
EXCLUDE_DIRS = {
|
|
29
|
+
".git",
|
|
30
|
+
".venv",
|
|
31
|
+
"venv",
|
|
32
|
+
"env",
|
|
33
|
+
".build-venv",
|
|
34
|
+
".npm-cache",
|
|
35
|
+
"build",
|
|
36
|
+
"dist",
|
|
37
|
+
"node_modules",
|
|
38
|
+
"__pycache__",
|
|
39
|
+
".pytest_cache",
|
|
40
|
+
".mypy_cache",
|
|
41
|
+
".ruff_cache",
|
|
42
|
+
"agent_workspace",
|
|
43
|
+
"outputs",
|
|
44
|
+
"playwright-report",
|
|
45
|
+
"test-results",
|
|
46
|
+
"ltcai.egg-info",
|
|
47
|
+
".ltcai",
|
|
48
|
+
".ltcai-brain",
|
|
49
|
+
".ltcai-test",
|
|
50
|
+
# Vendored snapshot of an older packaged release — not part of the build.
|
|
51
|
+
"ltcai-0.3.1",
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def iter_modules():
|
|
56
|
+
for path in ROOT.rglob("*.py"):
|
|
57
|
+
parts = path.relative_to(ROOT).parts
|
|
58
|
+
if any(part in EXCLUDE_DIRS for part in parts):
|
|
59
|
+
continue
|
|
60
|
+
yield path
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def main(argv: list[str]) -> int:
|
|
64
|
+
modules = sorted(iter_modules())
|
|
65
|
+
if "--list" in argv:
|
|
66
|
+
for path in modules:
|
|
67
|
+
print(path.relative_to(ROOT))
|
|
68
|
+
return 0
|
|
69
|
+
|
|
70
|
+
failures: list[str] = []
|
|
71
|
+
for path in modules:
|
|
72
|
+
try:
|
|
73
|
+
py_compile.compile(str(path), doraise=True)
|
|
74
|
+
except py_compile.PyCompileError as exc:
|
|
75
|
+
failures.append(str(exc))
|
|
76
|
+
|
|
77
|
+
if failures:
|
|
78
|
+
print("\n".join(failures))
|
|
79
|
+
print(f"check:python FAILED — {len(failures)} of {len(modules)} module(s) did not compile")
|
|
80
|
+
return 1
|
|
81
|
+
|
|
82
|
+
print(f"check:python OK — compiled {len(modules)} modules")
|
|
83
|
+
return 0
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
if __name__ == "__main__":
|
|
87
|
+
raise SystemExit(main(sys.argv[1:]))
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
background: var(--card);
|
|
47
47
|
border-color: var(--accent-soft);
|
|
48
48
|
box-shadow: 0 20px 64px rgba(102, 82, 168, 0.20), inset 0 1px 0 rgba(255,255,255,0.86);
|
|
49
|
-
backdrop-filter:
|
|
49
|
+
backdrop-filter: none; /* glass removed v3.5.0 */
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
.lattice-ref-auth .card::before {
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
color: var(--ref-ink);
|
|
66
66
|
background: var(--surface);
|
|
67
67
|
border-bottom: 1px solid rgba(111,66,232,0.08);
|
|
68
|
-
backdrop-filter:
|
|
68
|
+
backdrop-filter: none; /* glass removed v3.5.0 */
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
.auth-window-brand {
|
|
@@ -712,7 +712,10 @@
|
|
|
712
712
|
font-weight: 700;
|
|
713
713
|
background: transparent;
|
|
714
714
|
cursor: pointer;
|
|
715
|
-
transition
|
|
715
|
+
/* Animate surface affordances, but never `color`: a color transition on
|
|
716
|
+
theme switch would briefly render the rail link dark-on-dark (the v226
|
|
717
|
+
dark-mode contrast gate caught this on slow CI). Color flips instantly. */
|
|
718
|
+
transition: background-color 160ms ease, border-color 160ms ease, transform 160ms ease;
|
|
716
719
|
}
|
|
717
720
|
|
|
718
721
|
.reference-rail a.active,
|
|
@@ -842,7 +845,7 @@
|
|
|
842
845
|
background: var(--sidebar);
|
|
843
846
|
border-bottom: 1px solid rgba(111,66,232,0.11);
|
|
844
847
|
box-shadow: 0 2px 12px rgba(88,72,150,0.06);
|
|
845
|
-
backdrop-filter:
|
|
848
|
+
backdrop-filter: none; /* glass removed v3.5.0 */
|
|
846
849
|
}
|
|
847
850
|
|
|
848
851
|
.lattice-ref-chat .messages-viewport {
|
|
@@ -1295,7 +1298,7 @@
|
|
|
1295
1298
|
height: 96px;
|
|
1296
1299
|
background: var(--sidebar);
|
|
1297
1300
|
border-bottom: 1px solid rgba(111,66,232,0.10);
|
|
1298
|
-
backdrop-filter:
|
|
1301
|
+
backdrop-filter: none; /* glass removed v3.5.0 */
|
|
1299
1302
|
padding: 22px 34px 8px;
|
|
1300
1303
|
position: sticky;
|
|
1301
1304
|
}
|
|
@@ -81,8 +81,8 @@
|
|
|
81
81
|
display: flex;
|
|
82
82
|
flex-direction: column;
|
|
83
83
|
min-width: 240px;
|
|
84
|
-
backdrop-filter:
|
|
85
|
-
-webkit-backdrop-filter:
|
|
84
|
+
backdrop-filter: none; /* glass removed v3.5.0 */
|
|
85
|
+
-webkit-backdrop-filter: none; /* glass removed v3.5.0 */
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
.sidebar-header {
|
|
@@ -342,8 +342,8 @@
|
|
|
342
342
|
padding: 10px 22px;
|
|
343
343
|
border-bottom: 1px solid rgba(111,66,232,0.10);
|
|
344
344
|
background: var(--sidebar);
|
|
345
|
-
backdrop-filter:
|
|
346
|
-
-webkit-backdrop-filter:
|
|
345
|
+
backdrop-filter: none; /* glass removed v3.5.0 */
|
|
346
|
+
-webkit-backdrop-filter: none; /* glass removed v3.5.0 */
|
|
347
347
|
position: relative;
|
|
348
348
|
z-index: 50;
|
|
349
349
|
}
|
|
@@ -636,7 +636,7 @@
|
|
|
636
636
|
justify-content: space-between;
|
|
637
637
|
gap: 12px;
|
|
638
638
|
box-shadow: var(--shadow-sm), inset 0 1px 0 rgba(255,255,255,0.80);
|
|
639
|
-
backdrop-filter:
|
|
639
|
+
backdrop-filter: none; /* glass removed v3.5.0 */
|
|
640
640
|
transition: all .2s;
|
|
641
641
|
}
|
|
642
642
|
|
|
@@ -1323,7 +1323,7 @@
|
|
|
1323
1323
|
box-shadow: var(--shadow), 0 0 0 1px rgba(111,66,232,0.05);
|
|
1324
1324
|
position: relative;
|
|
1325
1325
|
z-index: 1;
|
|
1326
|
-
backdrop-filter:
|
|
1326
|
+
backdrop-filter: none; /* glass removed v3.5.0 */
|
|
1327
1327
|
}
|
|
1328
1328
|
|
|
1329
1329
|
.auth-card::before {
|
|
@@ -2754,7 +2754,7 @@
|
|
|
2754
2754
|
.admin-panel {
|
|
2755
2755
|
background: var(--card);
|
|
2756
2756
|
border-left: 1px solid var(--border);
|
|
2757
|
-
backdrop-filter:
|
|
2757
|
+
backdrop-filter: none; /* glass removed v3.5.0 */
|
|
2758
2758
|
color: var(--text);
|
|
2759
2759
|
}
|
|
2760
2760
|
.admin-header {
|
|
@@ -4254,7 +4254,7 @@
|
|
|
4254
4254
|
background: var(--sidebar);
|
|
4255
4255
|
border-bottom: 1px solid var(--line);
|
|
4256
4256
|
box-shadow: none;
|
|
4257
|
-
backdrop-filter:
|
|
4257
|
+
backdrop-filter: none; /* glass removed v3.5.0 */
|
|
4258
4258
|
}
|
|
4259
4259
|
|
|
4260
4260
|
/* Messages viewport */
|
|
@@ -120,7 +120,7 @@
|
|
|
120
120
|
z-index: 20;
|
|
121
121
|
border: 1px solid var(--line);
|
|
122
122
|
background: var(--panel);
|
|
123
|
-
backdrop-filter:
|
|
123
|
+
backdrop-filter: none; /* glass removed v3.5.0 */
|
|
124
124
|
box-shadow: var(--shadow);
|
|
125
125
|
}
|
|
126
126
|
|
|
@@ -904,7 +904,7 @@
|
|
|
904
904
|
border-radius: 10px;
|
|
905
905
|
background: var(--surface-2);
|
|
906
906
|
box-shadow: var(--shadow);
|
|
907
|
-
backdrop-filter:
|
|
907
|
+
backdrop-filter: none; /* glass removed v3.5.0 */
|
|
908
908
|
}
|
|
909
909
|
|
|
910
910
|
.focus-chip span {
|
|
@@ -319,8 +319,8 @@ select {
|
|
|
319
319
|
z-index: 99;
|
|
320
320
|
display: none;
|
|
321
321
|
background: rgba(15, 12, 30, 0.42);
|
|
322
|
-
-webkit-backdrop-filter:
|
|
323
|
-
backdrop-filter:
|
|
322
|
+
-webkit-backdrop-filter: none; /* glass removed v3.5.0 */
|
|
323
|
+
backdrop-filter: none; /* glass removed v3.5.0 */
|
|
324
324
|
}
|
|
325
325
|
body.sidebar-open .sidebar-overlay { display: block; }
|
|
326
326
|
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "3.
|
|
2
|
+
"version": "3.5.0",
|
|
3
3
|
"generated_at": "deterministic",
|
|
4
4
|
"entrypoints": {
|
|
5
|
-
"app": "/static/v3/js/app.
|
|
5
|
+
"app": "/static/v3/js/app.d086489d.js",
|
|
6
6
|
"styles": [
|
|
7
7
|
"/static/css/tokens.3ba22e37.css",
|
|
8
8
|
"/static/v3/css/lattice.tokens.e7018963.css",
|
|
9
9
|
"/static/v3/css/lattice.base.e4cdd05d.css",
|
|
10
10
|
"/static/v3/css/lattice.components.9b49d614.css",
|
|
11
|
-
"/static/v3/css/lattice.shell.
|
|
11
|
+
"/static/v3/css/lattice.shell.8fcc9d33.css",
|
|
12
12
|
"/static/v3/css/lattice.views.22f69117.css"
|
|
13
13
|
]
|
|
14
14
|
},
|
|
@@ -17,15 +17,15 @@
|
|
|
17
17
|
"static/v3/css/lattice.tokens.css": "/static/v3/css/lattice.tokens.e7018963.css",
|
|
18
18
|
"static/v3/css/lattice.base.css": "/static/v3/css/lattice.base.e4cdd05d.css",
|
|
19
19
|
"static/v3/css/lattice.components.css": "/static/v3/css/lattice.components.9b49d614.css",
|
|
20
|
-
"static/v3/css/lattice.shell.css": "/static/v3/css/lattice.shell.
|
|
20
|
+
"static/v3/css/lattice.shell.css": "/static/v3/css/lattice.shell.8fcc9d33.css",
|
|
21
21
|
"static/v3/css/lattice.views.css": "/static/v3/css/lattice.views.22f69117.css",
|
|
22
|
-
"static/v3/js/app.js": "/static/v3/js/app.
|
|
22
|
+
"static/v3/js/app.js": "/static/v3/js/app.d086489d.js",
|
|
23
23
|
"static/v3/js/core/api.js": "/static/v3/js/core/api.12b568ad.js",
|
|
24
|
-
"static/v3/js/core/components.js": "/static/v3/js/core/components.
|
|
24
|
+
"static/v3/js/core/components.js": "/static/v3/js/core/components.f25b3b93.js",
|
|
25
25
|
"static/v3/js/core/dom.js": "/static/v3/js/core/dom.a2773eb0.js",
|
|
26
26
|
"static/v3/js/core/router.js": "/static/v3/js/core/router.584570f2.js",
|
|
27
27
|
"static/v3/js/core/routes.js": "/static/v3/js/core/routes.d214b399.js",
|
|
28
|
-
"static/v3/js/core/shell.js": "/static/v3/js/core/shell.
|
|
28
|
+
"static/v3/js/core/shell.js": "/static/v3/js/core/shell.d05266f5.js",
|
|
29
29
|
"static/v3/js/core/store.js": "/static/v3/js/core/store.34ebd5e6.js",
|
|
30
30
|
"static/v3/js/views/admin-audit.js": "/static/v3/js/views/admin-audit.660a1fb1.js",
|
|
31
31
|
"static/v3/js/views/admin-permissions.js": "/static/v3/js/views/admin-permissions.a7ae5f09.js",
|
|
@@ -37,14 +37,14 @@
|
|
|
37
37
|
"static/v3/js/views/chat.js": "/static/v3/js/views/chat.e6dd7dd0.js",
|
|
38
38
|
"static/v3/js/views/files.js": "/static/v3/js/views/files.adad14c1.js",
|
|
39
39
|
"static/v3/js/views/home.js": "/static/v3/js/views/home.24f8b8ae.js",
|
|
40
|
-
"static/v3/js/views/hooks.js": "/static/v3/js/views/hooks.
|
|
40
|
+
"static/v3/js/views/hooks.js": "/static/v3/js/views/hooks.37895880.js",
|
|
41
41
|
"static/v3/js/views/hybrid-search.js": "/static/v3/js/views/hybrid-search.b22b97e0.js",
|
|
42
42
|
"static/v3/js/views/knowledge-graph.js": "/static/v3/js/views/knowledge-graph.a14ea7e7.js",
|
|
43
43
|
"static/v3/js/views/marketplace.js": "/static/v3/js/views/marketplace.ab0583d4.js",
|
|
44
44
|
"static/v3/js/views/mcp.js": "/static/v3/js/views/mcp.99b5c6a7.js",
|
|
45
45
|
"static/v3/js/views/memory.js": "/static/v3/js/views/memory.4ebdf474.js",
|
|
46
46
|
"static/v3/js/views/models.js": "/static/v3/js/views/models.a1ffa147.js",
|
|
47
|
-
"static/v3/js/views/my-computer.js": "/static/v3/js/views/my-computer.
|
|
47
|
+
"static/v3/js/views/my-computer.js": "/static/v3/js/views/my-computer.d9d9ae1c.js",
|
|
48
48
|
"static/v3/js/views/pipeline.js": "/static/v3/js/views/pipeline.c522f1ce.js",
|
|
49
49
|
"static/v3/js/views/planning.js": "/static/v3/js/views/planning.9ac3e313.js",
|
|
50
50
|
"static/v3/js/views/settings.js": "/static/v3/js/views/settings.8631fa5e.js",
|
|
@@ -349,8 +349,9 @@
|
|
|
349
349
|
.lt3-scrim {
|
|
350
350
|
position: fixed; inset: 0;
|
|
351
351
|
z-index: var(--lt3-z-scrim);
|
|
352
|
+
/* Solid dim scrim — no backdrop blur (glassmorphism removed in v3.5.0 for a
|
|
353
|
+
crisp, stable surface). */
|
|
352
354
|
background: var(--overlay);
|
|
353
|
-
backdrop-filter: blur(2px);
|
|
354
355
|
opacity: 0;
|
|
355
356
|
animation: lt3-fade var(--lt3-dur-2) var(--lt3-ease) forwards;
|
|
356
357
|
}
|
|
@@ -349,8 +349,9 @@
|
|
|
349
349
|
.lt3-scrim {
|
|
350
350
|
position: fixed; inset: 0;
|
|
351
351
|
z-index: var(--lt3-z-scrim);
|
|
352
|
+
/* Solid dim scrim — no backdrop blur (glassmorphism removed in v3.5.0 for a
|
|
353
|
+
crisp, stable surface). */
|
|
352
354
|
background: var(--overlay);
|
|
353
|
-
backdrop-filter: blur(2px);
|
|
354
355
|
opacity: 0;
|
|
355
356
|
animation: lt3-fade var(--lt3-dur-2) var(--lt3-ease) forwards;
|
|
356
357
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Boots the shell. Views are lazy-loaded by the router (see core/routes.js).
|
|
4
4
|
* ========================================================================== */
|
|
5
5
|
|
|
6
|
-
import { boot } from "./core/shell.
|
|
6
|
+
import { boot } from "./core/shell.d05266f5.js";
|
|
7
7
|
|
|
8
8
|
const root = document.getElementById("app");
|
|
9
9
|
if (root) boot(root);
|
|
@@ -74,7 +74,7 @@ const STATE_VARIANT = {
|
|
|
74
74
|
// Agent runs / Hook dispatch). Keep these honest: amber for in-progress,
|
|
75
75
|
// green for healthy/active, red for blocked/failed, neutral for inert.
|
|
76
76
|
ingested: "warn", ingesting: "warn", watching: "ok", watched: "ok",
|
|
77
|
-
connected: "ok", online: "ok", offline: "err", synced: "ok",
|
|
77
|
+
connected: "ok", online: "ok", offline: "err", degraded: "warn", starting: "warn", synced: "ok",
|
|
78
78
|
queued: "warn", running: "warn", retrying: "warn", retried_ok: "ok",
|
|
79
79
|
rejected: "err", cancelled: "", stopped: "", blocked: "err",
|
|
80
80
|
advisory: "warn", skipped: "", complete: "ok", partial: "warn",
|
|
@@ -74,7 +74,7 @@ const STATE_VARIANT = {
|
|
|
74
74
|
// Agent runs / Hook dispatch). Keep these honest: amber for in-progress,
|
|
75
75
|
// green for healthy/active, red for blocked/failed, neutral for inert.
|
|
76
76
|
ingested: "warn", ingesting: "warn", watching: "ok", watched: "ok",
|
|
77
|
-
connected: "ok", online: "ok", offline: "err", synced: "ok",
|
|
77
|
+
connected: "ok", online: "ok", offline: "err", degraded: "warn", starting: "warn", synced: "ok",
|
|
78
78
|
queued: "warn", running: "warn", retrying: "warn", retried_ok: "ok",
|
|
79
79
|
rejected: "err", cancelled: "", stopped: "", blocked: "err",
|
|
80
80
|
advisory: "warn", skipped: "", complete: "ok", partial: "warn",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import { h, icon, $, $$ } from "./dom.a2773eb0.js";
|
|
9
9
|
import { store } from "./store.34ebd5e6.js";
|
|
10
10
|
import { api } from "./api.12b568ad.js";
|
|
11
|
-
import * as c from "./components.
|
|
11
|
+
import * as c from "./components.f25b3b93.js";
|
|
12
12
|
import { createRouter } from "./router.584570f2.js";
|
|
13
13
|
import { GROUPS, ROUTES, ROUTE_BY_KEY, MODE_RANK, visibleRoutes, loadView } from "./routes.d214b399.js";
|
|
14
14
|
|
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
/* ============================================================================
|
|
2
|
-
* View: Hooks — the lifecycle hooks registry.
|
|
3
|
-
* Reads /api/hooks (built-in + user hooks across
|
|
4
|
-
*
|
|
5
|
-
* registers
|
|
2
|
+
* View: Hooks — the lifecycle hooks registry + dispatch.
|
|
3
|
+
* Reads /api/hooks (built-in + user hooks across the pre_/post_ run, tool,
|
|
4
|
+
* workflow, upload, and index lifecycle pairs + agent), toggles enabled state,
|
|
5
|
+
* reorders, registers, runs hooks, and shows a recent-executions log. Built-in
|
|
6
|
+
* hooks are platform-managed; non-executable hooks are labelled "advisory".
|
|
6
7
|
* ========================================================================== */
|
|
7
8
|
|
|
8
9
|
const KIND_LABEL = {
|
|
9
|
-
pre_run: "Pre-run", post_run: "Post-run",
|
|
10
|
-
|
|
10
|
+
pre_run: "Pre-run", post_run: "Post-run",
|
|
11
|
+
pre_tool: "Pre-tool", post_tool: "Post-tool",
|
|
12
|
+
pre_workflow: "Pre-workflow", post_workflow: "Post-workflow",
|
|
13
|
+
pre_upload: "Pre-upload", post_upload: "Post-upload",
|
|
14
|
+
pre_index: "Pre-index", post_index: "Post-index",
|
|
15
|
+
agent: "Agent",
|
|
11
16
|
};
|
|
12
17
|
|
|
13
18
|
export async function render(ctx) {
|
|
@@ -85,7 +90,7 @@ export async function render(ctx) {
|
|
|
85
90
|
function hookRow(ctx2, hk) {
|
|
86
91
|
return c.card(h("div.lt3-row", { style: { "justify-content": "space-between", "align-items": "center", gap: "var(--lt3-space-3)" } },
|
|
87
92
|
h("div", { style: { "min-width": 0 } },
|
|
88
|
-
h("div.lt3-row-2", h("b", hk.name), c.pill(hk.source === "builtin" ? "built-in" : "custom", hk.source === "builtin" ? "info" : ""), hk.managed === "platform" ? c.pill("managed", "") : null),
|
|
93
|
+
h("div.lt3-row-2", h("b", hk.name), c.pill(hk.source === "builtin" ? "built-in" : "custom", hk.source === "builtin" ? "info" : ""), hk.managed === "platform" ? c.pill("managed", "") : null, hk.advisory ? c.pill("advisory", "warn") : c.pill("executable", "ok")),
|
|
89
94
|
h("p.lt3-muted", { style: { margin: "2px 0 0", "font-size": "var(--lt3-text-sm)" } }, hk.description || ""),
|
|
90
95
|
hk.binding ? h("div.lt3-faint", { style: { "font-size": "var(--lt3-text-2xs)", "font-family": "var(--lt3-font-mono)" } }, hk.binding) : null,
|
|
91
96
|
),
|
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
/* ============================================================================
|
|
2
|
-
* View: Hooks — the lifecycle hooks registry.
|
|
3
|
-
* Reads /api/hooks (built-in + user hooks across
|
|
4
|
-
*
|
|
5
|
-
* registers
|
|
2
|
+
* View: Hooks — the lifecycle hooks registry + dispatch.
|
|
3
|
+
* Reads /api/hooks (built-in + user hooks across the pre_/post_ run, tool,
|
|
4
|
+
* workflow, upload, and index lifecycle pairs + agent), toggles enabled state,
|
|
5
|
+
* reorders, registers, runs hooks, and shows a recent-executions log. Built-in
|
|
6
|
+
* hooks are platform-managed; non-executable hooks are labelled "advisory".
|
|
6
7
|
* ========================================================================== */
|
|
7
8
|
|
|
8
9
|
const KIND_LABEL = {
|
|
9
|
-
pre_run: "Pre-run", post_run: "Post-run",
|
|
10
|
-
|
|
10
|
+
pre_run: "Pre-run", post_run: "Post-run",
|
|
11
|
+
pre_tool: "Pre-tool", post_tool: "Post-tool",
|
|
12
|
+
pre_workflow: "Pre-workflow", post_workflow: "Post-workflow",
|
|
13
|
+
pre_upload: "Pre-upload", post_upload: "Post-upload",
|
|
14
|
+
pre_index: "Pre-index", post_index: "Post-index",
|
|
15
|
+
agent: "Agent",
|
|
11
16
|
};
|
|
12
17
|
|
|
13
18
|
export async function render(ctx) {
|
|
@@ -85,7 +90,7 @@ export async function render(ctx) {
|
|
|
85
90
|
function hookRow(ctx2, hk) {
|
|
86
91
|
return c.card(h("div.lt3-row", { style: { "justify-content": "space-between", "align-items": "center", gap: "var(--lt3-space-3)" } },
|
|
87
92
|
h("div", { style: { "min-width": 0 } },
|
|
88
|
-
h("div.lt3-row-2", h("b", hk.name), c.pill(hk.source === "builtin" ? "built-in" : "custom", hk.source === "builtin" ? "info" : ""), hk.managed === "platform" ? c.pill("managed", "") : null),
|
|
93
|
+
h("div.lt3-row-2", h("b", hk.name), c.pill(hk.source === "builtin" ? "built-in" : "custom", hk.source === "builtin" ? "info" : ""), hk.managed === "platform" ? c.pill("managed", "") : null, hk.advisory ? c.pill("advisory", "warn") : c.pill("executable", "ok")),
|
|
89
94
|
h("p.lt3-muted", { style: { margin: "2px 0 0", "font-size": "var(--lt3-text-sm)" } }, hk.description || ""),
|
|
90
95
|
hk.binding ? h("div.lt3-faint", { style: { "font-size": "var(--lt3-text-2xs)", "font-family": "var(--lt3-font-mono)" } }, hk.binding) : null,
|
|
91
96
|
),
|