ltcai 3.3.0 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/README.md +85 -66
  2. package/docs/CHANGELOG.md +36 -0
  3. package/docs/architecture.md +2 -1
  4. package/docs/assets/v3.4.0/agent-run.png +0 -0
  5. package/docs/assets/v3.4.0/agents.png +0 -0
  6. package/docs/assets/v3.4.0/before/chat-before.png +0 -0
  7. package/docs/assets/v3.4.0/before/files-before.png +0 -0
  8. package/docs/assets/v3.4.0/chat.png +0 -0
  9. package/docs/assets/v3.4.0/connect-folder.png +0 -0
  10. package/docs/assets/v3.4.0/files.png +0 -0
  11. package/docs/assets/v3.4.0/home.png +0 -0
  12. package/docs/assets/v3.4.0/hooks-dispatch.png +0 -0
  13. package/docs/assets/v3.4.0/knowledge-graph.png +0 -0
  14. package/docs/assets/v3.4.0/local-agent.png +0 -0
  15. package/docs/assets/v3.4.0/memory.png +0 -0
  16. package/docs/assets/v3.4.0/settings.png +0 -0
  17. package/docs/assets/v3.4.0/vision-input.png +0 -0
  18. package/docs/assets/v3.4.0/workflows.png +0 -0
  19. package/knowledge_graph.py +45 -0
  20. package/knowledge_graph_api.py +10 -0
  21. package/latticeai/__init__.py +1 -1
  22. package/latticeai/api/agents.py +3 -0
  23. package/latticeai/api/hooks.py +39 -0
  24. package/latticeai/api/local_files.py +41 -0
  25. package/latticeai/api/models.py +36 -1
  26. package/latticeai/api/tools.py +16 -1
  27. package/latticeai/api/workflow_designer.py +2 -1
  28. package/latticeai/core/hooks.py +398 -2
  29. package/latticeai/core/marketplace.py +1 -1
  30. package/latticeai/core/multi_agent.py +1 -1
  31. package/latticeai/core/workflow_engine.py +21 -1
  32. package/latticeai/core/workspace_os.py +1 -1
  33. package/latticeai/server_app.py +40 -0
  34. package/latticeai/services/agent_runtime.py +46 -1
  35. package/latticeai/services/upload_service.py +17 -0
  36. package/package.json +1 -1
  37. package/scripts/capture/capture_v340.js +88 -0
  38. package/static/css/{tokens.8b8e31bd.css → tokens.3ba22e37.css} +109 -109
  39. package/static/css/tokens.css +109 -109
  40. package/static/v3/asset-manifest.json +24 -24
  41. package/static/v3/css/{lattice.components.011e988b.css → lattice.components.9b49d614.css} +57 -32
  42. package/static/v3/css/lattice.components.css +57 -32
  43. package/static/v3/css/{lattice.shell.4920f42d.css → lattice.shell.6ceea7c8.css} +75 -31
  44. package/static/v3/css/lattice.shell.css +75 -31
  45. package/static/v3/css/lattice.tokens.css +13 -13
  46. package/static/v3/css/{lattice.tokens.c597ff81.css → lattice.tokens.e7018963.css} +13 -13
  47. package/static/v3/css/{lattice.views.1d326beb.css → lattice.views.22f69117.css} +93 -15
  48. package/static/v3/css/lattice.views.css +93 -15
  49. package/static/v3/js/{app.cf5bb712.js → app.c4acfdd8.js} +1 -1
  50. package/static/v3/js/core/{api.113660c5.js → api.12b568ad.js} +67 -0
  51. package/static/v3/js/core/api.js +67 -0
  52. package/static/v3/js/core/{components.4c83e0a9.js → components.35f02e4c.js} +8 -0
  53. package/static/v3/js/core/components.js +8 -0
  54. package/static/v3/js/core/{routes.07ad6696.js → routes.d214b399.js} +16 -12
  55. package/static/v3/js/core/routes.js +16 -12
  56. package/static/v3/js/core/{shell.9e707234.js → shell.80a6ad82.js} +37 -9
  57. package/static/v3/js/core/shell.js +34 -6
  58. package/static/v3/js/views/agents.014d0b74.js +541 -0
  59. package/static/v3/js/views/agents.js +305 -57
  60. package/static/v3/js/views/{chat.c48fd9e2.js → chat.e6dd7dd0.js} +161 -9
  61. package/static/v3/js/views/chat.js +161 -9
  62. package/static/v3/js/views/files.adad14c1.js +365 -0
  63. package/static/v3/js/views/files.js +212 -79
  64. package/static/v3/js/views/home.24f8b8ae.js +200 -0
  65. package/static/v3/js/views/home.js +96 -15
  66. package/static/v3/js/views/hooks.13845954.js +215 -0
  67. package/static/v3/js/views/hooks.js +117 -1
  68. package/static/v3/js/views/{my-computer.1b2ff621.js → my-computer.c3ef5283.js} +224 -1
  69. package/static/v3/js/views/my-computer.js +224 -1
  70. package/static/v3/js/views/{settings.c7b0cc05.js → settings.8631fa5e.js} +54 -0
  71. package/static/v3/js/views/settings.js +54 -0
  72. package/static/v3/js/views/agents.c373d48c.js +0 -293
  73. package/static/v3/js/views/files.8464634a.js +0 -232
  74. package/static/v3/js/views/home.cdde3b32.js +0 -119
  75. package/static/v3/js/views/hooks.f3edebca.js +0 -99
