ltcai 4.0.0 → 4.0.1

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 (108) hide show
  1. package/README.md +37 -33
  2. package/docs/CHANGELOG.md +64 -0
  3. package/docs/REALTIME_COLLABORATION.md +3 -3
  4. package/docs/V3_FRONTEND.md +9 -8
  5. package/docs/V4_DIGITAL_BRAIN_RECOVERY.md +86 -43
  6. package/docs/kg-schema.md +6 -2
  7. package/docs/spec-vs-impl.md +10 -10
  8. package/kg_schema.py +2 -603
  9. package/knowledge_graph.py +37 -4958
  10. package/latticeai/__init__.py +1 -1
  11. package/latticeai/api/admin.py +15 -16
  12. package/latticeai/api/agents.py +13 -6
  13. package/latticeai/api/auth.py +19 -11
  14. package/latticeai/api/invitations.py +100 -0
  15. package/latticeai/api/knowledge_graph.py +4 -11
  16. package/latticeai/api/plugins.py +3 -6
  17. package/latticeai/api/realtime.py +4 -7
  18. package/latticeai/api/static_routes.py +9 -12
  19. package/latticeai/api/ui_redirects.py +26 -0
  20. package/latticeai/api/workflow_designer.py +39 -6
  21. package/latticeai/api/workspace.py +24 -10
  22. package/latticeai/app_factory.py +88 -17
  23. package/latticeai/brain/_kg_common.py +1123 -0
  24. package/latticeai/brain/discovery.py +1455 -0
  25. package/latticeai/brain/documents.py +218 -0
  26. package/latticeai/brain/ingest.py +644 -0
  27. package/latticeai/brain/projection.py +561 -0
  28. package/latticeai/brain/provenance.py +401 -0
  29. package/latticeai/brain/retrieval.py +1316 -0
  30. package/latticeai/brain/schema.py +640 -0
  31. package/latticeai/brain/store.py +216 -0
  32. package/latticeai/brain/write_master.py +225 -0
  33. package/latticeai/core/invitations.py +131 -0
  34. package/latticeai/core/marketplace.py +1 -1
  35. package/latticeai/core/multi_agent.py +1 -1
  36. package/latticeai/core/policy.py +54 -0
  37. package/latticeai/core/realtime.py +65 -44
  38. package/latticeai/core/sessions.py +31 -5
  39. package/latticeai/core/users.py +147 -0
  40. package/latticeai/core/workspace_os.py +420 -20
  41. package/latticeai/services/agent_runtime.py +242 -4
  42. package/latticeai/services/run_executor.py +328 -0
  43. package/latticeai/services/workspace_service.py +27 -19
  44. package/package.json +2 -14
  45. package/scripts/lint_v3.mjs +23 -0
  46. package/static/v3/asset-manifest.json +21 -14
  47. package/static/v3/js/{app.356e6452.js → app.c5c80c46.js} +1 -1
  48. package/static/v3/js/core/{api.7a308b89.js → api.ba0fbf14.js} +58 -1
  49. package/static/v3/js/core/api.js +57 -0
  50. package/static/v3/js/core/i18n.880e1fec.js +575 -0
  51. package/static/v3/js/core/i18n.js +575 -0
  52. package/static/v3/js/core/routes.37522821.js +101 -0
  53. package/static/v3/js/core/routes.js +71 -63
  54. package/static/v3/js/core/{shell.a1657f20.js → shell.e3f6bbfa.js} +67 -38
  55. package/static/v3/js/core/shell.js +65 -36
  56. package/static/v3/js/core/{store.204a08b2.js → store.7b2aa044.js} +10 -0
  57. package/static/v3/js/core/store.js +10 -0
  58. package/static/v3/js/views/account.eff40715.js +143 -0
  59. package/static/v3/js/views/account.js +143 -0
  60. package/static/v3/js/views/activity.0d271ef9.js +67 -0
  61. package/static/v3/js/views/activity.js +67 -0
  62. package/static/v3/js/views/{admin-users.03bac88c.js → admin-users.f7ac7b43.js} +4 -6
  63. package/static/v3/js/views/admin-users.js +4 -6
  64. package/static/v3/js/views/{agents.014d0b74.js → agents.17c5288d.js} +35 -12
  65. package/static/v3/js/views/agents.js +35 -12
  66. package/static/v3/js/views/{chat.e6dd7dd0.js → chat.e250e2cc.js} +23 -0
  67. package/static/v3/js/views/chat.js +23 -0
  68. package/static/v3/js/views/{knowledge-graph.5e40cbeb.js → knowledge-graph.4d09c537.js} +27 -7
  69. package/static/v3/js/views/knowledge-graph.js +27 -7
  70. package/static/v3/js/views/network.52a4f181.js +97 -0
  71. package/static/v3/js/views/network.js +97 -0
  72. package/static/v3/js/views/{planning.9ac3e313.js → planning.4876fd77.js} +26 -5
  73. package/static/v3/js/views/planning.js +26 -5
  74. package/static/v3/js/views/runs.b63b2afa.js +144 -0
  75. package/static/v3/js/views/runs.js +144 -0
  76. package/static/v3/js/views/{settings.8631fa5e.js → settings.b7140634.js} +7 -8
  77. package/static/v3/js/views/settings.js +7 -8
  78. package/static/v3/js/views/snapshots.6f5db095.js +135 -0
  79. package/static/v3/js/views/snapshots.js +135 -0
  80. package/static/v3/js/views/{workflows.26c57290.js → workflows.7752225a.js} +87 -2
  81. package/static/v3/js/views/workflows.js +87 -2
  82. package/static/v3/js/views/workspace-admin.c466029b.js +156 -0
  83. package/static/v3/js/views/workspace-admin.js +156 -0
  84. package/static/account.html +0 -113
  85. package/static/activity.html +0 -73
  86. package/static/admin.html +0 -486
  87. package/static/agents.html +0 -139
  88. package/static/chat.html +0 -841
  89. package/static/css/reference/account.css +0 -439
  90. package/static/css/reference/admin.css +0 -610
  91. package/static/css/reference/base.css +0 -1661
  92. package/static/css/reference/chat.css +0 -4623
  93. package/static/css/reference/graph.css +0 -1016
  94. package/static/css/responsive.css +0 -861
  95. package/static/graph.html +0 -122
  96. package/static/platform.css +0 -104
  97. package/static/plugins.html +0 -136
  98. package/static/scripts/account.js +0 -238
  99. package/static/scripts/admin.js +0 -1614
  100. package/static/scripts/chat.js +0 -5081
  101. package/static/scripts/graph.js +0 -1804
  102. package/static/scripts/platform.js +0 -64
  103. package/static/scripts/ux.js +0 -167
  104. package/static/scripts/workspace.js +0 -948
  105. package/static/v3/js/core/routes.7222343d.js +0 -93
  106. package/static/workflows.html +0 -146
  107. package/static/workspace.css +0 -1121
  108. package/static/workspace.html +0 -357
