npcsh 1.1.20__py3-none-any.whl → 1.1.21__py3-none-any.whl
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.
- npcsh/_state.py +5 -71
- npcsh/diff_viewer.py +3 -3
- npcsh/npc_team/jinxs/lib/core/compress.jinx +373 -85
- npcsh/npc_team/jinxs/lib/core/search/db_search.jinx +17 -6
- npcsh/npc_team/jinxs/lib/core/search/file_search.jinx +17 -6
- npcsh/npc_team/jinxs/lib/core/search/kg_search.jinx +19 -8
- npcsh/npc_team/jinxs/lib/core/search/web_search.jinx +52 -14
- npcsh/npc_team/jinxs/{bin → lib/utils}/benchmark.jinx +2 -2
- npcsh/npc_team/jinxs/{bin → lib/utils}/jinxs.jinx +12 -12
- npcsh/npc_team/jinxs/{bin → lib/utils}/models.jinx +7 -7
- npcsh/npc_team/jinxs/{bin → lib/utils}/setup.jinx +6 -6
- npcsh/npc_team/jinxs/modes/alicanto.jinx +1573 -296
- npcsh/npc_team/jinxs/modes/arxiv.jinx +5 -5
- npcsh/npc_team/jinxs/modes/config_tui.jinx +300 -0
- npcsh/npc_team/jinxs/modes/corca.jinx +3 -3
- npcsh/npc_team/jinxs/modes/git.jinx +795 -0
- {npcsh-1.1.20.data/data/npcsh/npc_team → npcsh/npc_team/jinxs/modes}/kg.jinx +13 -13
- npcsh/npc_team/jinxs/modes/memories.jinx +414 -0
- npcsh/npc_team/jinxs/{bin → modes}/nql.jinx +10 -21
- npcsh/npc_team/jinxs/modes/papers.jinx +578 -0
- npcsh/npc_team/jinxs/modes/plonk.jinx +490 -304
- npcsh/npc_team/jinxs/modes/reattach.jinx +3 -3
- npcsh/npc_team/jinxs/modes/spool.jinx +3 -3
- npcsh/npc_team/jinxs/{bin → modes}/team.jinx +12 -12
- npcsh/npc_team/jinxs/modes/vixynt.jinx +388 -0
- npcsh/npc_team/jinxs/modes/wander.jinx +454 -181
- npcsh/npc_team/jinxs/modes/yap.jinx +10 -3
- npcsh/npcsh.py +112 -47
- npcsh/routes.py +4 -1
- npcsh/salmon_simulation.py +0 -0
- npcsh-1.1.21.data/data/npcsh/npc_team/alicanto.jinx +1633 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/arxiv.jinx +5 -5
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/benchmark.jinx +2 -2
- npcsh-1.1.21.data/data/npcsh/npc_team/compress.jinx +428 -0
- npcsh-1.1.21.data/data/npcsh/npc_team/config_tui.jinx +300 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/corca.jinx +3 -3
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/db_search.jinx +17 -6
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/file_search.jinx +17 -6
- npcsh-1.1.21.data/data/npcsh/npc_team/git.jinx +795 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/jinxs.jinx +12 -12
- {npcsh/npc_team/jinxs/bin → npcsh-1.1.21.data/data/npcsh/npc_team}/kg.jinx +13 -13
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/kg_search.jinx +19 -8
- npcsh-1.1.21.data/data/npcsh/npc_team/memories.jinx +414 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/models.jinx +7 -7
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/nql.jinx +10 -21
- npcsh-1.1.21.data/data/npcsh/npc_team/papers.jinx +578 -0
- npcsh-1.1.21.data/data/npcsh/npc_team/plonk.jinx +565 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/reattach.jinx +3 -3
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/setup.jinx +6 -6
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/spool.jinx +3 -3
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/team.jinx +12 -12
- npcsh-1.1.21.data/data/npcsh/npc_team/vixynt.jinx +388 -0
- npcsh-1.1.21.data/data/npcsh/npc_team/wander.jinx +728 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/web_search.jinx +52 -14
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/yap.jinx +10 -3
- {npcsh-1.1.20.dist-info → npcsh-1.1.21.dist-info}/METADATA +2 -2
- {npcsh-1.1.20.dist-info → npcsh-1.1.21.dist-info}/RECORD +145 -150
- npcsh-1.1.21.dist-info/entry_points.txt +11 -0
- npcsh/npc_team/jinxs/bin/config_tui.jinx +0 -300
- npcsh/npc_team/jinxs/bin/memories.jinx +0 -317
- npcsh/npc_team/jinxs/bin/vixynt.jinx +0 -122
- npcsh/npc_team/jinxs/lib/core/search/mem_review.jinx +0 -73
- npcsh/npc_team/jinxs/lib/core/search/mem_search.jinx +0 -388
- npcsh/npc_team/jinxs/lib/research/paper_search.jinx +0 -412
- npcsh/npc_team/jinxs/lib/research/semantic_scholar.jinx +0 -386
- npcsh/npc_team/plonkjr.npc +0 -23
- npcsh-1.1.20.data/data/npcsh/npc_team/alicanto.jinx +0 -356
- npcsh-1.1.20.data/data/npcsh/npc_team/compress.jinx +0 -140
- npcsh-1.1.20.data/data/npcsh/npc_team/config_tui.jinx +0 -300
- npcsh-1.1.20.data/data/npcsh/npc_team/mem_review.jinx +0 -73
- npcsh-1.1.20.data/data/npcsh/npc_team/mem_search.jinx +0 -388
- npcsh-1.1.20.data/data/npcsh/npc_team/memories.jinx +0 -317
- npcsh-1.1.20.data/data/npcsh/npc_team/paper_search.jinx +0 -412
- npcsh-1.1.20.data/data/npcsh/npc_team/plonk.jinx +0 -379
- npcsh-1.1.20.data/data/npcsh/npc_team/plonkjr.npc +0 -23
- npcsh-1.1.20.data/data/npcsh/npc_team/semantic_scholar.jinx +0 -386
- npcsh-1.1.20.data/data/npcsh/npc_team/vixynt.jinx +0 -122
- npcsh-1.1.20.data/data/npcsh/npc_team/wander.jinx +0 -455
- npcsh-1.1.20.dist-info/entry_points.txt +0 -25
- /npcsh/npc_team/jinxs/lib/{orchestration → core}/convene.jinx +0 -0
- /npcsh/npc_team/jinxs/lib/{orchestration → core}/delegate.jinx +0 -0
- /npcsh/npc_team/jinxs/{bin → lib/core}/sample.jinx +0 -0
- /npcsh/npc_team/jinxs/{bin → lib/utils}/sync.jinx +0 -0
- /npcsh/npc_team/jinxs/{bin → modes}/roll.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/add_tab.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/alicanto.npc +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/alicanto.png +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/browser_action.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/browser_screenshot.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/build.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/chat.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/click.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/close_browser.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/close_pane.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/close_tab.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/cmd.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/compile.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/confirm.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/convene.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/corca.npc +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/corca.png +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/corca_example.png +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/delegate.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/edit_file.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/focus_pane.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/frederic.npc +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/frederic4.png +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/guac.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/guac.npc +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/guac.png +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/help.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/incognide.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/init.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/kadiefa.npc +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/kadiefa.png +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/key_press.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/launch_app.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/list_panes.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/load_file.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/navigate.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/notify.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/npcsh.ctx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/npcsh_sibiji.png +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/open_browser.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/open_pane.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/ots.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/paste.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/plonk.npc +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/plonk.png +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/plonkjr.png +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/pti.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/python.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/read_pane.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/roll.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/run_terminal.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/sample.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/screenshot.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/search.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/send_message.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/serve.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/set.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/sh.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/shh.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/sibiji.npc +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/sibiji.png +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/sleep.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/split_pane.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/spool.png +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/sql.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/switch.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/switch_npc.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/switch_tab.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/switches.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/sync.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/teamviz.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/trigger.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/type_text.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/usage.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/verbose.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/wait.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/write_file.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/yap.png +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/zen_mode.jinx +0 -0
- {npcsh-1.1.20.dist-info → npcsh-1.1.21.dist-info}/WHEEL +0 -0
- {npcsh-1.1.20.dist-info → npcsh-1.1.21.dist-info}/licenses/LICENSE +0 -0
- {npcsh-1.1.20.dist-info → npcsh-1.1.21.dist-info}/top_level.txt +0 -0
|
@@ -104,8 +104,8 @@ steps:
|
|
|
104
104
|
|
|
105
105
|
# Search filter
|
|
106
106
|
if ui.search_query:
|
|
107
|
-
|
|
108
|
-
items = [j for j in items if
|
|
107
|
+
srch = ui.search_query.lower()
|
|
108
|
+
items = [j for j in items if srch in j['name'].lower() or srch in j['description'].lower()]
|
|
109
109
|
|
|
110
110
|
ui.filtered = items
|
|
111
111
|
# Clamp selection
|
|
@@ -129,8 +129,8 @@ steps:
|
|
|
129
129
|
# ── header ──
|
|
130
130
|
hdr = " Jinxs "
|
|
131
131
|
pad = '=' * W
|
|
132
|
-
out.append(wline(1, f"\033[
|
|
133
|
-
out.append(f"\033[1;{max(1, (W - len(hdr)) // 2)}H\033[
|
|
132
|
+
out.append(wline(1, f"\033[7;1m{pad}\033[0m"))
|
|
133
|
+
out.append(f"\033[1;{max(1, (W - len(hdr)) // 2)}H\033[7;1m{hdr}\033[0m")
|
|
134
134
|
|
|
135
135
|
# ── tabs ──
|
|
136
136
|
tb = ""
|
|
@@ -184,7 +184,7 @@ steps:
|
|
|
184
184
|
foot = " [j/k] Scroll [q/Esc] Back"
|
|
185
185
|
else:
|
|
186
186
|
foot = " [Tab] Filter [j/k] Nav [Enter] Detail [/] Search [q] Quit"
|
|
187
|
-
out.append(wline(H, f"\033[
|
|
187
|
+
out.append(wline(H, f"\033[7m{foot[:W].ljust(W)}\033[0m"))
|
|
188
188
|
|
|
189
189
|
sys.stdout.write(''.join(out))
|
|
190
190
|
sys.stdout.flush()
|
|
@@ -296,10 +296,10 @@ steps:
|
|
|
296
296
|
return True
|
|
297
297
|
|
|
298
298
|
def handle_esc():
|
|
299
|
-
if select.select([
|
|
300
|
-
c2 =
|
|
299
|
+
if select.select([fd], [], [], 0.05)[0]:
|
|
300
|
+
c2 = os.read(fd, 1).decode('latin-1')
|
|
301
301
|
if c2 == '[':
|
|
302
|
-
c3 =
|
|
302
|
+
c3 = os.read(fd, 1).decode('latin-1')
|
|
303
303
|
if c3 == 'A':
|
|
304
304
|
nav_up()
|
|
305
305
|
elif c3 == 'B':
|
|
@@ -322,10 +322,10 @@ steps:
|
|
|
322
322
|
def handle_search(c):
|
|
323
323
|
if c == '\x1b':
|
|
324
324
|
# Check if arrow key or bare esc
|
|
325
|
-
if select.select([
|
|
326
|
-
c2 =
|
|
325
|
+
if select.select([fd], [], [], 0.05)[0]:
|
|
326
|
+
c2 = os.read(fd, 1).decode('latin-1')
|
|
327
327
|
if c2 == '[':
|
|
328
|
-
|
|
328
|
+
os.read(fd, 1).decode('latin-1') # consume arrow char
|
|
329
329
|
else:
|
|
330
330
|
ui.search_mode = False
|
|
331
331
|
ui.search_buf = ""
|
|
@@ -395,7 +395,7 @@ steps:
|
|
|
395
395
|
sys.stdout.flush()
|
|
396
396
|
render()
|
|
397
397
|
while True:
|
|
398
|
-
c =
|
|
398
|
+
c = os.read(fd, 1).decode('latin-1')
|
|
399
399
|
if not handle(c):
|
|
400
400
|
break
|
|
401
401
|
render()
|
|
@@ -166,12 +166,12 @@ steps:
|
|
|
166
166
|
|
|
167
167
|
def do_search(query):
|
|
168
168
|
ui.search_results = []
|
|
169
|
-
|
|
169
|
+
pat = f"%{query}%"
|
|
170
170
|
with engine.connect() as conn:
|
|
171
171
|
r = conn.execute(text(
|
|
172
172
|
"SELECT statement, source_text, type, generation, origin "
|
|
173
|
-
"FROM kg_facts WHERE statement LIKE :
|
|
174
|
-
), {"
|
|
173
|
+
"FROM kg_facts WHERE statement LIKE :pat ORDER BY rowid DESC"
|
|
174
|
+
), {"pat": pat})
|
|
175
175
|
for row in r:
|
|
176
176
|
ui.search_results.append({
|
|
177
177
|
'kind': 'fact',
|
|
@@ -377,8 +377,8 @@ steps:
|
|
|
377
377
|
# ── header ──
|
|
378
378
|
hdr = " Knowledge Graph "
|
|
379
379
|
pad = '=' * W
|
|
380
|
-
out.append(wline(1, f"\033[
|
|
381
|
-
out.append(f"\033[1;{max(1,(W - len(hdr))//2)}H\033[
|
|
380
|
+
out.append(wline(1, f"\033[7;1m{pad}\033[0m"))
|
|
381
|
+
out.append(f"\033[1;{max(1,(W - len(hdr))//2)}H\033[7;1m{hdr}\033[0m")
|
|
382
382
|
|
|
383
383
|
# ── tabs ──
|
|
384
384
|
tb = ""
|
|
@@ -439,7 +439,7 @@ steps:
|
|
|
439
439
|
foot = " [Tab] Switch [j/k] Select [Enter] Center [Backspace] Back [q] Quit"
|
|
440
440
|
else:
|
|
441
441
|
foot = " [Tab] Switch [j/k] Nav [Enter] Detail [/] Search [g] Gen [q] Quit"
|
|
442
|
-
out.append(wline(H, f"\033[
|
|
442
|
+
out.append(wline(H, f"\033[7m{foot[:W].ljust(W)}\033[0m"))
|
|
443
443
|
|
|
444
444
|
sys.stdout.write(''.join(out))
|
|
445
445
|
sys.stdout.flush()
|
|
@@ -779,10 +779,10 @@ steps:
|
|
|
779
779
|
return True
|
|
780
780
|
|
|
781
781
|
def handle_esc():
|
|
782
|
-
if select.select([
|
|
783
|
-
c2 =
|
|
782
|
+
if select.select([fd], [], [], 0.05)[0]:
|
|
783
|
+
c2 = os.read(fd, 1).decode('latin-1')
|
|
784
784
|
if c2 == '[':
|
|
785
|
-
c3 =
|
|
785
|
+
c3 = os.read(fd, 1).decode('latin-1')
|
|
786
786
|
if c3 == 'A':
|
|
787
787
|
nav_up()
|
|
788
788
|
elif c3 == 'B':
|
|
@@ -796,10 +796,10 @@ steps:
|
|
|
796
796
|
|
|
797
797
|
def handle_search_input(c):
|
|
798
798
|
if c == '\x1b':
|
|
799
|
-
if select.select([
|
|
800
|
-
c2 =
|
|
799
|
+
if select.select([fd], [], [], 0.05)[0]:
|
|
800
|
+
c2 = os.read(fd, 1).decode('latin-1')
|
|
801
801
|
if c2 == '[':
|
|
802
|
-
|
|
802
|
+
os.read(fd, 1).decode('latin-1')
|
|
803
803
|
else:
|
|
804
804
|
ui.search_mode = False
|
|
805
805
|
ui.search_buf = ""
|
|
@@ -929,7 +929,7 @@ steps:
|
|
|
929
929
|
sys.stdout.flush()
|
|
930
930
|
render()
|
|
931
931
|
while True:
|
|
932
|
-
c =
|
|
932
|
+
c = os.read(fd, 1).decode('latin-1')
|
|
933
933
|
if not handle(c):
|
|
934
934
|
break
|
|
935
935
|
render()
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
jinx_name: kg_search
|
|
2
2
|
description: Search the knowledge graph with interactive TUI
|
|
3
|
+
interactive: true
|
|
3
4
|
inputs:
|
|
4
5
|
- query: ""
|
|
5
6
|
- type: "facts"
|
|
@@ -241,11 +242,11 @@ steps:
|
|
|
241
242
|
# Header
|
|
242
243
|
if mode == 'list':
|
|
243
244
|
sort_ind = {'score': '1', 'concept': '2', 'type': '3'}[sort_mode]
|
|
244
|
-
|
|
245
|
-
header = f" KG SEARCH ({len(display_results)} results): '{
|
|
245
|
+
label = query or concept or search_type
|
|
246
|
+
header = f" KG SEARCH ({len(display_results)} results): '{label}' [sort:{sort_mode}({sort_ind}) filter:{type_filter}] "
|
|
246
247
|
else:
|
|
247
248
|
header = f" PREVIEW: {display_results[selected]['type']} "
|
|
248
|
-
sys.stdout.write(f'\033[
|
|
249
|
+
sys.stdout.write(f'\033[7;1m{header.ljust(width)}\033[0m\n')
|
|
249
250
|
|
|
250
251
|
# Column headers
|
|
251
252
|
if mode == 'list':
|
|
@@ -286,7 +287,7 @@ steps:
|
|
|
286
287
|
sel = display_results[selected] if display_results else {}
|
|
287
288
|
source = sel.get('source', '')
|
|
288
289
|
sys.stdout.write(f'\033[{height-1};1H\033[K Source: {source}'.ljust(width))
|
|
289
|
-
sys.stdout.write(f'\033[{height};1H\033[K\033[
|
|
290
|
+
sys.stdout.write(f'\033[{height};1H\033[K\033[7m j/k:Nav 1/2/3:Sort c:Concepts e:Explore p:Preview q:Quit [{selected+1}/{len(display_results)}] \033[0m')
|
|
290
291
|
|
|
291
292
|
else: # preview mode
|
|
292
293
|
sel = display_results[selected]
|
|
@@ -311,16 +312,26 @@ steps:
|
|
|
311
312
|
|
|
312
313
|
sys.stdout.write(f'\033[{height-2};1H\033[K\033[90m{"─" * width}\033[0m')
|
|
313
314
|
sys.stdout.write(f'\033[{height-1};1H\033[K [{preview_scroll+1}/{len(all_lines)} lines]')
|
|
314
|
-
sys.stdout.write(f'\033[{height};1H\033[K\033[
|
|
315
|
+
sys.stdout.write(f'\033[{height};1H\033[K\033[7m j/k:Scroll b:Back e:Explore q:Quit \033[0m')
|
|
315
316
|
|
|
316
317
|
sys.stdout.flush()
|
|
317
318
|
|
|
318
|
-
c =
|
|
319
|
+
c = os.read(fd, 1).decode('latin-1')
|
|
319
320
|
|
|
320
321
|
if c == '\x1b':
|
|
321
|
-
|
|
322
|
+
import select as _sel
|
|
323
|
+
if _sel.select([fd], [], [], 0.05)[0]:
|
|
324
|
+
c2 = os.read(fd, 1).decode('latin-1')
|
|
325
|
+
else:
|
|
326
|
+
if mode == 'preview':
|
|
327
|
+
mode = 'list'
|
|
328
|
+
sys.stdout.write('\033[2J\033[H')
|
|
329
|
+
else:
|
|
330
|
+
context['output'] = "Cancelled."
|
|
331
|
+
break
|
|
332
|
+
continue
|
|
322
333
|
if c2 == '[':
|
|
323
|
-
c3 =
|
|
334
|
+
c3 = os.read(fd, 1).decode('latin-1')
|
|
324
335
|
if c3 == 'A': # Up
|
|
325
336
|
if mode == 'list' and selected > 0:
|
|
326
337
|
selected -= 1
|
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
jinx_name: memories
|
|
2
|
+
description: Interactive TUI for browsing and managing npcsh memories
|
|
3
|
+
interactive: true
|
|
4
|
+
inputs:
|
|
5
|
+
- scope: ""
|
|
6
|
+
steps:
|
|
7
|
+
- name: memory_browser
|
|
8
|
+
engine: python
|
|
9
|
+
code: |
|
|
10
|
+
import os
|
|
11
|
+
import sys
|
|
12
|
+
import tty
|
|
13
|
+
import termios
|
|
14
|
+
import select
|
|
15
|
+
import time
|
|
16
|
+
from datetime import datetime
|
|
17
|
+
|
|
18
|
+
if not sys.stdin.isatty():
|
|
19
|
+
context['output'] = "Memory browser requires an interactive terminal."
|
|
20
|
+
|
|
21
|
+
else:
|
|
22
|
+
from npcpy.memory.command_history import CommandHistory
|
|
23
|
+
from npcsh.config import NPCSH_DB_PATH
|
|
24
|
+
from sqlalchemy import text
|
|
25
|
+
|
|
26
|
+
db_path = os.path.expanduser(NPCSH_DB_PATH)
|
|
27
|
+
command_history = CommandHistory(db_path)
|
|
28
|
+
|
|
29
|
+
# ========== Discover actual status values from DB ==========
|
|
30
|
+
db_statuses = []
|
|
31
|
+
try:
|
|
32
|
+
with command_history.engine.connect() as conn:
|
|
33
|
+
rows = conn.execute(text("SELECT DISTINCT status FROM memory_lifecycle ORDER BY status"))
|
|
34
|
+
db_statuses = [r[0] for r in rows if r[0]]
|
|
35
|
+
except:
|
|
36
|
+
pass
|
|
37
|
+
|
|
38
|
+
# Build tabs: All + pending first, then rest
|
|
39
|
+
ordered = []
|
|
40
|
+
for s in db_statuses:
|
|
41
|
+
if 'pending' in s.lower():
|
|
42
|
+
ordered.insert(0, s)
|
|
43
|
+
else:
|
|
44
|
+
ordered.append(s)
|
|
45
|
+
tab_names = ['All'] + ordered
|
|
46
|
+
tab_filters = [None] + ordered
|
|
47
|
+
|
|
48
|
+
# ========== State ==========
|
|
49
|
+
class MemState:
|
|
50
|
+
tab = 0
|
|
51
|
+
tabs = tab_names
|
|
52
|
+
tab_filt = tab_filters
|
|
53
|
+
memories = []
|
|
54
|
+
sel = 0
|
|
55
|
+
scroll = 0
|
|
56
|
+
preview = False
|
|
57
|
+
msg = ""
|
|
58
|
+
msg_color = "33"
|
|
59
|
+
npc_filter = None
|
|
60
|
+
team_filter = None
|
|
61
|
+
approved_count = 0
|
|
62
|
+
rejected_count = 0
|
|
63
|
+
|
|
64
|
+
st = MemState()
|
|
65
|
+
|
|
66
|
+
# ========== Helpers ==========
|
|
67
|
+
def get_size():
|
|
68
|
+
try:
|
|
69
|
+
s = os.get_terminal_size()
|
|
70
|
+
return s.columns, s.lines
|
|
71
|
+
except:
|
|
72
|
+
return 80, 24
|
|
73
|
+
|
|
74
|
+
def status_icon(sv):
|
|
75
|
+
if not sv:
|
|
76
|
+
return '\033[90m?\033[0m'
|
|
77
|
+
s = sv.lower()
|
|
78
|
+
if 'approved' in s:
|
|
79
|
+
return '\033[1;32m+\033[0m'
|
|
80
|
+
if 'edited' in s:
|
|
81
|
+
return '\033[1;36m~\033[0m'
|
|
82
|
+
if 'rejected' in s:
|
|
83
|
+
return '\033[1;31m-\033[0m'
|
|
84
|
+
if 'pending' in s:
|
|
85
|
+
return '\033[1;33m*\033[0m'
|
|
86
|
+
return '\033[90m?\033[0m'
|
|
87
|
+
|
|
88
|
+
def status_color(sv):
|
|
89
|
+
if not sv:
|
|
90
|
+
return '0'
|
|
91
|
+
s = sv.lower()
|
|
92
|
+
if 'approved' in s:
|
|
93
|
+
return '32'
|
|
94
|
+
if 'edited' in s:
|
|
95
|
+
return '36'
|
|
96
|
+
if 'rejected' in s:
|
|
97
|
+
return '31'
|
|
98
|
+
if 'pending' in s:
|
|
99
|
+
return '33'
|
|
100
|
+
return '0'
|
|
101
|
+
|
|
102
|
+
def load_memories():
|
|
103
|
+
st.memories = []
|
|
104
|
+
try:
|
|
105
|
+
with command_history.engine.connect() as conn:
|
|
106
|
+
sf = st.tab_filt[st.tab] if st.tab < len(st.tab_filt) else None
|
|
107
|
+
q = "SELECT id, created_at, npc, team, directory_path, initial_memory, final_memory, status FROM memory_lifecycle"
|
|
108
|
+
conds = []
|
|
109
|
+
params = {}
|
|
110
|
+
|
|
111
|
+
if sf:
|
|
112
|
+
conds.append("status = :sf")
|
|
113
|
+
params['sf'] = sf
|
|
114
|
+
if st.npc_filter:
|
|
115
|
+
conds.append("npc = :npc")
|
|
116
|
+
params['npc'] = st.npc_filter
|
|
117
|
+
if st.team_filter:
|
|
118
|
+
conds.append("team = :team")
|
|
119
|
+
params['team'] = st.team_filter
|
|
120
|
+
|
|
121
|
+
if conds:
|
|
122
|
+
q += " WHERE " + " AND ".join(conds)
|
|
123
|
+
q += " ORDER BY created_at DESC LIMIT 200"
|
|
124
|
+
|
|
125
|
+
result = conn.execute(text(q), params)
|
|
126
|
+
for row in result:
|
|
127
|
+
st.memories.append({
|
|
128
|
+
'id': row[0],
|
|
129
|
+
'created_at': row[1],
|
|
130
|
+
'npc': row[2],
|
|
131
|
+
'team': row[3],
|
|
132
|
+
'scope': row[4] or '',
|
|
133
|
+
'original': row[5],
|
|
134
|
+
'final': row[6],
|
|
135
|
+
'status': row[7]
|
|
136
|
+
})
|
|
137
|
+
except Exception as e:
|
|
138
|
+
st.msg = "DB Error: " + str(e)
|
|
139
|
+
st.msg_color = "31"
|
|
140
|
+
|
|
141
|
+
def do_update(memory_id, new_status, final_mem=None):
|
|
142
|
+
"""Update memory status in DB and reload list."""
|
|
143
|
+
try:
|
|
144
|
+
command_history.update_memory_status(memory_id, new_status, final_mem)
|
|
145
|
+
old_count = len(st.memories)
|
|
146
|
+
old_sel = st.sel
|
|
147
|
+
load_memories()
|
|
148
|
+
new_count = len(st.memories)
|
|
149
|
+
|
|
150
|
+
# Clamp selection
|
|
151
|
+
if st.memories:
|
|
152
|
+
st.sel = min(old_sel, len(st.memories) - 1)
|
|
153
|
+
else:
|
|
154
|
+
st.sel = 0
|
|
155
|
+
|
|
156
|
+
# Fix scroll
|
|
157
|
+
_, height = get_size()
|
|
158
|
+
vis = max(1, height - 7)
|
|
159
|
+
if st.sel < st.scroll:
|
|
160
|
+
st.scroll = st.sel
|
|
161
|
+
elif st.sel >= st.scroll + vis:
|
|
162
|
+
st.scroll = st.sel - vis + 1
|
|
163
|
+
|
|
164
|
+
return True
|
|
165
|
+
except Exception as e:
|
|
166
|
+
st.msg = "UPDATE FAILED: " + str(e)
|
|
167
|
+
st.msg_color = "31"
|
|
168
|
+
return False
|
|
169
|
+
|
|
170
|
+
def format_date(dt_str):
|
|
171
|
+
if not dt_str:
|
|
172
|
+
return " "
|
|
173
|
+
try:
|
|
174
|
+
if isinstance(dt_str, str):
|
|
175
|
+
dt = datetime.fromisoformat(dt_str.replace('Z', '+00:00'))
|
|
176
|
+
else:
|
|
177
|
+
dt = dt_str
|
|
178
|
+
return dt.strftime('%m-%d %H:%M')
|
|
179
|
+
except:
|
|
180
|
+
return str(dt_str)[:10]
|
|
181
|
+
|
|
182
|
+
# ========== Rendering ==========
|
|
183
|
+
def render():
|
|
184
|
+
width, height = get_size()
|
|
185
|
+
out = []
|
|
186
|
+
|
|
187
|
+
# Header with session stats
|
|
188
|
+
stats = ""
|
|
189
|
+
if st.approved_count or st.rejected_count:
|
|
190
|
+
stats = " [+" + str(st.approved_count) + " -" + str(st.rejected_count) + "]"
|
|
191
|
+
header = " MEMORIES (" + str(len(st.memories)) + ")" + stats + " "
|
|
192
|
+
out.append("\033[1;1H\033[K\033[7;1m" + header.ljust(width) + "\033[0m")
|
|
193
|
+
|
|
194
|
+
# Tabs
|
|
195
|
+
tab_str = ""
|
|
196
|
+
for i, tab in enumerate(st.tabs):
|
|
197
|
+
if i == st.tab:
|
|
198
|
+
tab_str += "\033[1;7m [" + tab + "] \033[0m"
|
|
199
|
+
else:
|
|
200
|
+
tab_str += " \033[90m" + tab + "\033[0m "
|
|
201
|
+
out.append("\033[2;1H\033[K " + tab_str)
|
|
202
|
+
|
|
203
|
+
# Separator
|
|
204
|
+
out.append("\033[3;1H\033[K\033[90m" + ("-" * width) + "\033[0m")
|
|
205
|
+
|
|
206
|
+
if st.preview and st.memories:
|
|
207
|
+
render_preview(out, width, height)
|
|
208
|
+
else:
|
|
209
|
+
render_list(out, width, height)
|
|
210
|
+
|
|
211
|
+
# Status bar
|
|
212
|
+
out.append("\033[" + str(height-2) + ";1H\033[K\033[90m" + ("-" * width) + "\033[0m")
|
|
213
|
+
out.append("\033[" + str(height-1) + ";1H\033[K")
|
|
214
|
+
if st.msg:
|
|
215
|
+
out.append(" \033[" + st.msg_color + ";1m" + st.msg[:width-2] + "\033[0m")
|
|
216
|
+
|
|
217
|
+
# Footer
|
|
218
|
+
if st.preview:
|
|
219
|
+
foot = " [Esc] Back [a] Approve [x] Reject [j/k] Prev/Next [q] Quit "
|
|
220
|
+
else:
|
|
221
|
+
foot = " [Tab] Filter [j/k] Nav [Enter] Preview [a] Approve [x] Reject [q] Quit "
|
|
222
|
+
out.append("\033[" + str(height) + ";1H\033[K\033[7m" + foot.ljust(width) + "\033[0m")
|
|
223
|
+
|
|
224
|
+
sys.stdout.write(''.join(out))
|
|
225
|
+
sys.stdout.flush()
|
|
226
|
+
|
|
227
|
+
def render_list(out, width, height):
|
|
228
|
+
vis_h = height - 7
|
|
229
|
+
if vis_h < 1:
|
|
230
|
+
vis_h = 1
|
|
231
|
+
|
|
232
|
+
for i in range(vis_h):
|
|
233
|
+
row = 4 + i
|
|
234
|
+
out.append("\033[" + str(row) + ";1H\033[K")
|
|
235
|
+
idx = st.scroll + i
|
|
236
|
+
if idx >= len(st.memories):
|
|
237
|
+
continue
|
|
238
|
+
|
|
239
|
+
mem = st.memories[idx]
|
|
240
|
+
icon = status_icon(mem['status'])
|
|
241
|
+
date_str = format_date(mem['created_at'])
|
|
242
|
+
npc_str = (mem['npc'] or '-')[:8]
|
|
243
|
+
content = (mem['final'] or mem['original'] or '')[:width-35].replace('\n', ' ')
|
|
244
|
+
|
|
245
|
+
line = icon + " " + date_str + " " + npc_str.ljust(9) + content
|
|
246
|
+
|
|
247
|
+
if idx == st.sel:
|
|
248
|
+
out.append("\033[7m " + line + " \033[0m")
|
|
249
|
+
else:
|
|
250
|
+
out.append(" " + line)
|
|
251
|
+
|
|
252
|
+
# Scroll indicator
|
|
253
|
+
if len(st.memories) > vis_h and vis_h > 0:
|
|
254
|
+
total = max(1, len(st.memories) - vis_h)
|
|
255
|
+
pct = int((st.scroll / total) * 100) if total > 0 else 0
|
|
256
|
+
out.append("\033[4;" + str(width-6) + "H\033[90m[" + str(pct) + "%]\033[0m")
|
|
257
|
+
|
|
258
|
+
if not st.memories:
|
|
259
|
+
out.append("\033[6;4H\033[90mNo memories found for this filter.\033[0m")
|
|
260
|
+
out.append("\033[7;4H\033[90mTry switching tabs with Tab key.\033[0m")
|
|
261
|
+
|
|
262
|
+
def render_preview(out, width, height):
|
|
263
|
+
if not st.memories or st.sel >= len(st.memories):
|
|
264
|
+
return
|
|
265
|
+
|
|
266
|
+
mem = st.memories[st.sel]
|
|
267
|
+
|
|
268
|
+
row = 4
|
|
269
|
+
sc = status_color(mem['status'])
|
|
270
|
+
out.append("\033[" + str(row) + ";1H\033[K\033[1m Memory #" + str(mem['id']) + " \033[" + sc + "m[" + str(mem['status']) + "]\033[0m")
|
|
271
|
+
row += 1
|
|
272
|
+
|
|
273
|
+
out.append("\033[" + str(row) + ";1H\033[K\033[90m Date: " + format_date(mem['created_at']) + " NPC: " + str(mem['npc'] or '-') + " Team: " + str(mem['team'] or '-') + "\033[0m")
|
|
274
|
+
row += 1
|
|
275
|
+
out.append("\033[" + str(row) + ";1H\033[K\033[90m Scope: " + str(mem['scope'] or '-')[:60] + "\033[0m")
|
|
276
|
+
row += 1
|
|
277
|
+
out.append("\033[" + str(row) + ";1H\033[K")
|
|
278
|
+
row += 1
|
|
279
|
+
|
|
280
|
+
out.append("\033[" + str(row) + ";1H\033[K\033[1m Content:\033[0m")
|
|
281
|
+
row += 1
|
|
282
|
+
|
|
283
|
+
content = mem['final'] or mem['original'] or '(empty)'
|
|
284
|
+
for line in content.split('\n')[:height - row - 3]:
|
|
285
|
+
out.append("\033[" + str(row) + ";1H\033[K " + line[:width-5])
|
|
286
|
+
row += 1
|
|
287
|
+
|
|
288
|
+
if mem['final'] and mem['original'] and mem['final'] != mem['original']:
|
|
289
|
+
out.append("\033[" + str(row) + ";1H\033[K")
|
|
290
|
+
row += 1
|
|
291
|
+
out.append("\033[" + str(row) + ";1H\033[K\033[90;1m Original:\033[0m")
|
|
292
|
+
row += 1
|
|
293
|
+
for line in mem['original'].split('\n')[:3]:
|
|
294
|
+
if row >= height - 3:
|
|
295
|
+
break
|
|
296
|
+
out.append("\033[" + str(row) + ";1H\033[K\033[90m " + line[:width-5] + "\033[0m")
|
|
297
|
+
row += 1
|
|
298
|
+
|
|
299
|
+
while row < height - 2:
|
|
300
|
+
out.append("\033[" + str(row) + ";1H\033[K")
|
|
301
|
+
row += 1
|
|
302
|
+
|
|
303
|
+
# ========== Input ==========
|
|
304
|
+
def handle_input(c):
|
|
305
|
+
if c == 'q' or c == '\x03':
|
|
306
|
+
return False
|
|
307
|
+
|
|
308
|
+
if c == '\x1b':
|
|
309
|
+
if select.select([fd], [], [], 0.05)[0]:
|
|
310
|
+
c2 = os.read(fd, 1).decode('latin-1')
|
|
311
|
+
if c2 == '[':
|
|
312
|
+
c3 = os.read(fd, 1).decode('latin-1')
|
|
313
|
+
if c3 == 'A':
|
|
314
|
+
move_up()
|
|
315
|
+
elif c3 == 'B':
|
|
316
|
+
move_down()
|
|
317
|
+
elif c3 == 'Z':
|
|
318
|
+
# Shift+Tab = prev tab
|
|
319
|
+
st.tab = (st.tab - 1) % len(st.tabs)
|
|
320
|
+
st.sel = 0
|
|
321
|
+
st.scroll = 0
|
|
322
|
+
load_memories()
|
|
323
|
+
st.msg = ""
|
|
324
|
+
else:
|
|
325
|
+
if st.preview:
|
|
326
|
+
st.preview = False
|
|
327
|
+
return True
|
|
328
|
+
|
|
329
|
+
if c == '\t':
|
|
330
|
+
st.tab = (st.tab + 1) % len(st.tabs)
|
|
331
|
+
st.sel = 0
|
|
332
|
+
st.scroll = 0
|
|
333
|
+
load_memories()
|
|
334
|
+
st.msg = ""
|
|
335
|
+
st.msg_color = "33"
|
|
336
|
+
elif c == 'k':
|
|
337
|
+
move_up()
|
|
338
|
+
elif c == 'j':
|
|
339
|
+
move_down()
|
|
340
|
+
elif c == '\r' or c == '\n' or c == 'p':
|
|
341
|
+
if st.memories:
|
|
342
|
+
st.preview = not st.preview
|
|
343
|
+
elif c == 'a':
|
|
344
|
+
approve_current()
|
|
345
|
+
elif c == 'x':
|
|
346
|
+
reject_current()
|
|
347
|
+
|
|
348
|
+
return True
|
|
349
|
+
|
|
350
|
+
def move_up():
|
|
351
|
+
st.sel = max(0, st.sel - 1)
|
|
352
|
+
if st.sel < st.scroll:
|
|
353
|
+
st.scroll = st.sel
|
|
354
|
+
st.msg = ""
|
|
355
|
+
|
|
356
|
+
def move_down():
|
|
357
|
+
_, height = get_size()
|
|
358
|
+
vis = max(1, height - 7)
|
|
359
|
+
st.sel = min(max(0, len(st.memories) - 1), st.sel + 1)
|
|
360
|
+
if st.sel >= st.scroll + vis:
|
|
361
|
+
st.scroll = st.sel - vis + 1
|
|
362
|
+
st.msg = ""
|
|
363
|
+
|
|
364
|
+
def approve_current():
|
|
365
|
+
if not st.memories or st.sel >= len(st.memories):
|
|
366
|
+
st.msg = "No memory selected"
|
|
367
|
+
st.msg_color = "33"
|
|
368
|
+
return
|
|
369
|
+
mem = st.memories[st.sel]
|
|
370
|
+
final = mem.get('final') or mem.get('original')
|
|
371
|
+
if do_update(mem['id'], 'human-approved', final):
|
|
372
|
+
st.approved_count += 1
|
|
373
|
+
st.msg = "APPROVED #" + str(mem['id'])
|
|
374
|
+
st.msg_color = "32"
|
|
375
|
+
|
|
376
|
+
def reject_current():
|
|
377
|
+
if not st.memories or st.sel >= len(st.memories):
|
|
378
|
+
st.msg = "No memory selected"
|
|
379
|
+
st.msg_color = "33"
|
|
380
|
+
return
|
|
381
|
+
mem = st.memories[st.sel]
|
|
382
|
+
if do_update(mem['id'], 'human-rejected'):
|
|
383
|
+
st.rejected_count += 1
|
|
384
|
+
st.msg = "REJECTED #" + str(mem['id'])
|
|
385
|
+
st.msg_color = "31"
|
|
386
|
+
|
|
387
|
+
# ========== Main Loop ==========
|
|
388
|
+
load_memories()
|
|
389
|
+
|
|
390
|
+
fd = sys.stdin.fileno()
|
|
391
|
+
old_settings = termios.tcgetattr(fd)
|
|
392
|
+
|
|
393
|
+
try:
|
|
394
|
+
tty.setcbreak(fd)
|
|
395
|
+
sys.stdout.write('\033[?25l')
|
|
396
|
+
sys.stdout.write('\033[2J')
|
|
397
|
+
render()
|
|
398
|
+
|
|
399
|
+
while True:
|
|
400
|
+
c = os.read(fd, 1).decode('latin-1')
|
|
401
|
+
if not handle_input(c):
|
|
402
|
+
break
|
|
403
|
+
render()
|
|
404
|
+
|
|
405
|
+
finally:
|
|
406
|
+
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
|
|
407
|
+
sys.stdout.write('\033[?25h')
|
|
408
|
+
sys.stdout.write('\033[2J\033[H')
|
|
409
|
+
sys.stdout.flush()
|
|
410
|
+
|
|
411
|
+
summary = "Memory browser closed."
|
|
412
|
+
if st.approved_count or st.rejected_count:
|
|
413
|
+
summary += " Session: " + str(st.approved_count) + " approved, " + str(st.rejected_count) + " rejected."
|
|
414
|
+
context['output'] = summary
|
|
@@ -120,8 +120,8 @@ steps:
|
|
|
120
120
|
# -- header --
|
|
121
121
|
hdr = " Models "
|
|
122
122
|
pad = '=' * W
|
|
123
|
-
out.append(wline(1, f"\033[
|
|
124
|
-
out.append(f"\033[1;{max(1,(W - len(hdr)) // 2)}H\033[
|
|
123
|
+
out.append(wline(1, f"\033[7;1m{pad}\033[0m"))
|
|
124
|
+
out.append(f"\033[1;{max(1,(W - len(hdr)) // 2)}H\033[7;1m{hdr}\033[0m")
|
|
125
125
|
|
|
126
126
|
# -- tabs --
|
|
127
127
|
tb = ""
|
|
@@ -205,7 +205,7 @@ steps:
|
|
|
205
205
|
# combine status into footer area
|
|
206
206
|
foot = " [Tab] Filter [j/k] Nav [c] Set Chat [v] Set Vision [e] Set Embed [r] Set Reasoning [d] Refresh [q] Quit"
|
|
207
207
|
out.append(wline(H - 1, stat_line))
|
|
208
|
-
out.append(wline(H, f"\033[
|
|
208
|
+
out.append(wline(H, f"\033[7m{foot[:W].ljust(W)}\033[0m"))
|
|
209
209
|
|
|
210
210
|
sys.stdout.write(''.join(out))
|
|
211
211
|
sys.stdout.flush()
|
|
@@ -240,10 +240,10 @@ steps:
|
|
|
240
240
|
return True
|
|
241
241
|
|
|
242
242
|
def handle_esc():
|
|
243
|
-
if select.select([
|
|
244
|
-
c2 =
|
|
243
|
+
if select.select([fd], [], [], 0.05)[0]:
|
|
244
|
+
c2 = os.read(fd, 1).decode('latin-1')
|
|
245
245
|
if c2 == '[':
|
|
246
|
-
c3 =
|
|
246
|
+
c3 = os.read(fd, 1).decode('latin-1')
|
|
247
247
|
if c3 == 'A':
|
|
248
248
|
nav_up()
|
|
249
249
|
elif c3 == 'B':
|
|
@@ -331,7 +331,7 @@ steps:
|
|
|
331
331
|
sys.stdout.flush()
|
|
332
332
|
render()
|
|
333
333
|
while True:
|
|
334
|
-
c =
|
|
334
|
+
c = os.read(fd, 1).decode('latin-1')
|
|
335
335
|
if not handle(c):
|
|
336
336
|
break
|
|
337
337
|
render()
|