@@ -440,6 +440,73 @@ export const api = {
440
440
  mcpClaudeServers() { return withFallback("/mcp/claude-code-servers", {}, { servers: [] }); },
441
441
  mcpCustom() { return withFallback("/mcp/custom", {}, { custom: [] }); },
442
442
  mcpRecommend(query, limit = 6) { return raw("/mcp/recommend", { method: "POST", body: { query, limit } }); },
443
+
444
+ /* ── v3.4 Platform Completion ───────────────────────────────────────────
445
+ * Uploaded documents in Files, Connect Folder + Folder Watch over the real
446
+ * on-device runtime, the Local Agent status, and Hooks dispatch/run-log.
447
+ * All endpoints are real (latticeai/api + knowledge_graph_api); fallback-safe. */
448
+
449
+ /** GET /knowledge-graph/documents — uploaded + indexed docs with index state. */
450
+ async documents(limit = 200) {
451
+ const res = await raw(`/knowledge-graph/documents?limit=${encodeURIComponent(limit)}`);
452
+ if (res.ok && res.data && Array.isArray(res.data.documents)) {
453
+ return { ok: true, status: res.status, data: res.data.documents, source: "live", total: res.data.total };
454
+ }
455
+ return { ok: false, status: res.status, data: [], source: "unavailable", error: res.error };
456
+ },
457
+
458
+ // Local Agent (the on-device Lattice runtime: real GET /api/local-agent/status)
459
+ async localAgent() {
460
+ const res = await raw("/api/local-agent/status");
461
+ if (res.ok && res.data && res.data.agent) {
462
+ return { ok: true, status: res.status, data: res.data, source: "live" };
463
+ }
464
+ return {
465
+ ok: false, status: res.status, source: "unavailable",
466
+ data: { agent: { online: false }, health: {}, folders: { connected: 0, watching: 0 }, watch: { available: false, active: {} }, sources: [] },
467
+ };
468
+ },
469
+
470
+ // Connect Folder + Folder Watch (real backend: /knowledge-graph/local/*)
471
+ localRoots() { return withFallback("/knowledge-graph/local/roots", {}, { roots: [] }); },
472
+ async localSources() {
473
+ const res = await raw("/knowledge-graph/local/sources");
474
+ if (res.ok && res.data && Array.isArray(res.data.sources)) {
475
+ return { ok: true, status: res.status, data: res.data, source: "live" };
476
+ }
477
+ return { ok: false, status: res.status, data: { sources: [], watch: { available: false, active: {} } }, source: "unavailable" };
478
+ },
479
+ localWatchStatus() { return raw("/knowledge-graph/local/watch/status"); },
480
+ localWatchStop(source_id) { return raw("/knowledge-graph/local/watch/stop", { method: "POST", body: { source_id } }); },
481
+ approvePermission(token) { return raw(`/permissions/approve/${encodeURIComponent(token)}`, { method: "POST" }); },
482
+ indexFolder(path, opts = {}) {
483
+ return raw("/knowledge-graph/local/index", { method: "POST", body: { path, ...opts } });
484
+ },
485
+ /** One-call Connect Folder: request → self-approve (the click is the consent)
486
+ * → index (+ optional watch). Returns { ok, data, error }. */
487
+ async connectFolder(path, { watch = true, includeOcr = false } = {}) {
488
+ const probe = await raw("/knowledge-graph/local/index", { method: "POST", body: { path, approved: false } });
489
+ const token = probe.data && probe.data.approval_token;
490
+ if (!token) {
491
+ const detail = (probe.data && (probe.data.detail || probe.data.error)) || "the runtime did not return an approval token";
492
+ return { ok: false, error: detail, status: probe.status };
493
+ }
494
+ const approved = await raw(`/permissions/approve/${encodeURIComponent(token)}`, { method: "POST" });
495
+ if (!approved.ok) {
496
+ const detail = (approved.data && (approved.data.detail || approved.data.error)) || "approval failed";
497
+ return { ok: false, error: detail, status: approved.status };
498
+ }
499
+ const res = await raw("/knowledge-graph/local/index", {
500
+ method: "POST",
501
+ body: { path, approved: true, approval_token: token, watch_enabled: watch, include_ocr: includeOcr, consent: { approved: true, source: "files-ui" } },
502
+ });
503
+ if (res.ok && res.data && !res.data.detail) return { ok: true, data: res.data, status: res.status };
504
+ return { ok: false, error: (res.data && (res.data.detail || res.data.error)) || "indexing failed", status: res.status, data: res.data };
505
+ },
506
+
507
+ // Hooks dispatch (real backend: POST /api/hooks/run + GET /api/hooks/runs)
508
+ hookRun(body) { return raw("/api/hooks/run", { method: "POST", body }); },
509
+ hookRuns(limit = 50, kind) { return withFallback(`/api/hooks/runs?limit=${encodeURIComponent(limit)}${kind ? "&kind=" + encodeURIComponent(kind) : ""}`, {}, { runs: [], total: 0 }); },
443
510
  };