@@ -26,7 +26,7 @@ Guardrail summary (v1.2.0):
26
26
 
27
27
  from __future__ import annotations
28
28
 
29
- from typing import Any, Dict, Optional
29
+ from typing import Any, Callable, Dict, Optional
30
30
 
31
31
  from latticeai.core.workspace_os import WorkspaceOSStore
32
32
 
@@ -38,13 +38,20 @@ class WorkspaceService:
38
38
  # partitioned per workspace. Surfaced so the UI / docs can be explicit.
39
39
  SHARED_GLOBAL_AREAS = ("graph", "skills")
40
40
 
41
- def __init__(self, store: WorkspaceOSStore):
41
+ def __init__(self, store: WorkspaceOSStore, *, resolve_user_id: Optional[Callable[[Optional[str]], Optional[str]]] = None):
42
42
  self.store = store
43
+ self._resolve_user_id = resolve_user_id or (lambda user_id: user_id)
44
+
45
+ def _identity(self, user_id: Optional[str]) -> Optional[str]:
46
+ if isinstance(user_id, str) and user_id.startswith("user:"):
47
+ return user_id
48
+ return self._resolve_user_id(user_id)
43
49
 
44
50
  # ── scope resolution + gating ────────────────────────────────────────
45
51
 
46
52
  def _ensure_permission(self, workspace_id: str, user_id: Optional[str], permission: str) -> None:
47
- if not self.store.has_permission(workspace_id, user_id, permission):
53
+ resolved_user = self._identity(user_id)
54
+ if not self.store.has_permission(workspace_id, resolved_user, permission):
48
55
  raise PermissionError(
49
56
  f"'{user_id or 'anonymous'}' lacks '{permission}' on workspace '{workspace_id}'"
50
57
  )
@@ -67,10 +74,10 @@ class WorkspaceService:
67
74
  return workspace_id
68
75
 
69
76
  def can_read(self, workspace_id: str, user_id: Optional[str]) -> bool:
70
- return self.store.has_permission(workspace_id, user_id, "read")
77
+ return self.store.has_permission(workspace_id, self._identity(user_id), "read")
71
78
 
72
79
  def can_write(self, workspace_id: str, user_id: Optional[str]) -> bool:
73
- return self.store.has_permission(workspace_id, user_id, "write")
80
+ return self.store.has_permission(workspace_id, self._identity(user_id), "write")
74
81
 
75
82
  # ── record-level authorization (by-id access must not bypass gating) ──
76
83
 
