cozo-memory 1.0.7 β 1.0.8
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 +38 -10
- package/dist/eval-suite.js +136 -0
- package/dist/hybrid-search.js +99 -0
- package/dist/index.js +267 -43
- package/dist/inference-engine.js +7 -0
- package/dist/make-old.js +58 -0
- package/dist/test-agentic-retrieval.js +28 -0
- package/dist/test-discovery.js +53 -0
- package/dist/test-graphrag.js +35 -0
- package/dist/verify-agentic-logic.js +64 -0
- package/package.json +2 -1
- package/dist/test-mcp-search.js +0 -47
- package/dist/tui-blessed.js +0 -789
- package/dist/tui.py +0 -481
package/dist/tui.py
DELETED
|
@@ -1,481 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
Modern TUI for CozoDB Memory using Textual
|
|
4
|
-
Features: Mouse support, interactive menus, real-time updates
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
from textual.app import App, ComposeResult
|
|
8
|
-
from textual.containers import Container, Horizontal, Vertical, ScrollableContainer
|
|
9
|
-
from textual.widgets import Header, Footer, Button, Static, Input, Tree, Label, DataTable, TabbedContent, TabPane
|
|
10
|
-
from textual.binding import Binding
|
|
11
|
-
from textual import events
|
|
12
|
-
import subprocess
|
|
13
|
-
import json
|
|
14
|
-
import sys
|
|
15
|
-
from pathlib import Path
|
|
16
|
-
|
|
17
|
-
class CozoMemoryTUI(App):
|
|
18
|
-
"""Textual TUI for CozoDB Memory"""
|
|
19
|
-
|
|
20
|
-
CSS = """
|
|
21
|
-
Screen {
|
|
22
|
-
background: $surface;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
#sidebar {
|
|
26
|
-
width: 30;
|
|
27
|
-
background: $panel;
|
|
28
|
-
border-right: solid $primary;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
#main-content {
|
|
32
|
-
width: 1fr;
|
|
33
|
-
padding: 1 2;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
Button {
|
|
37
|
-
width: 100%;
|
|
38
|
-
margin: 1 0;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
.success {
|
|
42
|
-
color: $success;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
.error {
|
|
46
|
-
color: $error;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
.info {
|
|
50
|
-
color: $accent;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
#result-container {
|
|
54
|
-
height: 1fr;
|
|
55
|
-
border: solid $primary;
|
|
56
|
-
padding: 1;
|
|
57
|
-
margin-top: 1;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
Input {
|
|
61
|
-
margin: 1 0;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
Label {
|
|
65
|
-
margin: 1 0;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
DataTable {
|
|
69
|
-
height: 1fr;
|
|
70
|
-
}
|
|
71
|
-
"""
|
|
72
|
-
|
|
73
|
-
BINDINGS = [
|
|
74
|
-
Binding("q", "quit", "Quit"),
|
|
75
|
-
Binding("h", "show_help", "Help"),
|
|
76
|
-
Binding("r", "refresh", "Refresh"),
|
|
77
|
-
]
|
|
78
|
-
|
|
79
|
-
def __init__(self):
|
|
80
|
-
super().__init__()
|
|
81
|
-
self.cli_path = self._find_cli_path()
|
|
82
|
-
|
|
83
|
-
def _find_cli_path(self) -> str:
|
|
84
|
-
"""Find the cozo-memory CLI executable"""
|
|
85
|
-
# Try different locations
|
|
86
|
-
possible_paths = [
|
|
87
|
-
Path(__file__).parent.parent / "dist" / "cli.js",
|
|
88
|
-
Path.cwd() / "dist" / "cli.js",
|
|
89
|
-
]
|
|
90
|
-
|
|
91
|
-
for path in possible_paths:
|
|
92
|
-
if path.exists():
|
|
93
|
-
return str(path)
|
|
94
|
-
|
|
95
|
-
# Fallback to global installation
|
|
96
|
-
return "cozo-memory"
|
|
97
|
-
|
|
98
|
-
def compose(self) -> ComposeResult:
|
|
99
|
-
"""Create child widgets"""
|
|
100
|
-
yield Header(show_clock=True)
|
|
101
|
-
|
|
102
|
-
with Horizontal():
|
|
103
|
-
# Sidebar with navigation
|
|
104
|
-
with Vertical(id="sidebar"):
|
|
105
|
-
yield Static("π§ CozoDB Memory", classes="info")
|
|
106
|
-
yield Button("π System Health", id="btn-health", variant="primary")
|
|
107
|
-
yield Button("β Create Entity", id="btn-create-entity")
|
|
108
|
-
yield Button("π Search", id="btn-search")
|
|
109
|
-
yield Button("πΈοΈ Graph Operations", id="btn-graph")
|
|
110
|
-
yield Button("π€ Export", id="btn-export")
|
|
111
|
-
yield Button("π₯ Import", id="btn-import")
|
|
112
|
-
yield Button("π List Entities", id="btn-list")
|
|
113
|
-
|
|
114
|
-
# Main content area
|
|
115
|
-
with ScrollableContainer(id="main-content"):
|
|
116
|
-
yield Static("Welcome to CozoDB Memory TUI", id="welcome-text", classes="info")
|
|
117
|
-
yield Static("Click a button or use keyboard shortcuts", id="help-text")
|
|
118
|
-
|
|
119
|
-
# Dynamic content container
|
|
120
|
-
with Container(id="result-container"):
|
|
121
|
-
yield Static("Results will appear here...", id="result-text")
|
|
122
|
-
|
|
123
|
-
yield Footer()
|
|
124
|
-
|
|
125
|
-
def _run_cli_command(self, *args, use_json_format: bool = True) -> dict:
|
|
126
|
-
"""Execute CLI command and return JSON result"""
|
|
127
|
-
try:
|
|
128
|
-
cmd = ["node", self.cli_path] + list(args)
|
|
129
|
-
# Only add -f json for commands that support it
|
|
130
|
-
if use_json_format:
|
|
131
|
-
cmd.extend(["-f", "json"])
|
|
132
|
-
|
|
133
|
-
result = subprocess.run(
|
|
134
|
-
cmd,
|
|
135
|
-
capture_output=True,
|
|
136
|
-
text=True,
|
|
137
|
-
timeout=30
|
|
138
|
-
)
|
|
139
|
-
|
|
140
|
-
if result.returncode != 0:
|
|
141
|
-
return {"error": result.stderr or "Command failed"}
|
|
142
|
-
|
|
143
|
-
# Parse JSON output - stdout should be pure JSON
|
|
144
|
-
if use_json_format:
|
|
145
|
-
try:
|
|
146
|
-
# Parse the JSON directly from stdout
|
|
147
|
-
parsed = json.loads(result.stdout)
|
|
148
|
-
return {"success": True, "data": parsed}
|
|
149
|
-
except json.JSONDecodeError as e:
|
|
150
|
-
# If JSON parsing fails, return error with details
|
|
151
|
-
return {"error": f"Failed to parse JSON: {str(e)}\nOutput: {result.stdout[:200]}"}
|
|
152
|
-
else:
|
|
153
|
-
# For non-JSON commands, return raw output
|
|
154
|
-
return {"success": True, "data": {"output": result.stdout}}
|
|
155
|
-
|
|
156
|
-
except subprocess.TimeoutExpired:
|
|
157
|
-
return {"error": "Command timed out"}
|
|
158
|
-
except Exception as e:
|
|
159
|
-
return {"error": str(e)}
|
|
160
|
-
|
|
161
|
-
def _update_result(self, data: dict):
|
|
162
|
-
"""Update the result container with new data"""
|
|
163
|
-
# Always recreate the Static widget to avoid markup issues
|
|
164
|
-
container = self.query_one("#result-container", Container)
|
|
165
|
-
container.remove_children()
|
|
166
|
-
|
|
167
|
-
if "error" in data:
|
|
168
|
-
# Show error without markup
|
|
169
|
-
content = f"ERROR:\n{data['error']}"
|
|
170
|
-
elif "success" in data and data["success"]:
|
|
171
|
-
# Format the data nicely
|
|
172
|
-
formatted = json.dumps(data["data"], indent=2)
|
|
173
|
-
# Truncate if too long
|
|
174
|
-
if len(formatted) > 5000:
|
|
175
|
-
formatted = formatted[:5000] + "\n... (truncated)"
|
|
176
|
-
content = f"SUCCESS:\n{formatted}"
|
|
177
|
-
else:
|
|
178
|
-
# Fallback
|
|
179
|
-
formatted = json.dumps(data, indent=2)
|
|
180
|
-
content = formatted
|
|
181
|
-
|
|
182
|
-
# Create new Static widget with markup disabled
|
|
183
|
-
result_text = Static(content, id="result-text", markup=False)
|
|
184
|
-
container.mount(result_text)
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
async def action_show_health(self) -> None:
|
|
189
|
-
"""Show system health"""
|
|
190
|
-
self.query_one("#welcome-text", Static).update("π System Health")
|
|
191
|
-
result = self._run_cli_command("system", "health")
|
|
192
|
-
self._update_result(result)
|
|
193
|
-
|
|
194
|
-
async def action_create_entity(self) -> None:
|
|
195
|
-
"""Show create entity form"""
|
|
196
|
-
self.query_one("#welcome-text", Static).update("β Create Entity")
|
|
197
|
-
|
|
198
|
-
# Replace result container with form
|
|
199
|
-
container = self.query_one("#result-container", Container)
|
|
200
|
-
await container.remove_children()
|
|
201
|
-
|
|
202
|
-
await container.mount(
|
|
203
|
-
Label("Entity Name:"),
|
|
204
|
-
Input(placeholder="Enter entity name", id="input-name"),
|
|
205
|
-
Label("Entity Type:"),
|
|
206
|
-
Input(placeholder="Enter entity type", id="input-type"),
|
|
207
|
-
Label("Metadata (JSON, optional):"),
|
|
208
|
-
Input(placeholder='{"key": "value"}', id="input-metadata"),
|
|
209
|
-
Button("Create", id="btn-submit-entity", variant="success")
|
|
210
|
-
)
|
|
211
|
-
|
|
212
|
-
async def action_search(self) -> None:
|
|
213
|
-
"""Show search form"""
|
|
214
|
-
self.query_one("#welcome-text", Static).update("π Search Memory")
|
|
215
|
-
|
|
216
|
-
container = self.query_one("#result-container", Container)
|
|
217
|
-
await container.remove_children()
|
|
218
|
-
|
|
219
|
-
await container.mount(
|
|
220
|
-
Label("Search Query:"),
|
|
221
|
-
Input(placeholder="Enter search query", id="input-search-query"),
|
|
222
|
-
Label("Limit (optional):"),
|
|
223
|
-
Input(placeholder="10", id="input-search-limit"),
|
|
224
|
-
Button("Search", id="btn-submit-search", variant="primary")
|
|
225
|
-
)
|
|
226
|
-
|
|
227
|
-
async def action_graph_menu(self) -> None:
|
|
228
|
-
"""Show graph operations menu"""
|
|
229
|
-
self.query_one("#welcome-text", Static).update("πΈοΈ Graph Operations")
|
|
230
|
-
|
|
231
|
-
container = self.query_one("#result-container", Container)
|
|
232
|
-
await container.remove_children()
|
|
233
|
-
|
|
234
|
-
await container.mount(
|
|
235
|
-
Static("Select a graph operation:", classes="info"),
|
|
236
|
-
Button("π PageRank", id="btn-graph-pagerank"),
|
|
237
|
-
Button("ποΈ Communities", id="btn-graph-communities"),
|
|
238
|
-
Button("π Explore from Entity", id="btn-graph-explore")
|
|
239
|
-
)
|
|
240
|
-
|
|
241
|
-
async def action_export_menu(self) -> None:
|
|
242
|
-
"""Show export menu"""
|
|
243
|
-
self.query_one("#welcome-text", Static).update("π€ Export Memory")
|
|
244
|
-
|
|
245
|
-
container = self.query_one("#result-container", Container)
|
|
246
|
-
await container.remove_children()
|
|
247
|
-
|
|
248
|
-
await container.mount(
|
|
249
|
-
Static("Select export format:", classes="info"),
|
|
250
|
-
Label("Output File:"),
|
|
251
|
-
Input(placeholder="export.json", id="input-export-file"),
|
|
252
|
-
Button("Export as JSON", id="btn-export-json"),
|
|
253
|
-
Button("Export as Markdown", id="btn-export-md"),
|
|
254
|
-
Button("Export as Obsidian ZIP", id="btn-export-obsidian")
|
|
255
|
-
)
|
|
256
|
-
|
|
257
|
-
async def action_import_menu(self) -> None:
|
|
258
|
-
"""Show import menu"""
|
|
259
|
-
self.query_one("#welcome-text", Static).update("π₯ Import Memory")
|
|
260
|
-
|
|
261
|
-
container = self.query_one("#result-container", Container)
|
|
262
|
-
await container.remove_children()
|
|
263
|
-
|
|
264
|
-
await container.mount(
|
|
265
|
-
Static("Import data from file:", classes="info"),
|
|
266
|
-
Label("Input File:"),
|
|
267
|
-
Input(placeholder="import.json", id="input-import-file"),
|
|
268
|
-
Label("Format:"),
|
|
269
|
-
Input(placeholder="cozo", id="input-import-format"),
|
|
270
|
-
Button("Import", id="btn-submit-import", variant="warning")
|
|
271
|
-
)
|
|
272
|
-
|
|
273
|
-
async def action_list_entities(self) -> None:
|
|
274
|
-
"""List all entities"""
|
|
275
|
-
self.query_one("#welcome-text", Static).update("π Entity List")
|
|
276
|
-
|
|
277
|
-
# Get health to show entity count
|
|
278
|
-
result = self._run_cli_command("system", "health")
|
|
279
|
-
|
|
280
|
-
container = self.query_one("#result-container", Container)
|
|
281
|
-
await container.remove_children()
|
|
282
|
-
|
|
283
|
-
if "success" in result and result["success"]:
|
|
284
|
-
health_data = result["data"]
|
|
285
|
-
await container.mount(
|
|
286
|
-
Static(f"Total Entities: {health_data.get('entities', 0)}"),
|
|
287
|
-
Static(f"Total Observations: {health_data.get('observations', 0)}"),
|
|
288
|
-
Static(f"Total Relationships: {health_data.get('relationships', 0)}"),
|
|
289
|
-
Static("\nUse CLI to get detailed entity list:\ncozo-memory entity get -i <entity-id>")
|
|
290
|
-
)
|
|
291
|
-
else:
|
|
292
|
-
await container.mount(Static(f"Error: {result.get('error', 'Unknown error')}"))
|
|
293
|
-
|
|
294
|
-
async def on_button_pressed(self, event: Button.Pressed) -> None:
|
|
295
|
-
"""Handle all button presses"""
|
|
296
|
-
button_id = event.button.id
|
|
297
|
-
|
|
298
|
-
# Main menu buttons
|
|
299
|
-
if button_id == "btn-health":
|
|
300
|
-
await self.action_show_health()
|
|
301
|
-
elif button_id == "btn-create-entity":
|
|
302
|
-
await self.action_create_entity()
|
|
303
|
-
elif button_id == "btn-search":
|
|
304
|
-
await self.action_search()
|
|
305
|
-
elif button_id == "btn-graph":
|
|
306
|
-
await self.action_graph_menu()
|
|
307
|
-
elif button_id == "btn-export":
|
|
308
|
-
await self.action_export_menu()
|
|
309
|
-
elif button_id == "btn-import":
|
|
310
|
-
await self.action_import_menu()
|
|
311
|
-
elif button_id == "btn-list":
|
|
312
|
-
await self.action_list_entities()
|
|
313
|
-
|
|
314
|
-
# Form submission buttons
|
|
315
|
-
elif button_id == "btn-submit-entity":
|
|
316
|
-
await self.handle_create_entity()
|
|
317
|
-
elif button_id == "btn-submit-search":
|
|
318
|
-
await self.handle_search()
|
|
319
|
-
elif button_id == "btn-submit-import":
|
|
320
|
-
await self.handle_import()
|
|
321
|
-
|
|
322
|
-
# Graph operation buttons
|
|
323
|
-
elif button_id == "btn-graph-pagerank":
|
|
324
|
-
await self.handle_graph_pagerank()
|
|
325
|
-
elif button_id == "btn-graph-communities":
|
|
326
|
-
await self.handle_graph_communities()
|
|
327
|
-
elif button_id == "btn-graph-explore":
|
|
328
|
-
await self.handle_graph_explore_form()
|
|
329
|
-
|
|
330
|
-
# Export buttons
|
|
331
|
-
elif button_id == "btn-export-json":
|
|
332
|
-
await self.handle_export("json")
|
|
333
|
-
elif button_id == "btn-export-md":
|
|
334
|
-
await self.handle_export("markdown")
|
|
335
|
-
elif button_id == "btn-export-obsidian":
|
|
336
|
-
await self.handle_export("obsidian")
|
|
337
|
-
|
|
338
|
-
# Graph explore submit
|
|
339
|
-
elif button_id == "btn-submit-explore":
|
|
340
|
-
await self.handle_graph_explore()
|
|
341
|
-
|
|
342
|
-
async def handle_create_entity(self) -> None:
|
|
343
|
-
"""Handle entity creation form submission"""
|
|
344
|
-
name = self.query_one("#input-name", Input).value
|
|
345
|
-
entity_type = self.query_one("#input-type", Input).value
|
|
346
|
-
metadata = self.query_one("#input-metadata", Input).value
|
|
347
|
-
|
|
348
|
-
if not name or not entity_type:
|
|
349
|
-
self._update_result({"error": "Name and type are required"})
|
|
350
|
-
return
|
|
351
|
-
|
|
352
|
-
args = ["entity", "create", "-n", name, "-t", entity_type]
|
|
353
|
-
if metadata:
|
|
354
|
-
args.extend(["-m", metadata])
|
|
355
|
-
|
|
356
|
-
result = self._run_cli_command(*args)
|
|
357
|
-
self._update_result(result)
|
|
358
|
-
|
|
359
|
-
async def handle_search(self) -> None:
|
|
360
|
-
"""Handle search form submission"""
|
|
361
|
-
query = self.query_one("#input-search-query", Input).value
|
|
362
|
-
limit = self.query_one("#input-search-limit", Input).value
|
|
363
|
-
|
|
364
|
-
if not query:
|
|
365
|
-
self._update_result({"error": "Search query is required"})
|
|
366
|
-
return
|
|
367
|
-
|
|
368
|
-
args = ["search", "query", "-q", query]
|
|
369
|
-
if limit:
|
|
370
|
-
args.extend(["-l", limit])
|
|
371
|
-
|
|
372
|
-
result = self._run_cli_command(*args)
|
|
373
|
-
self._update_result(result)
|
|
374
|
-
|
|
375
|
-
async def handle_import(self) -> None:
|
|
376
|
-
"""Handle import form submission"""
|
|
377
|
-
file_path = self.query_one("#input-import-file", Input).value
|
|
378
|
-
format_type = self.query_one("#input-import-format", Input).value
|
|
379
|
-
|
|
380
|
-
if not file_path:
|
|
381
|
-
self._update_result({"error": "File path is required"})
|
|
382
|
-
return
|
|
383
|
-
|
|
384
|
-
args = ["import", "file", "-i", file_path, "-f", format_type or "cozo"]
|
|
385
|
-
# Import commands don't use -f json format
|
|
386
|
-
result = self._run_cli_command(*args, use_json_format=False)
|
|
387
|
-
self._update_result(result)
|
|
388
|
-
|
|
389
|
-
async def handle_graph_pagerank(self) -> None:
|
|
390
|
-
"""Execute PageRank"""
|
|
391
|
-
self.query_one("#welcome-text", Static).update("π Computing PageRank...")
|
|
392
|
-
result = self._run_cli_command("graph", "pagerank")
|
|
393
|
-
self._update_result(result)
|
|
394
|
-
|
|
395
|
-
async def handle_graph_communities(self) -> None:
|
|
396
|
-
"""Execute community detection"""
|
|
397
|
-
self.query_one("#welcome-text", Static).update("ποΈ Detecting Communities...")
|
|
398
|
-
result = self._run_cli_command("graph", "communities")
|
|
399
|
-
self._update_result(result)
|
|
400
|
-
|
|
401
|
-
async def handle_graph_explore_form(self) -> None:
|
|
402
|
-
"""Show graph explore form"""
|
|
403
|
-
container = self.query_one("#result-container", Container)
|
|
404
|
-
await container.remove_children()
|
|
405
|
-
|
|
406
|
-
await container.mount(
|
|
407
|
-
Label("Start Entity ID:"),
|
|
408
|
-
Input(placeholder="Enter entity ID", id="input-explore-start"),
|
|
409
|
-
Label("Max Hops:"),
|
|
410
|
-
Input(placeholder="3", id="input-explore-hops"),
|
|
411
|
-
Button("Explore", id="btn-submit-explore", variant="primary")
|
|
412
|
-
)
|
|
413
|
-
|
|
414
|
-
async def handle_graph_explore(self) -> None:
|
|
415
|
-
"""Execute graph exploration"""
|
|
416
|
-
start_id = self.query_one("#input-explore-start", Input).value
|
|
417
|
-
hops = self.query_one("#input-explore-hops", Input).value
|
|
418
|
-
|
|
419
|
-
if not start_id:
|
|
420
|
-
self._update_result({"error": "Start entity ID is required"})
|
|
421
|
-
return
|
|
422
|
-
|
|
423
|
-
args = ["graph", "explore", "-s", start_id]
|
|
424
|
-
if hops:
|
|
425
|
-
args.extend(["-h", hops])
|
|
426
|
-
|
|
427
|
-
result = self._run_cli_command(*args)
|
|
428
|
-
self._update_result(result)
|
|
429
|
-
|
|
430
|
-
async def handle_export(self, format_type: str) -> None:
|
|
431
|
-
"""Handle export"""
|
|
432
|
-
file_input = self.query_one("#input-export-file", Input)
|
|
433
|
-
file_path = file_input.value or f"export.{format_type}"
|
|
434
|
-
|
|
435
|
-
if format_type == "json":
|
|
436
|
-
args = ["export", "json", "-o", file_path, "--include-metadata", "--include-relationships", "--include-observations"]
|
|
437
|
-
elif format_type == "markdown":
|
|
438
|
-
args = ["export", "markdown", "-o", file_path]
|
|
439
|
-
else: # obsidian
|
|
440
|
-
args = ["export", "obsidian", "-o", file_path]
|
|
441
|
-
|
|
442
|
-
# Export commands don't use -f json format
|
|
443
|
-
result = self._run_cli_command(*args, use_json_format=False)
|
|
444
|
-
if "success" in result and result["success"]:
|
|
445
|
-
result = {"success": True, "data": {"message": f"Exported to {file_path}"}}
|
|
446
|
-
self._update_result(result)
|
|
447
|
-
|
|
448
|
-
def action_show_help(self) -> None:
|
|
449
|
-
"""Show help information"""
|
|
450
|
-
self.query_one("#welcome-text", Static).update("β Help")
|
|
451
|
-
help_text = """
|
|
452
|
-
[bold cyan]Keyboard Shortcuts:[/bold cyan]
|
|
453
|
-
β’ q - Quit application
|
|
454
|
-
β’ h - Show this help
|
|
455
|
-
β’ r - Refresh current view
|
|
456
|
-
|
|
457
|
-
[bold cyan]Mouse Support:[/bold cyan]
|
|
458
|
-
β’ Click buttons to navigate
|
|
459
|
-
β’ Scroll with mouse wheel
|
|
460
|
-
β’ Click input fields to type
|
|
461
|
-
|
|
462
|
-
[bold cyan]CLI Commands:[/bold cyan]
|
|
463
|
-
All operations can also be done via CLI:
|
|
464
|
-
β’ cozo-memory entity create -n "Name" -t "type"
|
|
465
|
-
β’ cozo-memory search query -q "search term"
|
|
466
|
-
β’ cozo-memory graph pagerank
|
|
467
|
-
β’ cozo-memory export json -o backup.json
|
|
468
|
-
"""
|
|
469
|
-
container = self.query_one("#result-container", Container)
|
|
470
|
-
container.remove_children()
|
|
471
|
-
container.mount(Static(help_text))
|
|
472
|
-
|
|
473
|
-
def action_refresh(self) -> None:
|
|
474
|
-
"""Refresh current view"""
|
|
475
|
-
self.query_one("#welcome-text", Static).update("π Refreshed")
|
|
476
|
-
self.action_show_health()
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
if __name__ == "__main__":
|
|
480
|
-
app = CozoMemoryTUI()
|
|
481
|
-
app.run()
|