444
511
 
445
512
  const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
@@ -70,6 +70,14 @@ const STATE_VARIANT = {
70
70
  ready: "ok", active: "ok", indexed: "ok", loaded: "ok", ok: "ok", available: "info",
71
71
  idle: "", standby: "", pending: "warn", indexing: "warn", building: "warn",
72
72
  failed: "err", error: "err", disabled: "err", not_configured: "",
73
+ // v3.4.0 platform-completion states (Files / Folder Watch / Local Agent /
74
+ // Agent runs / Hook dispatch). Keep these honest: amber for in-progress,
75
+ // green for healthy/active, red for blocked/failed, neutral for inert.
76
+ ingested: "warn", ingesting: "warn", watching: "ok", watched: "ok",
77
+ connected: "ok", online: "ok", offline: "err", synced: "ok",
78
+ queued: "warn", running: "warn", retrying: "warn", retried_ok: "ok",
79
+ rejected: "err", cancelled: "", stopped: "", blocked: "err",
80
+ advisory: "warn", skipped: "", complete: "ok", partial: "warn",
73
81
  };
74
82
  export function statePill(state) {
75
83
  return pill(String(state || "unknown"), STATE_VARIANT[String(state).toLowerCase()] ?? "", { dot: true });
@@ -70,6 +70,14 @@ const STATE_VARIANT = {
70
70
  ready: "ok", active: "ok", indexed: "ok", loaded: "ok", ok: "ok", available: "info",
71
71
  idle: "", standby: "", pending: "warn", indexing: "warn", building: "warn",
72
72
  failed: "err", error: "err", disabled: "err", not_configured: "",
73
+ // v3.4.0 platform-completion states (Files / Folder Watch / Local Agent /
74
+ // Agent runs / Hook dispatch). Keep these honest: amber for in-progress,
75
+ // green for healthy/active, red for blocked/failed, neutral for inert.
76
+ ingested: "warn", ingesting: "warn", watching: "ok", watched: "ok",
77
+ connected: "ok", online: "ok", offline: "err", synced: "ok",
78
+ queued: "warn", running: "warn", retrying: "warn", retried_ok: "ok",
79
+ rejected: "err", cancelled: "", stopped: "", blocked: "err",
80
+ advisory: "warn", skipped: "", complete: "ok", partial: "warn",
73
81
  };
74
82
  export function statePill(state) {
75
83
  return pill(String(state || "unknown"), STATE_VARIANT[String(state).toLowerCase()] ?? "", { dot: true });
@@ -11,8 +11,8 @@ export const MODE_RANK = { basic: 0, advanced: 1, admin: 2 };
11
11
  /** Nav groups in display order. */
12
12
  export const GROUPS = [
13
13
  { id: "workspace", label: "Workspace" },
14
- { id: "retrieval", label: "Retrieval" },
15
14
  { id: "data", label: "Data" },
15
+ { id: "retrieval", label: "Retrieval" },
16
16
  { id: "compute", label: "Compute" },
17
17
  { id: "platform", label: "Platform" },
18
18
  { id: "system", label: "System" },
@@ -28,32 +28,35 @@ export const ROUTES = [
28
28
  { key: "home", label: "Home", icon: "layout-dashboard", group: "workspace", minMode: "basic", view: "home", title: "Home", desc: "Your local-first AI workspace at a glance." },
29
29
  { key: "chat", label: "Chat", icon: "message-2", group: "workspace", minMode: "basic", view: "chat", title: "Chat", desc: "Grounded conversation over your indexed workspace." },
30
30
 
31
- // Retrieval (the product identity)
32
- { key: "knowledge-graph", label: "Knowledge Graph", icon: "chart-dots-3", group: "retrieval", minMode: "basic", view: "knowledge-graph", title: "Knowledge Graph", desc: "Entities and relations extracted from your workspace." },
33
- { key: "hybrid-search", label: "Hybrid Search", icon: "arrows-join", group: "retrieval", minMode: "basic", view: "hybrid-search", title: "Hybrid Search", desc: "Graph structure fused with vector similarity." },
34
- { key: "memory", label: "Memory", icon: "brain", group: "retrieval", minMode: "basic", view: "memory", title: "Memory", desc: "Long-term workspace, project, agent, and conversation memory." },
35
-
36
31
  // Data
37
32
  { key: "files", label: "Files", icon: "folders", group: "data", minMode: "basic", view: "files", title: "Files", desc: "Connected sources and indexed documents." },
38
- { key: "pipeline", label: "Pipeline", icon: "git-branch", group: "data", minMode: "advanced", view: "pipeline", title: "Pipeline", desc: "Ingest, embed, and graph-build flows." },
33
+
34
+ // Retrieval (the product identity)
35
+ { key: "hybrid-search", label: "Search", icon: "arrows-join", group: "retrieval", minMode: "basic", view: "hybrid-search", title: "Hybrid Search", desc: "Graph structure fused with vector similarity." },
36
+ { key: "knowledge-graph", label: "Knowledge", icon: "chart-dots-3", group: "retrieval", minMode: "basic", view: "knowledge-graph", title: "Knowledge Graph", desc: "Entities and relations extracted from your workspace." },
37
+ { key: "memory", label: "Memory", icon: "brain", group: "retrieval", minMode: "basic", view: "memory", title: "Memory", desc: "Long-term workspace, project, agent, and conversation memory." },
39
38
 
40
39
  // Compute
40
+ { key: "models", label: "Models", icon: "cpu", group: "compute", minMode: "basic", view: "models", title: "Models", desc: "Local MLX models and embeddings." },
41
41
  { key: "agents", label: "Agents", icon: "robot", group: "compute", minMode: "advanced", view: "agents", title: "Agents", desc: "Multi-agent roles, runs, and handoffs." },
42
42
  { key: "workflows", label: "Workflows", icon: "sitemap", group: "compute", minMode: "advanced", view: "workflows", title: "Workflow Agents", desc: "Trigger → agent chain → tools → memory → result." },
43
- { key: "planning", label: "Planning", icon: "target-arrow", group: "compute", minMode: "advanced", view: "planning", title: "Autonomous Planning", desc: "Goal → plan → execute → review → replan." },
44
- { key: "models", label: "Models", icon: "cpu", group: "compute", minMode: "basic", view: "models", title: "Models", desc: "Local MLX models and embeddings." },
45
- { key: "my-computer", label: "My Computer", icon: "device-desktop-analytics", group: "compute", minMode: "advanced", view: "my-computer", title: "My Computer", desc: "Local hardware, memory, and runtime." },
46
43
 
47
44
  // Platform (the agent ecosystem)
48
- { key: "marketplace", label: "Marketplace", icon: "building-store", group: "platform", minMode: "advanced", view: "marketplace", title: "Marketplace", desc: "Agent templates, agents, plugins, and skills." },
49
45
  { key: "skills", label: "Skills", icon: "puzzle", group: "platform", minMode: "advanced", view: "skills", title: "Skills", desc: "Install, enable, and manage skills." },
50
46
  { key: "hooks", label: "Hooks", icon: "webhook", group: "platform", minMode: "advanced", view: "hooks", title: "Hooks", desc: "Lifecycle hooks across runs, tools, and workflows." },
51
- { key: "tools", label: "Tools", icon: "tools", group: "platform", minMode: "advanced", view: "tools", title: "Tool Registry", desc: "Local, workspace, and MCP tools with governance." },
52
47
  { key: "mcp", label: "MCP", icon: "plug-connected", group: "platform", minMode: "advanced", view: "mcp", title: "MCP Manager", desc: "Connected MCP servers, available tools, and health." },
53
48
 
54
49
  // System
55
50
  { key: "settings", label: "Settings", icon: "settings", group: "system", minMode: "basic", view: "settings", title: "Settings", desc: "Appearance, workspace, and integrations." },
56
51
 
52
+ // Deep-linkable legacy/experimental surfaces. They remain renderable for
53
+ // compatibility, but are not promoted in the production navigation.
54
+ { key: "pipeline", label: "Pipeline", icon: "git-branch", group: "data", minMode: "advanced", view: "pipeline", title: "Pipeline", desc: "Ingest, embed, and graph-build flows.", hidden: true },
55
+ { key: "planning", label: "Planning", icon: "target-arrow", group: "compute", minMode: "advanced", view: "planning", title: "Autonomous Planning", desc: "Goal → plan → execute → review → replan.", hidden: true },
56
+ { key: "my-computer", label: "My Computer", icon: "device-desktop-analytics", group: "compute", minMode: "advanced", view: "my-computer", title: "My Computer", desc: "Local hardware, memory, and runtime.", hidden: true },
57
+ { key: "marketplace", label: "Marketplace", icon: "building-store", group: "platform", minMode: "advanced", view: "marketplace", title: "Marketplace", desc: "Agent templates, agents, plugins, and skills.", hidden: true },
58
+ { key: "tools", label: "Tools", icon: "tools", group: "platform", minMode: "advanced", view: "tools", title: "Tool Registry", desc: "Local, workspace, and MCP tools with governance.", hidden: true },
59
+
57
60
  // Admin
58
61
  { key: "admin/users", label: "Users", icon: "users", group: "admin", minMode: "admin", view: "admin-users", title: "Users", desc: "Workspace members and access.", admin: true },
59
62
  { key: "admin/permissions", label: "Permissions", icon: "key", group: "admin", minMode: "admin", view: "admin-permissions", title: "Permissions", desc: "Roles and capability mapping.", admin: true },
@@ -69,6 +72,7 @@ export const ROUTE_BY_KEY = Object.fromEntries(ROUTES.map((r) => [r.key, r]));
69
72
  export function visibleRoutes(mode) {
70
73
  const rank = MODE_RANK[mode] ?? 0;
71
74
  return ROUTES.filter((r) => {
75
+ if (r.hidden) return false;
72
76
  if (r.admin) return mode === "admin";
73
77
  return (MODE_RANK[r.minMode] ?? 0) <= rank;
74
78
  });
@@ -11,8 +11,8 @@ export const MODE_RANK = { basic: 0, advanced: 1, admin: 2 };
11
11
  /** Nav groups in display order. */
12
12
  export const GROUPS = [
13
13
  { id: "workspace", label: "Workspace" },
14
- { id: "retrieval", label: "Retrieval" },
15
14
  { id: "data", label: "Data" },
15
+ { id: "retrieval", label: "Retrieval" },
16
16
  { id: "compute", label: "Compute" },
17
17
  { id: "platform", label: "Platform" },
18
18
  { id: "system", label: "System" },
@@ -28,32 +28,35 @@ export const ROUTES = [
28
28
  { key: "home", label: "Home", icon: "layout-dashboard", group: "workspace", minMode: "basic", view: "home", title: "Home", desc: "Your local-first AI workspace at a glance." },
29
29
  { key: "chat", label: "Chat", icon: "message-2", group: "workspace", minMode: "basic", view: "chat", title: "Chat", desc: "Grounded conversation over your indexed workspace." },
30
30
 
31
- // Retrieval (the product identity)
32
- { key: "knowledge-graph", label: "Knowledge Graph", icon: "chart-dots-3", group: "retrieval", minMode: "basic", view: "knowledge-graph", title: "Knowledge Graph", desc: "Entities and relations extracted from your workspace." },
33
- { key: "hybrid-search", label: "Hybrid Search", icon: "arrows-join", group: "retrieval", minMode: "basic", view: "hybrid-search", title: "Hybrid Search", desc: "Graph structure fused with vector similarity." },
34
- { key: "memory", label: "Memory", icon: "brain", group: "retrieval", minMode: "basic", view: "memory", title: "Memory", desc: "Long-term workspace, project, agent, and conversation memory." },
35
-
36
31
  // Data
37
32
  { key: "files", label: "Files", icon: "folders", group: "data", minMode: "basic", view: "files", title: "Files", desc: "Connected sources and indexed documents." },
38
- { key: "pipeline", label: "Pipeline", icon: "git-branch", group: "data", minMode: "advanced", view: "pipeline", title: "Pipeline", desc: "Ingest, embed, and graph-build flows." },
33
+
34
+ // Retrieval (the product identity)
35
+ { key: "hybrid-search", label: "Search", icon: "arrows-join", group: "retrieval", minMode: "basic", view: "hybrid-search", title: "Hybrid Search", desc: "Graph structure fused with vector similarity." },
36
+ { key: "knowledge-graph", label: "Knowledge", icon: "chart-dots-3", group: "retrieval", minMode: "basic", view: "knowledge-graph", title: "Knowledge Graph", desc: "Entities and relations extracted from your workspace." },
37
+ { key: "memory", label: "Memory", icon: "brain", group: "retrieval", minMode: "basic", view: "memory", title: "Memory", desc: "Long-term workspace, project, agent, and conversation memory." },
39
38
 
40
39
  // Compute
40
+ { key: "models", label: "Models", icon: "cpu", group: "compute", minMode: "basic", view: "models", title: "Models", desc: "Local MLX models and embeddings." },
41
41
  { key: "agents", label: "Agents", icon: "robot", group: "compute", minMode: "advanced", view: "agents", title: "Agents", desc: "Multi-agent roles, runs, and handoffs." },
42
42
  { key: "workflows", label: "Workflows", icon: "sitemap", group: "compute", minMode: "advanced", view: "workflows", title: "Workflow Agents", desc: "Trigger → agent chain → tools → memory → result." },
43
- { key: "planning", label: "Planning", icon: "target-arrow", group: "compute", minMode: "advanced", view: "planning", title: "Autonomous Planning", desc: "Goal → plan → execute → review → replan." },
44
- { key: "models", label: "Models", icon: "cpu", group: "compute", minMode: "basic", view: "models", title: "Models", desc: "Local MLX models and embeddings." },
45
- { key: "my-computer", label: "My Computer", icon: "device-desktop-analytics", group: "compute", minMode: "advanced", view: "my-computer", title: "My Computer", desc: "Local hardware, memory, and runtime." },
46
43
 
47
44
  // Platform (the agent ecosystem)
48
- { key: "marketplace", label: "Marketplace", icon: "building-store", group: "platform", minMode: "advanced", view: "marketplace", title: "Marketplace", desc: "Agent templates, agents, plugins, and skills." },
49
45
  { key: "skills", label: "Skills", icon: "puzzle", group: "platform", minMode: "advanced", view: "skills", title: "Skills", desc: "Install, enable, and manage skills." },
50
46
  { key: "hooks", label: "Hooks", icon: "webhook", group: "platform", minMode: "advanced", view: "hooks", title: "Hooks", desc: "Lifecycle hooks across runs, tools, and workflows." },
51
- { key: "tools", label: "Tools", icon: "tools", group: "platform", minMode: "advanced", view: "tools", title: "Tool Registry", desc: "Local, workspace, and MCP tools with governance." },
52
47
  { key: "mcp", label: "MCP", icon: "plug-connected", group: "platform", minMode: "advanced", view: "mcp", title: "MCP Manager", desc: "Connected MCP servers, available tools, and health." },
53
48
 
54
49
  // System
55
50
  { key: "settings", label: "Settings", icon: "settings", group: "system", minMode: "basic", view: "settings", title: "Settings", desc: "Appearance, workspace, and integrations." },
56
51
 
52
+ // Deep-linkable legacy/experimental surfaces. They remain renderable for
53
+ // compatibility, but are not promoted in the production navigation.
54
+ { key: "pipeline", label: "Pipeline", icon: "git-branch", group: "data", minMode: "advanced", view: "pipeline", title: "Pipeline", desc: "Ingest, embed, and graph-build flows.", hidden: true },
55
+ { key: "planning", label: "Planning", icon: "target-arrow", group: "compute", minMode: "advanced", view: "planning", title: "Autonomous Planning", desc: "Goal → plan → execute → review → replan.", hidden: true },
56
+ { key: "my-computer", label: "My Computer", icon: "device-desktop-analytics", group: "compute", minMode: "advanced", view: "my-computer", title: "My Computer", desc: "Local hardware, memory, and runtime.", hidden: true },
57
+ { key: "marketplace", label: "Marketplace", icon: "building-store", group: "platform", minMode: "advanced", view: "marketplace", title: "Marketplace", desc: "Agent templates, agents, plugins, and skills.", hidden: true },
58
+ { key: "tools", label: "Tools", icon: "tools", group: "platform", minMode: "advanced", view: "tools", title: "Tool Registry", desc: "Local, workspace, and MCP tools with governance.", hidden: true },
59
+
57
60
  // Admin
58
61
  { key: "admin/users", label: "Users", icon: "users", group: "admin", minMode: "admin", view: "admin-users", title: "Users", desc: "Workspace members and access.", admin: true },
59
62
  { key: "admin/permissions", label: "Permissions", icon: "key", group: "admin", minMode: "admin", view: "admin-permissions", title: "Permissions", desc: "Roles and capability mapping.", admin: true },
@@ -69,6 +72,7 @@ export const ROUTE_BY_KEY = Object.fromEntries(ROUTES.map((r) => [r.key, r]));
69
72
  export function visibleRoutes(mode) {
70
73
  const rank = MODE_RANK[mode] ?? 0;
71
74
  return ROUTES.filter((r) => {
75
+ if (r.hidden) return false;
72
76
  if (r.admin) return mode === "admin";
73
77
  return (MODE_RANK[r.minMode] ?? 0) <= rank;
74
78
  });
@@ -7,10 +7,10 @@
7
7
 
8
8
  import { h, icon, $, $$ } from "./dom.a2773eb0.js";
9
9
  import { store } from "./store.34ebd5e6.js";
10
- import { api } from "./api.113660c5.js";
11
- import * as c from "./components.4c83e0a9.js";
10
+ import { api } from "./api.12b568ad.js";
11
+ import * as c from "./components.35f02e4c.js";
12
12
  import { createRouter } from "./router.584570f2.js";
13
- import { GROUPS, ROUTES, ROUTE_BY_KEY, MODE_RANK, visibleRoutes, loadView } from "./routes.07ad6696.js";
13
+ import { GROUPS, ROUTES, ROUTE_BY_KEY, MODE_RANK, visibleRoutes, loadView } from "./routes.d214b399.js";
14
14
 
15
15
  const MODES = [
16
16
  { key: "basic", label: "Basic", icon: "circle" },
@@ -49,14 +49,17 @@ function buildRail() {
49
49
  return h("aside.lt3-rail", { id: "lt3-rail", "aria-label": "Primary" },
50
50
  h("div.lt3-rail__brand",
51
51
  h("div.lt3-rail__logo", { html: latticeMark() }),
52
- h("div.lt3-rail__word", h("b", "Lattice AI"), h("small", "Local-First Workspace")),
52
+ h("div.lt3-rail__word", h("b", "Lattice AI"), h("small", "Private runtime")),
53
53
  h("button.lt3-iconbtn.lt3-iconbtn--sm.lt3-rail__close", { "aria-label": "Close menu", on: { click: closeDrawer } }, icon("x")),
54
54
  ),
55
55
  h("div.lt3-rail__scope", { id: "lt3-scope" }),
56
56
  h("nav.lt3-rail__nav", { id: "lt3-nav", "aria-label": "Sections" }),
57
57
  h("div.lt3-rail__foot",
58
- h("button.lt3-rail__user", { id: "lt3-user", "aria-label": "Account", on: { click: () => router.navigate("settings") } }),
59
- h("button.lt3-iconbtn", { id: "lt3-theme", "aria-label": "Toggle theme", title: "Toggle theme", on: { click: () => store.toggleTheme() } }, icon("moon")),
58
+ h("div.lt3-rail__status", { id: "lt3-rail-status" }),
59
+ h("div.lt3-rail__foot-row",
60
+ h("button.lt3-rail__user", { id: "lt3-user", "aria-label": "Account", on: { click: () => router.navigate("settings") } }),
61
+ h("button.lt3-iconbtn", { id: "lt3-theme", "aria-label": "Toggle theme", title: "Toggle theme", on: { click: () => store.toggleTheme() } }, icon("moon")),
62
+ ),
60
63
  ),
61
64
  );
62
65
  }
@@ -82,10 +85,14 @@ function navItem(route) {
82
85
  return h("a.lt3-navitem", {
83
86
  href: "#/" + route.key,
84
87
  dataset: { key: route.key },
88
+ title: route.title || route.label,
85
89
  on: { click: () => closeDrawer() },
86
90
  },
87
91
  icon(route.icon),
88
- h("span.lt3-navitem__label", route.label),
92
+ h("span.lt3-navitem__copy",
93
+ h("span.lt3-navitem__label", route.label),
94
+ route.desc ? h("span.lt3-navitem__meta", route.desc) : null,
95
+ ),
89
96
  route.key === "hybrid-search" ? h("span.lt3-navitem__dot", { style: { background: "var(--lt3-pillar-hybrid)" } }) : null,
90
97
  );
91
98
  }
@@ -161,6 +168,23 @@ function renderCrumbs() {
161
168
 
162
169
  function renderIndexChip() {
163
170
  els.idxchip.replaceChildren(c.indexChip(store.get().indexStatus));
171
+ renderRailStatus();
172
+ }
173
+
174
+ function renderRailStatus() {
175
+ if (!els.railStatus) return;
176
+ const status = store.get().indexStatus;
177
+ const pipes = status?.pipelines || {};
178
+ const keys = ["knowledge_graph", "vector_index", "hybrid"];
179
+ const ready = keys.filter((key) => String(pipes[key]?.state || "").toLowerCase() === "ready").length;
180
+ const unavailable = !Object.keys(pipes).length;
181
+ els.railStatus.replaceChildren(
182
+ h("div.lt3-rail__status-top",
183
+ h("span.lt3-rail__status-dot", { dataset: { state: unavailable ? "pending" : ready === keys.length ? "ready" : "partial" } }),
184
+ h("span", unavailable ? "Local index pending" : `${ready}/${keys.length} retrieval signals ready`),
185
+ ),
186
+ h("div.lt3-rail__status-sub", unavailable ? "Start backend to sync live state" : "Graph · vector · hybrid"),
187
+ );
164
188
  }
165
189
 
166
190
  /* ── View rendering ─────────────────────────────────────────────────────── */
@@ -240,8 +264,10 @@ function closeDrawer() { delete els.root.dataset.drawer; }
240
264
 
241
265
  /* ── Command palette ────────────────────────────────────────────────────── */
242
266
  function paletteItems() {
243
- const nav = ROUTES.map((r) => ({
244
- group: "Go to", label: r.label, icon: r.icon, hint: r.group,
267
+ const mode = store.get().mode;
268
+ const currentRoutes = visibleRoutes(mode);
269
+ const nav = currentRoutes.map((r) => ({
270
+ group: "Go to", label: r.title || r.label, icon: r.icon, hint: r.label === r.title ? r.group : r.label,
245
271
  run: () => router.navigate(r.key),
246
272
  }));
247
273
  const actions = [
@@ -340,6 +366,7 @@ function cacheEls(root) {
340
366
  theme: $("#lt3-theme", root),
341
367
  crumbs: $("#lt3-crumbs", root),
342
368
  idxchip: $("#lt3-idxchip", root),
369
+ railStatus: $("#lt3-rail-status", root),
343
370
  outlet: $("#lt3-outlet", root),
344
371
  view: $("#lt3-view", root),
345
372
  };
@@ -349,6 +376,7 @@ function cacheEls(root) {
349
376
  renderMode();
350
377
  updateThemeIcon();
351
378
  renderIndexChip();
379
+ renderRailStatus();
352
380
  }
353
381
 
354
382
  function latticeMark() {
@@ -49,14 +49,17 @@ function buildRail() {
49
49
  return h("aside.lt3-rail", { id: "lt3-rail", "aria-label": "Primary" },
50
50
  h("div.lt3-rail__brand",
51
51
  h("div.lt3-rail__logo", { html: latticeMark() }),
52
- h("div.lt3-rail__word", h("b", "Lattice AI"), h("small", "Local-First Workspace")),
52
+ h("div.lt3-rail__word", h("b", "Lattice AI"), h("small", "Private runtime")),
53
53
  h("button.lt3-iconbtn.lt3-iconbtn--sm.lt3-rail__close", { "aria-label": "Close menu", on: { click: closeDrawer } }, icon("x")),
54
54
  ),
55
55
  h("div.lt3-rail__scope", { id: "lt3-scope" }),
56
56
  h("nav.lt3-rail__nav", { id: "lt3-nav", "aria-label": "Sections" }),
57
57
  h("div.lt3-rail__foot",
58
- h("button.lt3-rail__user", { id: "lt3-user", "aria-label": "Account", on: { click: () => router.navigate("settings") } }),
59
- h("button.lt3-iconbtn", { id: "lt3-theme", "aria-label": "Toggle theme", title: "Toggle theme", on: { click: () => store.toggleTheme() } }, icon("moon")),
58
+ h("div.lt3-rail__status", { id: "lt3-rail-status" }),
59
+ h("div.lt3-rail__foot-row",
60
+ h("button.lt3-rail__user", { id: "lt3-user", "aria-label": "Account", on: { click: () => router.navigate("settings") } }),
61
+ h("button.lt3-iconbtn", { id: "lt3-theme", "aria-label": "Toggle theme", title: "Toggle theme", on: { click: () => store.toggleTheme() } }, icon("moon")),
62
+ ),
60
63
  ),
61
64
  );
62
65
  }
@@ -82,10 +85,14 @@ function navItem(route) {
82
85
  return h("a.lt3-navitem", {
83
86
  href: "#/" + route.key,
84
87
  dataset: { key: route.key },
88
+ title: route.title || route.label,
85
89
  on: { click: () => closeDrawer() },
86
90
  },
87
91
  icon(route.icon),
88
- h("span.lt3-navitem__label", route.label),
92
+ h("span.lt3-navitem__copy",
93
+ h("span.lt3-navitem__label", route.label),
94
+ route.desc ? h("span.lt3-navitem__meta", route.desc) : null,
95
+ ),
89
96
  route.key === "hybrid-search" ? h("span.lt3-navitem__dot", { style: { background: "var(--lt3-pillar-hybrid)" } }) : null,
90
97
  );
91
98
  }
@@ -161,6 +168,23 @@ function renderCrumbs() {
161
168
 
162
169
  function renderIndexChip() {
163
170
  els.idxchip.replaceChildren(c.indexChip(store.get().indexStatus));
171
+ renderRailStatus();
172
+ }
173
+
174
+ function renderRailStatus() {
175
+ if (!els.railStatus) return;
176
+ const status = store.get().indexStatus;
177
+ const pipes = status?.pipelines || {};
178
+ const keys = ["knowledge_graph", "vector_index", "hybrid"];
179
+ const ready = keys.filter((key) => String(pipes[key]?.state || "").toLowerCase() === "ready").length;
180
+ const unavailable = !Object.keys(pipes).length;
181
+ els.railStatus.replaceChildren(
182
+ h("div.lt3-rail__status-top",
183
+ h("span.lt3-rail__status-dot", { dataset: { state: unavailable ? "pending" : ready === keys.length ? "ready" : "partial" } }),
184
+ h("span", unavailable ? "Local index pending" : `${ready}/${keys.length} retrieval signals ready`),
185
+ ),
186
+ h("div.lt3-rail__status-sub", unavailable ? "Start backend to sync live state" : "Graph · vector · hybrid"),
187
+ );
164
188
  }
165
189
 
166
190
  /* ── View rendering ─────────────────────────────────────────────────────── */
@@ -240,8 +264,10 @@ function closeDrawer() { delete els.root.dataset.drawer; }
240
264
 
241
265
  /* ── Command palette ────────────────────────────────────────────────────── */
242
266
  function paletteItems() {
243
- const nav = ROUTES.map((r) => ({
244
- group: "Go to", label: r.label, icon: r.icon, hint: r.group,
267
+ const mode = store.get().mode;
268
+ const currentRoutes = visibleRoutes(mode);
269
+ const nav = currentRoutes.map((r) => ({
270
+ group: "Go to", label: r.title || r.label, icon: r.icon, hint: r.label === r.title ? r.group : r.label,
245
271
  run: () => router.navigate(r.key),
246
272
  }));
247
273
  const actions = [
@@ -340,6 +366,7 @@ function cacheEls(root) {
340
366
  theme: $("#lt3-theme", root),
341
367
  crumbs: $("#lt3-crumbs", root),
342
368
  idxchip: $("#lt3-idxchip", root),
369
+ railStatus: $("#lt3-rail-status", root),
343
370
  outlet: $("#lt3-outlet", root),
344
371
  view: $("#lt3-view", root),
345
372
  };
@@ -349,6 +376,7 @@ function cacheEls(root) {
349
376
  renderMode();
350
377
  updateThemeIcon();
351
378
  renderIndexChip();
379
+ renderRailStatus();
352
380
  }
353
381
 
354
382
  function latticeMark() {