@@ -93,12 +100,13 @@ class WorkspaceService:
93
100
  """
94
101
  owner = (record or {}).get("user_email")
95
102
  workspace_id = (record or {}).get("workspace_id")
96
- if owner and owner == user_id:
103
+ resolved_user = self._identity(user_id)
104
+ if owner and owner in {user_id, resolved_user}:
97
105
  return
98
106
  if workspace_id:
99
- self._ensure_permission(workspace_id, user_id, "write")
107
+ self._ensure_permission(workspace_id, resolved_user, "write")
100
108
  return
101
- if owner and owner != user_id:
109
+ if owner and owner not in {user_id, resolved_user}:
102
110
  raise PermissionError(
103
111
  f"'{user_id or 'anonymous'}' is not the owner of memory '{record.get('id')}'"
104
112
  )
@@ -107,42 +115,42 @@ class WorkspaceService:
107
115
 
108
116
  def summary(self, user_id: Optional[str]) -> Dict[str, Any]:
109
117
  data = self.store.summary()
110
- data["workspace_registry"] = self.store.list_workspaces(user_id=user_id)
118
+ data["workspace_registry"] = self.store.list_workspaces(user_id=self._identity(user_id))
111
119
  data["shared_global_areas"] = list(self.SHARED_GLOBAL_AREAS)
112
120
  return data
113
121
 
114
122
  def list_workspaces(self, user_id: Optional[str]) -> Dict[str, Any]:
115
- return self.store.list_workspaces(user_id=user_id)
123
+ return self.store.list_workspaces(user_id=self._identity(user_id))
116
124
 
117
125
  def get_workspace(self, workspace_id: str, user_id: Optional[str]) -> Dict[str, Any]:
118
126
  # Reading workspace metadata requires read access to that workspace.
119
127
  self._ensure_permission(workspace_id, user_id, "read")
120
- return self.store.get_workspace(workspace_id, user_id=user_id)
128
+ return self.store.get_workspace(workspace_id, user_id=self._identity(user_id))
121
129
 
122
130
  def workspace_summary(self, workspace_id: str, user_id: Optional[str]) -> Dict[str, Any]:
123
131
  self._ensure_permission(workspace_id, user_id, "read")
124
- return self.store.workspace_summary(workspace_id, user_id=user_id)
132
+ return self.store.workspace_summary(workspace_id, user_id=self._identity(user_id))
125
133
 
126
134
  # ── organization workspace management (delegates with actor) ─────────
127
135
 
128
136
  def create_organization_workspace(self, *, name: str, owner_user_id: Optional[str], settings: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
129
- return self.store.create_organization_workspace(name=name, owner_user_id=owner_user_id, settings=settings)
137
+ return self.store.create_organization_workspace(name=name, owner_user_id=self._identity(owner_user_id), settings=settings)
130
138
 
131
139
  def update_workspace(self, workspace_id: str, *, name=None, settings=None, actor=None) -> Dict[str, Any]:
132
- return self.store.update_workspace(workspace_id, name=name, settings=settings, actor=actor)
140
+ return self.store.update_workspace(workspace_id, name=name, settings=settings, actor=self._identity(actor))
133
141
 
134
142
  def archive_workspace(self, workspace_id: str, *, actor=None) -> Dict[str, Any]:
135
- return self.store.archive_workspace(workspace_id, actor=actor)
143
+ return self.store.archive_workspace(workspace_id, actor=self._identity(actor))
136
144
 
137
145
  def add_member(self, workspace_id: str, *, user_id: str, role: str = "member", actor=None) -> Dict[str, Any]:
138
- return self.store.add_member(workspace_id, user_id=user_id, role=role, actor=actor)
146
+ return self.store.add_member(workspace_id, user_id=self._identity(user_id) or user_id, role=role, actor=self._identity(actor))
139
147
 
140
148
  def update_member_role(self, workspace_id: str, *, user_id: str, role: str, actor=None) -> Dict[str, Any]:
141
- return self.store.update_member_role(workspace_id, user_id=user_id, role=role, actor=actor)
149
+ return self.store.update_member_role(workspace_id, user_id=self._identity(user_id) or user_id, role=role, actor=self._identity(actor))
142
150
 
143
151
  def remove_member(self, workspace_id: str, *, user_id: str, actor=None) -> Dict[str, Any]:
144
- return self.store.remove_member(workspace_id, user_id=user_id, actor=actor)
152
+ return self.store.remove_member(workspace_id, user_id=self._identity(user_id) or user_id, actor=self._identity(actor))
145
153
 
146
154
  def set_active_workspace(self, workspace_id: str, user_id: Optional[str]) -> Dict[str, Any]:
147
155
  # Membership is enforced inside the store for organization workspaces.
148
- return self.store.set_active_workspace(workspace_id, user_id=user_id)
156
+ return self.store.set_active_workspace(workspace_id, user_id=self._identity(user_id))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ltcai",
3
- "version": "4.0.0",
3
+ "version": "4.0.1",
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": {
@@ -21,7 +21,7 @@
21
21
  "build:assets": "node scripts/build_v3_assets.mjs",
22
22
  "build:python": "python3 -m build",
23
23
  "check:python": "python3 scripts/check_python.py",
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",
24
+ "lint": "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",
27
27
  "test": "python3 -m pytest tests/ -v",
@@ -74,21 +74,9 @@
74
74
  "mcp_registry.py",
75
75
  "latticeai/**/*.py",
76
76
  "skills/",
77
- "static/account.html",
78
- "static/chat.html",
79
- "static/admin.html",
80
- "static/graph.html",
81
- "static/workspace.html",
82
- "static/plugins.html",
83
- "static/workflows.html",
84
- "static/agents.html",
85
- "static/activity.html",
86
77
  "static/favicon.ico",
87
78
  "static/manifest.json",
88
79
  "static/sw.js",
89
- "static/workspace.css",
90
- "static/platform.css",
91
- "static/scripts/",
92
80
  "static/css/",
93
81
  "static/v3/",
94
82
  "static/icons/",
@@ -8,6 +8,8 @@
8
8
  * style.color = "#…" literals).
9
9
  * 4. Privacy: zero CDN/external URLs in shipped static HTML/CSS/JS —
10
10
  * fonts/icons/libs are vendored under static/vendor.
11
+ * 5. i18n: routes, shell, and new v4 parity views must use the SPA i18n
12
+ * runtime instead of inert localStorage-only language toggles.
11
13
  * Exits non-zero on any failure. */
12
14
  import { readdirSync, statSync, readFileSync } from "node:fs";
13
15
  import { join, dirname, relative } from "node:path";
@@ -90,6 +92,27 @@ for (const file of walk(staticRoot, [".html", ".css", ".js"]).sort()) {
90
92
  }
91
93
  console.log(`privacy: ${shippedChecked} shipped static files scanned for CDN URLs`);
92
94
 
95
+ // ── 5. i18n acceptance for T9 surfaces ──────────────────────────────────
96
+ const i18nRequired = [
97
+ "static/v3/js/core/routes.js",
98
+ "static/v3/js/core/shell.js",
99
+ "static/v3/js/views/account.js",
100
+ "static/v3/js/views/workspace-admin.js",
101
+ "static/v3/js/views/snapshots.js",
102
+ "static/v3/js/views/activity.js",
103
+ "static/v3/js/views/runs.js",
104
+ "static/v3/js/views/network.js",
105
+ ];
106
+ let i18nChecked = 0;
107
+ for (const rel of i18nRequired) {
108
+ const file = join(repo, rel);
109
+ const text = readFileSync(file, "utf8");
110
+ i18nChecked++;
111
+ if (!/i18n\.js/.test(text)) fail(`${rel}: missing i18n runtime import`);
112
+ if (!/\bt\(/.test(text)) fail(`${rel}: no translation lookup found`);
113
+ }
114
+ console.log(`i18n: ${i18nChecked} route/shell/parity modules checked`);
115
+
93
116
  if (failed) {
94
117
  console.error(`\nv3 frontend lint: ${failed} failure(s)`);
95
118
  process.exit(1);
@@ -1,8 +1,8 @@
1
1
  {
2
- "version": "4.0.0",
2
+ "version": "4.0.1",
3
3
  "generated_at": "deterministic",
4
4
  "entrypoints": {
5
- "app": "/static/v3/js/app.356e6452.js",
5
+ "app": "/static/v3/js/app.c5c80c46.js",
6
6
  "styles": [
7
7
  "/static/css/tokens.3ba22e37.css",
8
8
  "/static/v3/css/lattice.tokens.304cbc40.css",
@@ -19,38 +19,45 @@
19
19
  "static/v3/css/lattice.components.css": "/static/v3/css/lattice.components.cde18231.css",
20
20
  "static/v3/css/lattice.shell.css": "/static/v3/css/lattice.shell.29d36d85.css",
21
21
  "static/v3/css/lattice.views.css": "/static/v3/css/lattice.views.0a18b6c5.css",
22
- "static/v3/js/app.js": "/static/v3/js/app.356e6452.js",
23
- "static/v3/js/core/api.js": "/static/v3/js/core/api.7a308b89.js",
22
+ "static/v3/js/app.js": "/static/v3/js/app.c5c80c46.js",
23
+ "static/v3/js/core/api.js": "/static/v3/js/core/api.ba0fbf14.js",
24
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
+ "static/v3/js/core/i18n.js": "/static/v3/js/core/i18n.880e1fec.js",
26
27
  "static/v3/js/core/router.js": "/static/v3/js/core/router.584570f2.js",
27
- "static/v3/js/core/routes.js": "/static/v3/js/core/routes.7222343d.js",
28
- "static/v3/js/core/shell.js": "/static/v3/js/core/shell.a1657f20.js",
29
- "static/v3/js/core/store.js": "/static/v3/js/core/store.204a08b2.js",
28
+ "static/v3/js/core/routes.js": "/static/v3/js/core/routes.37522821.js",
29
+ "static/v3/js/core/shell.js": "/static/v3/js/core/shell.e3f6bbfa.js",
30
+ "static/v3/js/core/store.js": "/static/v3/js/core/store.7b2aa044.js",
31
+ "static/v3/js/views/account.js": "/static/v3/js/views/account.eff40715.js",
32
+ "static/v3/js/views/activity.js": "/static/v3/js/views/activity.0d271ef9.js",
30
33
  "static/v3/js/views/admin-audit.js": "/static/v3/js/views/admin-audit.660a1fb1.js",
31
34
  "static/v3/js/views/admin-permissions.js": "/static/v3/js/views/admin-permissions.a7ae5f09.js",
32
35
  "static/v3/js/views/admin-policies.js": "/static/v3/js/views/admin-policies.3658fd86.js",
33
36
  "static/v3/js/views/admin-private-vpc.js": "/static/v3/js/views/admin-private-vpc.7d342d36.js",
34
37
  "static/v3/js/views/admin-security.js": "/static/v3/js/views/admin-security.07c66b72.js",
35
- "static/v3/js/views/admin-users.js": "/static/v3/js/views/admin-users.03bac88c.js",
36
- "static/v3/js/views/agents.js": "/static/v3/js/views/agents.014d0b74.js",
37
- "static/v3/js/views/chat.js": "/static/v3/js/views/chat.e6dd7dd0.js",
38
+ "static/v3/js/views/admin-users.js": "/static/v3/js/views/admin-users.f7ac7b43.js",
39
+ "static/v3/js/views/agents.js": "/static/v3/js/views/agents.17c5288d.js",
40
+ "static/v3/js/views/chat.js": "/static/v3/js/views/chat.e250e2cc.js",
38
41
  "static/v3/js/views/files.js": "/static/v3/js/views/files.adad14c1.js",
39
42
  "static/v3/js/views/graph-canvas.js": "/static/v3/js/views/graph-canvas.17c15d65.js",
40
43
  "static/v3/js/views/home.js": "/static/v3/js/views/home.24f8b8ae.js",
41
44
  "static/v3/js/views/hooks.js": "/static/v3/js/views/hooks.37895880.js",
42
45
  "static/v3/js/views/hybrid-search.js": "/static/v3/js/views/hybrid-search.2fb63ed9.js",
43
- "static/v3/js/views/knowledge-graph.js": "/static/v3/js/views/knowledge-graph.5e40cbeb.js",
46
+ "static/v3/js/views/knowledge-graph.js": "/static/v3/js/views/knowledge-graph.4d09c537.js",
44
47
  "static/v3/js/views/marketplace.js": "/static/v3/js/views/marketplace.ab0583d4.js",
45
48
  "static/v3/js/views/mcp.js": "/static/v3/js/views/mcp.99b5c6a7.js",
46
49
  "static/v3/js/views/memory.js": "/static/v3/js/views/memory.4ebdf474.js",
47
50
  "static/v3/js/views/models.js": "/static/v3/js/views/models.a1ffa147.js",
48
51
  "static/v3/js/views/my-computer.js": "/static/v3/js/views/my-computer.d9d9ae1c.js",
52
+ "static/v3/js/views/network.js": "/static/v3/js/views/network.52a4f181.js",
49
53
  "static/v3/js/views/pipeline.js": "/static/v3/js/views/pipeline.c522f1ce.js",
50
- "static/v3/js/views/planning.js": "/static/v3/js/views/planning.9ac3e313.js",
51
- "static/v3/js/views/settings.js": "/static/v3/js/views/settings.8631fa5e.js",
54
+ "static/v3/js/views/planning.js": "/static/v3/js/views/planning.4876fd77.js",
55
+ "static/v3/js/views/runs.js": "/static/v3/js/views/runs.b63b2afa.js",
56
+ "static/v3/js/views/settings.js": "/static/v3/js/views/settings.b7140634.js",
52
57
  "static/v3/js/views/skills.js": "/static/v3/js/views/skills.c6c2f965.js",
58
+ "static/v3/js/views/snapshots.js": "/static/v3/js/views/snapshots.6f5db095.js",
53
59
  "static/v3/js/views/tools.js": "/static/v3/js/views/tools.e4f11276.js",
54
- "static/v3/js/views/workflows.js": "/static/v3/js/views/workflows.26c57290.js"
60
+ "static/v3/js/views/workflows.js": "/static/v3/js/views/workflows.7752225a.js",
61
+ "static/v3/js/views/workspace-admin.js": "/static/v3/js/views/workspace-admin.c466029b.js"
55
62
  }
56
63
  }
@@ -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.a1657f20.js";
6
+ import { boot } from "./core/shell.e3f6bbfa.js";
7
7
 
8
8
  const root = document.getElementById("app");
9
9
  if (root) boot(root);
@@ -11,7 +11,7 @@
11
11
  * "unavailable" → endpoint missing/down; no fake payload
12
12
  * ========================================================================== */
13
13
 
14
- import { store } from "./store.204a08b2.js";
14
+ import { store } from "./store.7b2aa044.js";
15
15
 
16
16
  const TIMEOUT_MS = 8000;
17
17
  const EMPTY_INDEX_STATUS = { generated_at: null, pipelines: {}, sources: [] };
@@ -279,6 +279,53 @@ export const api = {
279
279
 
280
280
  /* ── Organization workspaces (real backend: /workspace/orgs) ────────── */
281
281
  createOrg(name) { return raw("/workspace/orgs", { method: "POST", body: { name } }); },
282
+ workspaceRegistry() { return withFallback("/workspace/registry", {}, { workspaces: [], roles: [], permissions: {} }); },
283
+ activateWorkspace(workspace_id) { return raw("/workspace/activate", { method: "POST", body: { workspace_id } }); },
284
+ workspaceDetail(workspace_id) { return raw(`/workspace/orgs/${encodeURIComponent(workspace_id)}`); },
285
+ updateWorkspace(workspace_id, body) { return raw(`/workspace/orgs/${encodeURIComponent(workspace_id)}`, { method: "PATCH", body }); },
286
+ archiveWorkspace(workspace_id) { return raw(`/workspace/orgs/${encodeURIComponent(workspace_id)}/archive`, { method: "POST", body: {} }); },
287
+ addWorkspaceMember(workspace_id, user_id, role) {
288
+ return raw(`/workspace/orgs/${encodeURIComponent(workspace_id)}/members`, { method: "POST", body: { user_id, role } });
289
+ },
290
+ updateWorkspaceMember(workspace_id, user_id, role) {
291
+ return raw(`/workspace/orgs/${encodeURIComponent(workspace_id)}/members/${encodeURIComponent(user_id)}`, { method: "PATCH", body: { role } });
292
+ },
293
+ removeWorkspaceMember(workspace_id, user_id) {
294
+ return raw(`/workspace/orgs/${encodeURIComponent(workspace_id)}/members/${encodeURIComponent(user_id)}`, { method: "DELETE" });
295
+ },
296
+ invitations() { return withFallback("/invitations", {}, { invitations: [] }); },
297
+ createInvitation(body) { return raw("/invitations", { method: "POST", body }); },
298
+ acceptInvitation(token) { return raw(`/invitations/${encodeURIComponent(token)}/accept`, { method: "POST", body: {} }); },
299
+
300
+ /* ── Account / token-native auth ───────────────────────────────────── */
301
+ profile() { return raw("/account/profile"); },
302
+ login(email, password) { return raw("/login", { method: "POST", body: { email, password } }); },
303
+ register(body) { return raw("/register", { method: "POST", body }); },
304
+ logout() { return raw("/logout", { method: "POST", body: {} }); },
305
+ updateProfile(body) { return raw("/account/profile", { method: "PATCH", body }); },
306
+ changePassword(current_password, new_password) {
307
+ return raw("/account/change-password", { method: "POST", body: { current_password, new_password } });
308
+ },
309
+ ssoConfig() { return withFallback("/auth/sso/config", {}, { enabled: false, providers: [] }); },
310
+
311
+ /* ── Snapshots, Time Machine, realtime ─────────────────────────────── */
312
+ snapshots() { return withFallback("/workspace/snapshots", {}, { snapshots: [] }); },
313
+ createSnapshot(name) { return raw("/workspace/snapshots", { method: "POST", body: { name } }); },
314
+ compareSnapshots(before_id, after_id) { return raw("/workspace/snapshots/compare", { method: "POST", body: { before_id, after_id } }); },
315
+ snapshotExport(snapshot_id) { return raw(`/workspace/snapshots/${encodeURIComponent(snapshot_id)}/export`, { method: "POST", body: {} }); },
316
+ snapshotRestore(snapshot_id) { return raw(`/workspace/snapshots/${encodeURIComponent(snapshot_id)}/restore`, { method: "POST", body: {} }); },
317
+ timeMachine(limit = 100) { return withFallback(`/workspace/time-machine?limit=${encodeURIComponent(limit)}`, {}, { events: [] }); },
318
+ realtimeFeed(limit = 50) { return withFallback(`/realtime/feed?limit=${encodeURIComponent(limit)}`, {}, { events: [], stats: {} }); },
319
+ presence() { return withFallback("/realtime/presence", {}, { presence: [], stats: {} }); },
320
+
321
+ /* ── Approval + Brain Network surfaces ─────────────────────────────── */
322
+ permissionsPending() { return withFallback("/permissions/pending", {}, { pending: {}, count: 0 }); },
323
+ denyPermission(token) { return raw(`/permissions/deny/${encodeURIComponent(token)}`, { method: "POST" }); },
324
+ networkIdentity() { return withFallback("/network/identity", {}, {}); },
325
+ networkPeers() { return withFallback("/network/peers", {}, { peers: [] }); },
326
+ pairPeer(body) { return raw("/network/peers", { method: "POST", body }); },
327
+ unpairPeer(peer_id) { return raw(`/network/peers/${encodeURIComponent(peer_id)}`, { method: "DELETE" }); },
328
+ pushPeer(peer_id, workspace_id) { return raw(`/network/push/${encodeURIComponent(peer_id)}`, { method: "POST", body: { workspace_id } }); },
282
329
 
283
330
  /* ── Chat (real backend: SSE /chat + /history/*) ────────────────────── */
284
331
 
@@ -402,9 +449,15 @@ export const api = {
402
449
  // Workflow Agents (Part 5)
403
450
  workflowDefinitions() { return withFallback("/workflows/api/definitions", {}, { workflows: [] }); },
404
451
  createWorkflow(body) { return raw("/workflows/api/definitions", { method: "POST", body }); },
452
+ updateWorkflow(id, body) { return raw(`/workflows/api/definitions/${encodeURIComponent(id)}`, { method: "PATCH", body }); },
405
453
  runWorkflow(id, body = {}) { return raw(`/workflows/api/definitions/${encodeURIComponent(id)}/run`, { method: "POST", body }); },
406
454
  workflowRuns() { return withFallback("/workflows/api/runs", {}, { runs: [] }); },
407
455
  workflowReplay(runId) { return raw(`/workflows/api/runs/${encodeURIComponent(runId)}/replay`); },
456
+ stopWorkflowRun(runId) { return raw(`/workflows/api/runs/${encodeURIComponent(runId)}/stop`, { method: "POST" }); },
457
+ resumeWorkflowRun(runId, approved = true) {
458
+ return raw(`/workflows/api/runs/${encodeURIComponent(runId)}/resume`, { method: "POST", body: { approved } });
459
+ },
460
+ workflowTriggers() { return withFallback("/workflows/api/triggers", {}, { running: false, armed: [] }); },
408
461
 
409
462
  // Long-Term Memory + Memory Manager (Parts 7, 8)
410
463
  memoryManager() { return withFallback("/api/memory/manager", {}, { sources: [], tiers: [], usage: {} }); },
@@ -532,6 +585,10 @@ export const api = {
532
585
  return withFallback(`/api/knowledge-graph/provenance${qs}`, {}, { items: [], count: 0 });
533
586
  },
534
587
 
588
+ kgProvenanceCoverage() {
589
+ return withFallback("/knowledge-graph/provenance/coverage", {}, { total_nodes: 0, nodes_with_provenance: 0, coverage_ratio: 0 });
590
+ },
591
+
535
592
  /** POST /api/knowledge-graph/export — logical JSON export of the whole graph. */
536
593
  graphExport() { return raw("/api/knowledge-graph/export", { method: "POST", body: {} }); },
537
594
 
@@ -279,6 +279,53 @@ export const api = {
279
279
 
280
280
  /* ── Organization workspaces (real backend: /workspace/orgs) ────────── */
281
281
  createOrg(name) { return raw("/workspace/orgs", { method: "POST", body: { name } }); },
282
+ workspaceRegistry() { return withFallback("/workspace/registry", {}, { workspaces: [], roles: [], permissions: {} }); },
283
+ activateWorkspace(workspace_id) { return raw("/workspace/activate", { method: "POST", body: { workspace_id } }); },
284
+ workspaceDetail(workspace_id) { return raw(`/workspace/orgs/${encodeURIComponent(workspace_id)}`); },
285
+ updateWorkspace(workspace_id, body) { return raw(`/workspace/orgs/${encodeURIComponent(workspace_id)}`, { method: "PATCH", body }); },
286
+ archiveWorkspace(workspace_id) { return raw(`/workspace/orgs/${encodeURIComponent(workspace_id)}/archive`, { method: "POST", body: {} }); },
287
+ addWorkspaceMember(workspace_id, user_id, role) {
288
+ return raw(`/workspace/orgs/${encodeURIComponent(workspace_id)}/members`, { method: "POST", body: { user_id, role } });
289
+ },
290
+ updateWorkspaceMember(workspace_id, user_id, role) {
291
+ return raw(`/workspace/orgs/${encodeURIComponent(workspace_id)}/members/${encodeURIComponent(user_id)}`, { method: "PATCH", body: { role } });
292
+ },
293
+ removeWorkspaceMember(workspace_id, user_id) {
294
+ return raw(`/workspace/orgs/${encodeURIComponent(workspace_id)}/members/${encodeURIComponent(user_id)}`, { method: "DELETE" });
295
+ },
296
+ invitations() { return withFallback("/invitations", {}, { invitations: [] }); },
297
+ createInvitation(body) { return raw("/invitations", { method: "POST", body }); },
298
+ acceptInvitation(token) { return raw(`/invitations/${encodeURIComponent(token)}/accept`, { method: "POST", body: {} }); },
299
+
300
+ /* ── Account / token-native auth ───────────────────────────────────── */
301
+ profile() { return raw("/account/profile"); },
302
+ login(email, password) { return raw("/login", { method: "POST", body: { email, password } }); },
303
+ register(body) { return raw("/register", { method: "POST", body }); },
304
+ logout() { return raw("/logout", { method: "POST", body: {} }); },
305
+ updateProfile(body) { return raw("/account/profile", { method: "PATCH", body }); },
306
+ changePassword(current_password, new_password) {
307
+ return raw("/account/change-password", { method: "POST", body: { current_password, new_password } });
308
+ },
309
+ ssoConfig() { return withFallback("/auth/sso/config", {}, { enabled: false, providers: [] }); },
310
+
311
+ /* ── Snapshots, Time Machine, realtime ─────────────────────────────── */
312
+ snapshots() { return withFallback("/workspace/snapshots", {}, { snapshots: [] }); },
313
+ createSnapshot(name) { return raw("/workspace/snapshots", { method: "POST", body: { name } }); },
314
+ compareSnapshots(before_id, after_id) { return raw("/workspace/snapshots/compare", { method: "POST", body: { before_id, after_id } }); },
315
+ snapshotExport(snapshot_id) { return raw(`/workspace/snapshots/${encodeURIComponent(snapshot_id)}/export`, { method: "POST", body: {} }); },
316
+ snapshotRestore(snapshot_id) { return raw(`/workspace/snapshots/${encodeURIComponent(snapshot_id)}/restore`, { method: "POST", body: {} }); },
317
+ timeMachine(limit = 100) { return withFallback(`/workspace/time-machine?limit=${encodeURIComponent(limit)}`, {}, { events: [] }); },
318
+ realtimeFeed(limit = 50) { return withFallback(`/realtime/feed?limit=${encodeURIComponent(limit)}`, {}, { events: [], stats: {} }); },
319
+ presence() { return withFallback("/realtime/presence", {}, { presence: [], stats: {} }); },
320
+
321
+ /* ── Approval + Brain Network surfaces ─────────────────────────────── */
322
+ permissionsPending() { return withFallback("/permissions/pending", {}, { pending: {}, count: 0 }); },
323
+ denyPermission(token) { return raw(`/permissions/deny/${encodeURIComponent(token)}`, { method: "POST" }); },
324
+ networkIdentity() { return withFallback("/network/identity", {}, {}); },
325
+ networkPeers() { return withFallback("/network/peers", {}, { peers: [] }); },
326
+ pairPeer(body) { return raw("/network/peers", { method: "POST", body }); },
327
+ unpairPeer(peer_id) { return raw(`/network/peers/${encodeURIComponent(peer_id)}`, { method: "DELETE" }); },
328
+ pushPeer(peer_id, workspace_id) { return raw(`/network/push/${encodeURIComponent(peer_id)}`, { method: "POST", body: { workspace_id } }); },
282
329
 
283
330
  /* ── Chat (real backend: SSE /chat + /history/*) ────────────────────── */
284
331
 
@@ -402,9 +449,15 @@ export const api = {
402
449
  // Workflow Agents (Part 5)
403
450
  workflowDefinitions() { return withFallback("/workflows/api/definitions", {}, { workflows: [] }); },
404
451
  createWorkflow(body) { return raw("/workflows/api/definitions", { method: "POST", body }); },
452
+ updateWorkflow(id, body) { return raw(`/workflows/api/definitions/${encodeURIComponent(id)}`, { method: "PATCH", body }); },
405
453
  runWorkflow(id, body = {}) { return raw(`/workflows/api/definitions/${encodeURIComponent(id)}/run`, { method: "POST", body }); },
406
454
  workflowRuns() { return withFallback("/workflows/api/runs", {}, { runs: [] }); },
407
455
  workflowReplay(runId) { return raw(`/workflows/api/runs/${encodeURIComponent(runId)}/replay`); },
456
+ stopWorkflowRun(runId) { return raw(`/workflows/api/runs/${encodeURIComponent(runId)}/stop`, { method: "POST" }); },
457
+ resumeWorkflowRun(runId, approved = true) {
458
+ return raw(`/workflows/api/runs/${encodeURIComponent(runId)}/resume`, { method: "POST", body: { approved } });
459
+ },
460
+ workflowTriggers() { return withFallback("/workflows/api/triggers", {}, { running: false, armed: [] }); },
408
461
 
409
462
  // Long-Term Memory + Memory Manager (Parts 7, 8)
410
463
  memoryManager() { return withFallback("/api/memory/manager", {}, { sources: [], tiers: [], usage: {} }); },
@@ -532,6 +585,10 @@ export const api = {
532
585
  return withFallback(`/api/knowledge-graph/provenance${qs}`, {}, { items: [], count: 0 });
533
586
  },
534
587
 
588
+ kgProvenanceCoverage() {
589
+ return withFallback("/knowledge-graph/provenance/coverage", {}, { total_nodes: 0, nodes_with_provenance: 0, coverage_ratio: 0 });
590
+ },
591
+
535
592
  /** POST /api/knowledge-graph/export — logical JSON export of the whole graph. */
536
593
  graphExport() { return raw("/api/knowledge-graph/export", { method: "POST", body: {} }); },
537
594