npcsh 1.1.19__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 +16 -78
- 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 +18 -7
- npcsh/npc_team/jinxs/lib/core/search/file_search.jinx +18 -7
- npcsh/npc_team/jinxs/lib/core/search/kg_search.jinx +20 -9
- npcsh/npc_team/jinxs/lib/core/search/web_search.jinx +53 -15
- npcsh/npc_team/jinxs/{bin → lib/utils}/benchmark.jinx +2 -2
- npcsh/npc_team/jinxs/lib/utils/jinxs.jinx +393 -317
- npcsh/npc_team/jinxs/lib/utils/models.jinx +343 -0
- npcsh/npc_team/jinxs/{bin → lib/utils}/setup.jinx +8 -7
- npcsh/npc_team/jinxs/modes/alicanto.jinx +1573 -296
- npcsh/npc_team/jinxs/modes/arxiv.jinx +6 -6
- npcsh/npc_team/jinxs/modes/config_tui.jinx +300 -0
- npcsh/npc_team/jinxs/modes/corca.jinx +4 -4
- npcsh/npc_team/jinxs/modes/git.jinx +795 -0
- npcsh/npc_team/jinxs/modes/guac.jinx +4 -4
- npcsh/npc_team/jinxs/modes/kg.jinx +941 -0
- npcsh/npc_team/jinxs/modes/memories.jinx +414 -0
- npcsh/npc_team/jinxs/modes/nql.jinx +460 -0
- npcsh/npc_team/jinxs/modes/papers.jinx +578 -0
- npcsh/npc_team/jinxs/modes/plonk.jinx +490 -304
- npcsh/npc_team/jinxs/modes/pti.jinx +1 -1
- npcsh/npc_team/jinxs/modes/reattach.jinx +4 -4
- npcsh/npc_team/jinxs/modes/spool.jinx +4 -4
- npcsh/npc_team/jinxs/modes/team.jinx +504 -0
- npcsh/npc_team/jinxs/modes/vixynt.jinx +388 -0
- npcsh/npc_team/jinxs/modes/wander.jinx +455 -182
- npcsh/npc_team/jinxs/modes/yap.jinx +10 -3
- npcsh/npcsh.py +112 -47
- npcsh/routes.py +12 -3
- npcsh/salmon_simulation.py +0 -0
- npcsh-1.1.21.data/data/npcsh/npc_team/alicanto.jinx +1633 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/arxiv.jinx +6 -6
- {npcsh-1.1.19.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.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/corca.jinx +4 -4
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/db_search.jinx +18 -7
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/file_search.jinx +18 -7
- npcsh-1.1.21.data/data/npcsh/npc_team/git.jinx +795 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/guac.jinx +4 -4
- npcsh-1.1.21.data/data/npcsh/npc_team/jinxs.jinx +407 -0
- npcsh-1.1.21.data/data/npcsh/npc_team/kg.jinx +941 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/kg_search.jinx +20 -9
- npcsh-1.1.21.data/data/npcsh/npc_team/memories.jinx +414 -0
- npcsh-1.1.21.data/data/npcsh/npc_team/models.jinx +343 -0
- npcsh-1.1.21.data/data/npcsh/npc_team/nql.jinx +460 -0
- 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.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/pti.jinx +1 -1
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/reattach.jinx +4 -4
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/setup.jinx +8 -7
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/spool.jinx +4 -4
- npcsh-1.1.21.data/data/npcsh/npc_team/team.jinx +504 -0
- 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.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/web_search.jinx +53 -15
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/yap.jinx +10 -3
- {npcsh-1.1.19.dist-info → npcsh-1.1.21.dist-info}/METADATA +2 -2
- {npcsh-1.1.19.dist-info → npcsh-1.1.21.dist-info}/RECORD +147 -148
- npcsh-1.1.21.dist-info/entry_points.txt +11 -0
- npcsh/npc_team/jinxs/bin/config_tui.jinx +0 -299
- npcsh/npc_team/jinxs/bin/memories.jinx +0 -316
- npcsh/npc_team/jinxs/bin/nql.jinx +0 -141
- npcsh/npc_team/jinxs/bin/team_tui.jinx +0 -327
- 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.19.data/data/npcsh/npc_team/alicanto.jinx +0 -356
- npcsh-1.1.19.data/data/npcsh/npc_team/compress.jinx +0 -140
- npcsh-1.1.19.data/data/npcsh/npc_team/config_tui.jinx +0 -299
- npcsh-1.1.19.data/data/npcsh/npc_team/jinxs.jinx +0 -331
- npcsh-1.1.19.data/data/npcsh/npc_team/mem_review.jinx +0 -73
- npcsh-1.1.19.data/data/npcsh/npc_team/mem_search.jinx +0 -388
- npcsh-1.1.19.data/data/npcsh/npc_team/memories.jinx +0 -316
- npcsh-1.1.19.data/data/npcsh/npc_team/nql.jinx +0 -141
- npcsh-1.1.19.data/data/npcsh/npc_team/paper_search.jinx +0 -412
- npcsh-1.1.19.data/data/npcsh/npc_team/plonk.jinx +0 -379
- npcsh-1.1.19.data/data/npcsh/npc_team/plonkjr.npc +0 -23
- npcsh-1.1.19.data/data/npcsh/npc_team/semantic_scholar.jinx +0 -386
- npcsh-1.1.19.data/data/npcsh/npc_team/team_tui.jinx +0 -327
- npcsh-1.1.19.data/data/npcsh/npc_team/vixynt.jinx +0 -122
- npcsh-1.1.19.data/data/npcsh/npc_team/wander.jinx +0 -455
- npcsh-1.1.19.dist-info/entry_points.txt +0 -22
- /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.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/add_tab.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/alicanto.npc +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/alicanto.png +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/browser_action.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/browser_screenshot.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/build.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/chat.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/click.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/close_browser.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/close_pane.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/close_tab.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/cmd.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/compile.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/confirm.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/convene.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/corca.npc +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/corca.png +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/corca_example.png +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/delegate.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/edit_file.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/focus_pane.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/frederic.npc +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/frederic4.png +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/guac.npc +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/guac.png +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/help.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/incognide.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/init.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/kadiefa.npc +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/kadiefa.png +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/key_press.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/launch_app.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/list_panes.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/load_file.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/navigate.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/notify.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/npcsh.ctx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/npcsh_sibiji.png +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/open_browser.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/open_pane.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/ots.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/paste.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/plonk.npc +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/plonk.png +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/plonkjr.png +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/python.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/read_pane.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/roll.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/run_terminal.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/sample.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/screenshot.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/search.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/send_message.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/serve.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/set.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/sh.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/shh.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/sibiji.npc +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/sibiji.png +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/sleep.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/split_pane.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/spool.png +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/sql.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/switch.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/switch_npc.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/switch_tab.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/switches.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/sync.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/teamviz.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/trigger.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/type_text.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/usage.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/verbose.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/wait.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/write_file.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/yap.png +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.21.data}/data/npcsh/npc_team/zen_mode.jinx +0 -0
- {npcsh-1.1.19.dist-info → npcsh-1.1.21.dist-info}/WHEEL +0 -0
- {npcsh-1.1.19.dist-info → npcsh-1.1.21.dist-info}/licenses/LICENSE +0 -0
- {npcsh-1.1.19.dist-info → npcsh-1.1.21.dist-info}/top_level.txt +0 -0
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
jinx_name: nql
|
|
2
|
-
description: "Run NPC-SQL models with AI-powered transformations. Supports cron scheduling."
|
|
3
|
-
inputs:
|
|
4
|
-
- models_dir: "~/.npcsh/npc_team/models"
|
|
5
|
-
- db: "~/npcsh_history.db"
|
|
6
|
-
- model: ""
|
|
7
|
-
- schema: ""
|
|
8
|
-
- show: ""
|
|
9
|
-
- cron: ""
|
|
10
|
-
- install_cron: ""
|
|
11
|
-
|
|
12
|
-
steps:
|
|
13
|
-
- name: run_nql
|
|
14
|
-
engine: python
|
|
15
|
-
code: |
|
|
16
|
-
import os
|
|
17
|
-
import sys
|
|
18
|
-
from pathlib import Path
|
|
19
|
-
|
|
20
|
-
models_dir = context.get('models_dir') or '~/.npcsh/npc_team/models'
|
|
21
|
-
db_path = context.get('db') or '~/npcsh_history.db'
|
|
22
|
-
model_name = context.get('model') or ''
|
|
23
|
-
schema = context.get('schema') or ''
|
|
24
|
-
list_models = context.get('show') or ''
|
|
25
|
-
cron_expr = context.get('cron') or ''
|
|
26
|
-
install_cron = context.get('install_cron') or ''
|
|
27
|
-
|
|
28
|
-
models_dir = os.path.expanduser(models_dir)
|
|
29
|
-
db_path = os.path.expanduser(db_path)
|
|
30
|
-
|
|
31
|
-
# Find NPC team directory
|
|
32
|
-
npc_dir = None
|
|
33
|
-
if os.path.exists('./npc_team'):
|
|
34
|
-
npc_dir = './npc_team'
|
|
35
|
-
elif os.path.exists(os.path.expanduser('~/.npcsh/npc_team')):
|
|
36
|
-
npc_dir = os.path.expanduser('~/.npcsh/npc_team')
|
|
37
|
-
|
|
38
|
-
# Import npcsql
|
|
39
|
-
try:
|
|
40
|
-
from npcpy.sql.npcsql import ModelCompiler, SQLModel
|
|
41
|
-
except ImportError:
|
|
42
|
-
output = "Error: npcpy.sql.npcsql not found. Install npcpy first."
|
|
43
|
-
raise SystemExit(1)
|
|
44
|
-
|
|
45
|
-
# List models mode
|
|
46
|
-
if list_models:
|
|
47
|
-
if not os.path.exists(models_dir):
|
|
48
|
-
output = "No models directory found at " + models_dir
|
|
49
|
-
else:
|
|
50
|
-
models_path = Path(models_dir)
|
|
51
|
-
sql_files = list(models_path.glob("**/*.sql"))
|
|
52
|
-
if not sql_files:
|
|
53
|
-
output = "No .sql models found in " + models_dir
|
|
54
|
-
else:
|
|
55
|
-
lines = ["Available NQL models in " + models_dir + ":", ""]
|
|
56
|
-
for f in sorted(sql_files):
|
|
57
|
-
rel = f.relative_to(models_path)
|
|
58
|
-
# Check for nql functions
|
|
59
|
-
with open(f, 'r') as fh:
|
|
60
|
-
content = fh.read()
|
|
61
|
-
has_nql = "nql." in content
|
|
62
|
-
marker = " [NQL]" if has_nql else ""
|
|
63
|
-
lines.append(" " + str(rel) + marker)
|
|
64
|
-
output = "\n".join(lines)
|
|
65
|
-
|
|
66
|
-
# Install cron mode
|
|
67
|
-
elif install_cron:
|
|
68
|
-
import subprocess
|
|
69
|
-
# Parse cron expression and model
|
|
70
|
-
parts = install_cron.split()
|
|
71
|
-
if len(parts) < 5:
|
|
72
|
-
output = "Error: cron expression must have 5 fields (min hour day month weekday)"
|
|
73
|
-
else:
|
|
74
|
-
cron_time = " ".join(parts[:5])
|
|
75
|
-
cron_model = parts[5] if len(parts) > 5 else ""
|
|
76
|
-
|
|
77
|
-
# Build command
|
|
78
|
-
nql_cmd = "npc nql"
|
|
79
|
-
if cron_model:
|
|
80
|
-
nql_cmd += " model=" + cron_model
|
|
81
|
-
nql_cmd += " models_dir=" + models_dir
|
|
82
|
-
nql_cmd += " db=" + db_path
|
|
83
|
-
if schema:
|
|
84
|
-
nql_cmd += " schema=" + schema
|
|
85
|
-
|
|
86
|
-
cron_line = cron_time + " " + nql_cmd
|
|
87
|
-
|
|
88
|
-
# Get current crontab
|
|
89
|
-
try:
|
|
90
|
-
result = subprocess.run(['crontab', '-l'], capture_output=True, text=True)
|
|
91
|
-
current = result.stdout if result.returncode == 0 else ""
|
|
92
|
-
except:
|
|
93
|
-
current = ""
|
|
94
|
-
|
|
95
|
-
# Check if already installed
|
|
96
|
-
if nql_cmd in current:
|
|
97
|
-
output = "Cron job already exists for: " + nql_cmd
|
|
98
|
-
else:
|
|
99
|
-
# Add new cron line
|
|
100
|
-
new_crontab = current.rstrip() + "\n" + cron_line + "\n"
|
|
101
|
-
proc = subprocess.run(['crontab', '-'], input=new_crontab, text=True, capture_output=True)
|
|
102
|
-
if proc.returncode == 0:
|
|
103
|
-
output = "Installed cron job:\n " + cron_line
|
|
104
|
-
else:
|
|
105
|
-
output = "Failed to install cron: " + proc.stderr
|
|
106
|
-
|
|
107
|
-
# Run models mode
|
|
108
|
-
else:
|
|
109
|
-
if not os.path.exists(models_dir):
|
|
110
|
-
output = "Models directory not found: " + models_dir + "\nCreate it with: mkdir -p " + models_dir
|
|
111
|
-
else:
|
|
112
|
-
try:
|
|
113
|
-
compiler = ModelCompiler(
|
|
114
|
-
models_dir=models_dir,
|
|
115
|
-
target_engine=db_path,
|
|
116
|
-
npc_directory=npc_dir,
|
|
117
|
-
target_schema=schema if schema else None
|
|
118
|
-
)
|
|
119
|
-
|
|
120
|
-
if model_name:
|
|
121
|
-
# Run specific model
|
|
122
|
-
compiler.discover_models()
|
|
123
|
-
if model_name not in compiler.models:
|
|
124
|
-
available = list(compiler.models.keys())
|
|
125
|
-
output = "Model '" + model_name + "' not found. Available: " + str(available)
|
|
126
|
-
else:
|
|
127
|
-
print("Running model: " + model_name)
|
|
128
|
-
df = compiler.execute_model(model_name)
|
|
129
|
-
output = "Model '" + model_name + "' completed. Rows: " + str(len(df))
|
|
130
|
-
else:
|
|
131
|
-
# Run all models in dependency order
|
|
132
|
-
results = compiler.run_all_models()
|
|
133
|
-
lines = ["NQL run complete:", ""]
|
|
134
|
-
for name, df in results.items():
|
|
135
|
-
lines.append(" " + name + ": " + str(len(df)) + " rows")
|
|
136
|
-
output = "\n".join(lines)
|
|
137
|
-
|
|
138
|
-
except Exception as e:
|
|
139
|
-
output = "NQL Error: " + str(e)
|
|
140
|
-
import traceback
|
|
141
|
-
traceback.print_exc()
|
|
@@ -1,327 +0,0 @@
|
|
|
1
|
-
jinx_name: team_tui
|
|
2
|
-
description: Interactive TUI for managing team context, NPCs, and jinxs
|
|
3
|
-
inputs: []
|
|
4
|
-
steps:
|
|
5
|
-
- name: team_manager
|
|
6
|
-
engine: python
|
|
7
|
-
code: |
|
|
8
|
-
import os
|
|
9
|
-
import sys
|
|
10
|
-
import tty
|
|
11
|
-
import termios
|
|
12
|
-
import select
|
|
13
|
-
import yaml
|
|
14
|
-
from pathlib import Path
|
|
15
|
-
|
|
16
|
-
if not sys.stdin.isatty():
|
|
17
|
-
context['output'] = "Team TUI requires an interactive terminal."
|
|
18
|
-
return
|
|
19
|
-
|
|
20
|
-
team = context.get('team')
|
|
21
|
-
if not team:
|
|
22
|
-
context['output'] = "No team loaded."
|
|
23
|
-
return
|
|
24
|
-
|
|
25
|
-
# ========== State ==========
|
|
26
|
-
class TeamState:
|
|
27
|
-
def __init__(self):
|
|
28
|
-
self.tab = 0 # 0=Team Context, 1=NPCs, 2=Jinxs
|
|
29
|
-
self.tabs = ['Team Context', 'NPCs', 'Jinxs']
|
|
30
|
-
self.selected_idx = 0
|
|
31
|
-
self.scroll_offset = 0
|
|
32
|
-
self.editing = False
|
|
33
|
-
self.edit_field = None
|
|
34
|
-
self.edit_buffer = ""
|
|
35
|
-
self.edit_cursor = 0
|
|
36
|
-
self.status = ""
|
|
37
|
-
self.team_ctx = {}
|
|
38
|
-
self.npcs = []
|
|
39
|
-
self.jinxs = []
|
|
40
|
-
|
|
41
|
-
state = TeamState()
|
|
42
|
-
|
|
43
|
-
# ========== Helpers ==========
|
|
44
|
-
def get_size():
|
|
45
|
-
try:
|
|
46
|
-
s = os.get_terminal_size()
|
|
47
|
-
return s.columns, s.lines
|
|
48
|
-
except:
|
|
49
|
-
return 80, 24
|
|
50
|
-
|
|
51
|
-
def load_team_data():
|
|
52
|
-
"""Load team context, NPCs, and jinxs."""
|
|
53
|
-
# Load team.ctx
|
|
54
|
-
if hasattr(team, 'team_ctx'):
|
|
55
|
-
state.team_ctx = team.team_ctx or {}
|
|
56
|
-
else:
|
|
57
|
-
ctx_path = Path(team.team_path) / 'team.ctx'
|
|
58
|
-
if ctx_path.exists():
|
|
59
|
-
with open(ctx_path) as f:
|
|
60
|
-
state.team_ctx = yaml.safe_load(f) or {}
|
|
61
|
-
|
|
62
|
-
# Load NPCs
|
|
63
|
-
if hasattr(team, 'npcs'):
|
|
64
|
-
state.npcs = list(team.npcs.keys())
|
|
65
|
-
else:
|
|
66
|
-
npc_dir = Path(team.team_path)
|
|
67
|
-
state.npcs = [f.stem for f in npc_dir.glob('*.npc')]
|
|
68
|
-
|
|
69
|
-
# Load Jinxs count by folder
|
|
70
|
-
jinxs_dir = Path(team.team_path) / 'jinxs'
|
|
71
|
-
state.jinxs = []
|
|
72
|
-
if jinxs_dir.exists():
|
|
73
|
-
for subdir in sorted(jinxs_dir.iterdir()):
|
|
74
|
-
if subdir.is_dir():
|
|
75
|
-
count = len(list(subdir.glob('*.jinx')))
|
|
76
|
-
state.jinxs.append((subdir.name, count))
|
|
77
|
-
|
|
78
|
-
def save_team_ctx():
|
|
79
|
-
"""Save team.ctx file."""
|
|
80
|
-
ctx_path = Path(team.team_path) / 'team.ctx'
|
|
81
|
-
with open(ctx_path, 'w') as f:
|
|
82
|
-
yaml.dump(state.team_ctx, f, default_flow_style=False)
|
|
83
|
-
state.status = "Team context saved!"
|
|
84
|
-
|
|
85
|
-
# ========== Rendering ==========
|
|
86
|
-
def render_screen():
|
|
87
|
-
width, height = get_size()
|
|
88
|
-
out = []
|
|
89
|
-
out.append("\033[2J\033[H")
|
|
90
|
-
|
|
91
|
-
# Header
|
|
92
|
-
team_name = getattr(team, 'name', 'Unknown')
|
|
93
|
-
header = f" Team: {team_name} "
|
|
94
|
-
out.append(f"\033[1;1H\033[44;37;1m{'=' * width}\033[0m")
|
|
95
|
-
out.append(f"\033[1;{(width - len(header)) // 2}H\033[44;37;1m{header}\033[0m")
|
|
96
|
-
|
|
97
|
-
# Tabs
|
|
98
|
-
tab_str = ""
|
|
99
|
-
for i, tab in enumerate(state.tabs):
|
|
100
|
-
if i == state.tab:
|
|
101
|
-
tab_str += f"\033[47;30m [{tab}] \033[0m"
|
|
102
|
-
else:
|
|
103
|
-
tab_str += f" [{tab}] "
|
|
104
|
-
out.append(f"\033[2;2H{tab_str}")
|
|
105
|
-
|
|
106
|
-
# Content area
|
|
107
|
-
out.append(f"\033[3;1H\033[90m{'─' * width}\033[0m")
|
|
108
|
-
|
|
109
|
-
if state.tab == 0:
|
|
110
|
-
render_team_ctx(out, width, height)
|
|
111
|
-
elif state.tab == 1:
|
|
112
|
-
render_npcs(out, width, height)
|
|
113
|
-
elif state.tab == 2:
|
|
114
|
-
render_jinxs(out, width, height)
|
|
115
|
-
|
|
116
|
-
# Status
|
|
117
|
-
if state.status:
|
|
118
|
-
out.append(f"\033[{height-2};2H\033[33m{state.status}\033[0m")
|
|
119
|
-
|
|
120
|
-
# Footer
|
|
121
|
-
if state.editing:
|
|
122
|
-
footer = "[Enter] Save [Esc] Cancel"
|
|
123
|
-
else:
|
|
124
|
-
footer = "[Tab] Switch Tab [j/k] Navigate [e] Edit [s] Save [q] Quit"
|
|
125
|
-
out.append(f"\033[{height};1H\033[90m{footer[:width]}\033[0m")
|
|
126
|
-
|
|
127
|
-
sys.stdout.write(''.join(out))
|
|
128
|
-
sys.stdout.flush()
|
|
129
|
-
|
|
130
|
-
def render_team_ctx(out, width, height):
|
|
131
|
-
"""Render team context tab."""
|
|
132
|
-
fields = [
|
|
133
|
-
('forenpc', 'Forenpc'),
|
|
134
|
-
('model', 'Model'),
|
|
135
|
-
('provider', 'Provider'),
|
|
136
|
-
('context', 'Context'),
|
|
137
|
-
]
|
|
138
|
-
|
|
139
|
-
row = 5
|
|
140
|
-
for i, (key, label) in enumerate(fields):
|
|
141
|
-
value = state.team_ctx.get(key, '')
|
|
142
|
-
if isinstance(value, str) and len(value) > 50:
|
|
143
|
-
value = value[:50] + '...'
|
|
144
|
-
|
|
145
|
-
if i == state.selected_idx:
|
|
146
|
-
if state.editing:
|
|
147
|
-
out.append(f"\033[{row};4H\033[1m{label}:\033[0m")
|
|
148
|
-
out.append(f"\033[{row+1};6H{state.edit_buffer[:width-10]}\033[7m \033[0m")
|
|
149
|
-
row += 2
|
|
150
|
-
else:
|
|
151
|
-
out.append(f"\033[{row};4H\033[47;30m{label}: {value}\033[0m")
|
|
152
|
-
row += 1
|
|
153
|
-
else:
|
|
154
|
-
if value:
|
|
155
|
-
out.append(f"\033[{row};4H{label}: \033[32m{value}\033[0m")
|
|
156
|
-
else:
|
|
157
|
-
out.append(f"\033[{row};4H{label}: \033[90m(not set)\033[0m")
|
|
158
|
-
row += 1
|
|
159
|
-
|
|
160
|
-
def render_npcs(out, width, height):
|
|
161
|
-
"""Render NPCs tab."""
|
|
162
|
-
visible_height = height - 8
|
|
163
|
-
visible = state.npcs[state.scroll_offset:state.scroll_offset + visible_height]
|
|
164
|
-
|
|
165
|
-
row = 5
|
|
166
|
-
for i, npc_name in enumerate(visible):
|
|
167
|
-
idx = i + state.scroll_offset
|
|
168
|
-
npc_obj = team.npcs.get(npc_name) if hasattr(team, 'npcs') else None
|
|
169
|
-
|
|
170
|
-
if npc_obj:
|
|
171
|
-
model_info = f"{npc_obj.model or 'default'}/{npc_obj.provider or 'default'}"
|
|
172
|
-
else:
|
|
173
|
-
model_info = ""
|
|
174
|
-
|
|
175
|
-
if idx == state.selected_idx:
|
|
176
|
-
out.append(f"\033[{row};4H\033[47;30m> {npc_name:<15} {model_info}\033[0m")
|
|
177
|
-
else:
|
|
178
|
-
out.append(f"\033[{row};4H {npc_name:<15} \033[90m{model_info}\033[0m")
|
|
179
|
-
row += 1
|
|
180
|
-
|
|
181
|
-
if not state.npcs:
|
|
182
|
-
out.append(f"\033[5;4H\033[90mNo NPCs found in team.\033[0m")
|
|
183
|
-
|
|
184
|
-
def render_jinxs(out, width, height):
|
|
185
|
-
"""Render Jinxs tab."""
|
|
186
|
-
visible_height = height - 8
|
|
187
|
-
visible = state.jinxs[state.scroll_offset:state.scroll_offset + visible_height]
|
|
188
|
-
|
|
189
|
-
row = 5
|
|
190
|
-
for i, (folder, count) in enumerate(visible):
|
|
191
|
-
idx = i + state.scroll_offset
|
|
192
|
-
if idx == state.selected_idx:
|
|
193
|
-
out.append(f"\033[{row};4H\033[47;30m> {folder}/ ({count} jinxs)\033[0m")
|
|
194
|
-
else:
|
|
195
|
-
out.append(f"\033[{row};4H {folder}/ \033[90m({count} jinxs)\033[0m")
|
|
196
|
-
row += 1
|
|
197
|
-
|
|
198
|
-
if not state.jinxs:
|
|
199
|
-
out.append(f"\033[5;4H\033[90mNo jinxs folders found.\033[0m")
|
|
200
|
-
|
|
201
|
-
# ========== Input Handling ==========
|
|
202
|
-
def handle_input(c):
|
|
203
|
-
if state.editing:
|
|
204
|
-
return handle_edit_input(c)
|
|
205
|
-
|
|
206
|
-
if c == 'q':
|
|
207
|
-
return False
|
|
208
|
-
|
|
209
|
-
if c == '\t': # Tab - switch tabs
|
|
210
|
-
state.tab = (state.tab + 1) % len(state.tabs)
|
|
211
|
-
state.selected_idx = 0
|
|
212
|
-
state.scroll_offset = 0
|
|
213
|
-
state.status = ""
|
|
214
|
-
|
|
215
|
-
elif c == '\x1b': # Escape sequence
|
|
216
|
-
if select.select([sys.stdin], [], [], 0.05)[0]:
|
|
217
|
-
c2 = sys.stdin.read(1)
|
|
218
|
-
if c2 == '[':
|
|
219
|
-
c3 = sys.stdin.read(1)
|
|
220
|
-
if c3 == 'A': # Up
|
|
221
|
-
move_up()
|
|
222
|
-
elif c3 == 'B': # Down
|
|
223
|
-
move_down()
|
|
224
|
-
|
|
225
|
-
elif c == 'k':
|
|
226
|
-
move_up()
|
|
227
|
-
elif c == 'j':
|
|
228
|
-
move_down()
|
|
229
|
-
elif c == 'e' or c == '\r' or c == '\n':
|
|
230
|
-
start_edit()
|
|
231
|
-
elif c == 's':
|
|
232
|
-
save_team_ctx()
|
|
233
|
-
|
|
234
|
-
return True
|
|
235
|
-
|
|
236
|
-
def handle_edit_input(c):
|
|
237
|
-
if c == '\x1b': # Escape - cancel
|
|
238
|
-
state.editing = False
|
|
239
|
-
state.edit_buffer = ""
|
|
240
|
-
state.status = "Edit cancelled"
|
|
241
|
-
return True
|
|
242
|
-
|
|
243
|
-
if c == '\r' or c == '\n': # Enter - save
|
|
244
|
-
if state.edit_field:
|
|
245
|
-
state.team_ctx[state.edit_field] = state.edit_buffer
|
|
246
|
-
state.status = f"Updated {state.edit_field}"
|
|
247
|
-
state.editing = False
|
|
248
|
-
state.edit_buffer = ""
|
|
249
|
-
state.edit_field = None
|
|
250
|
-
return True
|
|
251
|
-
|
|
252
|
-
if c == '\x7f' or c == '\x08': # Backspace
|
|
253
|
-
if state.edit_cursor > 0:
|
|
254
|
-
state.edit_buffer = state.edit_buffer[:state.edit_cursor-1] + state.edit_buffer[state.edit_cursor:]
|
|
255
|
-
state.edit_cursor -= 1
|
|
256
|
-
|
|
257
|
-
elif c >= ' ' and c <= '~': # Printable
|
|
258
|
-
state.edit_buffer = state.edit_buffer[:state.edit_cursor] + c + state.edit_buffer[state.edit_cursor:]
|
|
259
|
-
state.edit_cursor += 1
|
|
260
|
-
|
|
261
|
-
return True
|
|
262
|
-
|
|
263
|
-
def move_up():
|
|
264
|
-
state.selected_idx = max(0, state.selected_idx - 1)
|
|
265
|
-
if state.selected_idx < state.scroll_offset:
|
|
266
|
-
state.scroll_offset = state.selected_idx
|
|
267
|
-
state.status = ""
|
|
268
|
-
|
|
269
|
-
def move_down():
|
|
270
|
-
_, height = get_size()
|
|
271
|
-
visible_height = height - 8
|
|
272
|
-
|
|
273
|
-
if state.tab == 0:
|
|
274
|
-
max_idx = 3 # 4 fields in team ctx
|
|
275
|
-
elif state.tab == 1:
|
|
276
|
-
max_idx = len(state.npcs) - 1
|
|
277
|
-
else:
|
|
278
|
-
max_idx = len(state.jinxs) - 1
|
|
279
|
-
|
|
280
|
-
state.selected_idx = min(max_idx, state.selected_idx + 1)
|
|
281
|
-
if state.selected_idx >= state.scroll_offset + visible_height:
|
|
282
|
-
state.scroll_offset = state.selected_idx - visible_height + 1
|
|
283
|
-
state.status = ""
|
|
284
|
-
|
|
285
|
-
def start_edit():
|
|
286
|
-
if state.tab == 0:
|
|
287
|
-
fields = ['forenpc', 'model', 'provider', 'context']
|
|
288
|
-
if state.selected_idx < len(fields):
|
|
289
|
-
state.edit_field = fields[state.selected_idx]
|
|
290
|
-
state.edit_buffer = str(state.team_ctx.get(state.edit_field, ''))
|
|
291
|
-
state.edit_cursor = len(state.edit_buffer)
|
|
292
|
-
state.editing = True
|
|
293
|
-
state.status = "Editing..."
|
|
294
|
-
elif state.tab == 1:
|
|
295
|
-
if state.npcs and state.selected_idx < len(state.npcs):
|
|
296
|
-
npc_name = state.npcs[state.selected_idx]
|
|
297
|
-
state.status = f"Selected NPC: {npc_name} (edit NPC files directly)"
|
|
298
|
-
elif state.tab == 2:
|
|
299
|
-
if state.jinxs and state.selected_idx < len(state.jinxs):
|
|
300
|
-
folder, _ = state.jinxs[state.selected_idx]
|
|
301
|
-
state.status = f"Selected folder: {folder}/"
|
|
302
|
-
|
|
303
|
-
# ========== Main Loop ==========
|
|
304
|
-
load_team_data()
|
|
305
|
-
|
|
306
|
-
fd = sys.stdin.fileno()
|
|
307
|
-
old_settings = termios.tcgetattr(fd)
|
|
308
|
-
|
|
309
|
-
try:
|
|
310
|
-
tty.setcbreak(fd)
|
|
311
|
-
sys.stdout.write('\033[?25l') # Hide cursor
|
|
312
|
-
|
|
313
|
-
render_screen()
|
|
314
|
-
|
|
315
|
-
while True:
|
|
316
|
-
c = sys.stdin.read(1)
|
|
317
|
-
if not handle_input(c):
|
|
318
|
-
break
|
|
319
|
-
render_screen()
|
|
320
|
-
|
|
321
|
-
finally:
|
|
322
|
-
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
|
|
323
|
-
sys.stdout.write('\033[?25h') # Show cursor
|
|
324
|
-
sys.stdout.write('\033[2J\033[H') # Clear screen
|
|
325
|
-
sys.stdout.flush()
|
|
326
|
-
|
|
327
|
-
context['output'] = "Team manager closed."
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
jinx_name: "vixynt"
|
|
2
|
-
description: "Generates images from text descriptions or edits existing ones."
|
|
3
|
-
inputs:
|
|
4
|
-
- prompt
|
|
5
|
-
- model: null
|
|
6
|
-
- provider: null
|
|
7
|
-
- output_name: null
|
|
8
|
-
- attachments: null
|
|
9
|
-
- n_images: null
|
|
10
|
-
- height: null
|
|
11
|
-
- width: null
|
|
12
|
-
steps:
|
|
13
|
-
- name: "generate_or_edit_image"
|
|
14
|
-
engine: "python"
|
|
15
|
-
code: |
|
|
16
|
-
import os
|
|
17
|
-
import base64
|
|
18
|
-
from io import BytesIO
|
|
19
|
-
from datetime import datetime
|
|
20
|
-
from PIL import Image
|
|
21
|
-
from npcpy.llm_funcs import gen_image
|
|
22
|
-
|
|
23
|
-
# Extract inputs from context with proper type conversion
|
|
24
|
-
image_prompt = str(context.get('prompt', '')).strip()
|
|
25
|
-
output_name = context.get('output_name')
|
|
26
|
-
attachments_str = context.get('attachments')
|
|
27
|
-
|
|
28
|
-
# Handle integer inputs - they may come as strings or ints
|
|
29
|
-
try:
|
|
30
|
-
n_images = int(context.get('n_images', 1))
|
|
31
|
-
except (ValueError, TypeError):
|
|
32
|
-
n_images = 1
|
|
33
|
-
|
|
34
|
-
try:
|
|
35
|
-
height = int(context.get('height', 1024))
|
|
36
|
-
except (ValueError, TypeError):
|
|
37
|
-
height = 1024
|
|
38
|
-
|
|
39
|
-
try:
|
|
40
|
-
width = int(context.get('width', 1024))
|
|
41
|
-
except (ValueError, TypeError):
|
|
42
|
-
width = 1024
|
|
43
|
-
|
|
44
|
-
# Get model and provider from context or environment
|
|
45
|
-
model = context.get('model')
|
|
46
|
-
provider = context.get('provider')
|
|
47
|
-
|
|
48
|
-
# Fallback to environment variables
|
|
49
|
-
if not model:
|
|
50
|
-
model = os.getenv('NPCSH_IMAGE_GEN_MODEL')
|
|
51
|
-
if not provider:
|
|
52
|
-
provider = os.getenv('NPCSH_IMAGE_GEN_PROVIDER')
|
|
53
|
-
|
|
54
|
-
# Parse attachments
|
|
55
|
-
input_images = []
|
|
56
|
-
if attachments_str and str(attachments_str).strip():
|
|
57
|
-
input_images = [p.strip() for p in str(attachments_str).split(',')]
|
|
58
|
-
|
|
59
|
-
output_messages = context.get('messages', [])
|
|
60
|
-
|
|
61
|
-
if not image_prompt:
|
|
62
|
-
output = "Error: No prompt provided for image generation."
|
|
63
|
-
else:
|
|
64
|
-
try:
|
|
65
|
-
# Generate image(s)
|
|
66
|
-
result = gen_image(
|
|
67
|
-
prompt=image_prompt,
|
|
68
|
-
model=model,
|
|
69
|
-
provider=provider,
|
|
70
|
-
npc=npc,
|
|
71
|
-
height=height,
|
|
72
|
-
width=width,
|
|
73
|
-
n_images=n_images,
|
|
74
|
-
input_images=input_images if input_images else None
|
|
75
|
-
)
|
|
76
|
-
|
|
77
|
-
# Ensure we have a list of images
|
|
78
|
-
if not isinstance(result, list):
|
|
79
|
-
images_list = [result] if result is not None else []
|
|
80
|
-
else:
|
|
81
|
-
images_list = result
|
|
82
|
-
|
|
83
|
-
saved_files = []
|
|
84
|
-
|
|
85
|
-
for i, image in enumerate(images_list):
|
|
86
|
-
if image is None:
|
|
87
|
-
continue
|
|
88
|
-
|
|
89
|
-
# Determine output filename
|
|
90
|
-
if output_name and str(output_name).strip():
|
|
91
|
-
base_name, ext = os.path.splitext(os.path.expanduser(str(output_name)))
|
|
92
|
-
if not ext:
|
|
93
|
-
ext = ".png"
|
|
94
|
-
current_output_file = f"{base_name}_{i}{ext}" if len(images_list) > 1 else f"{base_name}{ext}"
|
|
95
|
-
else:
|
|
96
|
-
os.makedirs(os.path.expanduser("~/.npcsh/images/"), exist_ok=True)
|
|
97
|
-
current_output_file = (
|
|
98
|
-
os.path.expanduser("~/.npcsh/images/")
|
|
99
|
-
+ f"image_{datetime.now().strftime('%Y%m%d_%H%M%S')}_{i}.png"
|
|
100
|
-
)
|
|
101
|
-
|
|
102
|
-
# Save image to file
|
|
103
|
-
image.save(current_output_file)
|
|
104
|
-
saved_files.append(current_output_file)
|
|
105
|
-
|
|
106
|
-
if saved_files:
|
|
107
|
-
output = f"Image(s) generated: {', '.join(saved_files)}"
|
|
108
|
-
if input_images:
|
|
109
|
-
output = f"Image(s) edited: {', '.join(saved_files)}"
|
|
110
|
-
context['generated_images'] = saved_files
|
|
111
|
-
else:
|
|
112
|
-
output = "No images were generated."
|
|
113
|
-
|
|
114
|
-
except Exception as e:
|
|
115
|
-
import traceback
|
|
116
|
-
traceback.print_exc()
|
|
117
|
-
output = f"Error {'editing' if input_images else 'generating'} image: {str(e)}"
|
|
118
|
-
|
|
119
|
-
context['output'] = output
|
|
120
|
-
context['messages'] = output_messages
|
|
121
|
-
context['model'] = model
|
|
122
|
-
context['provider'] = provider
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
jinx_name: mem_review
|
|
2
|
-
description: Review pending memories with interactive UI
|
|
3
|
-
inputs:
|
|
4
|
-
- limit: "20"
|
|
5
|
-
- npc_filter: ""
|
|
6
|
-
- team_filter: ""
|
|
7
|
-
- db_path: ""
|
|
8
|
-
|
|
9
|
-
steps:
|
|
10
|
-
- name: review_memories
|
|
11
|
-
engine: python
|
|
12
|
-
code: |
|
|
13
|
-
import os
|
|
14
|
-
from npcpy.memory.command_history import CommandHistory
|
|
15
|
-
from npcpy.memory.memory_processor import memory_batch_review_ui
|
|
16
|
-
|
|
17
|
-
limit = int(context.get('limit') or 20)
|
|
18
|
-
npc_filter = context.get('npc_filter') or None
|
|
19
|
-
team_filter = context.get('team_filter') or None
|
|
20
|
-
db_path = context.get('db_path') or os.path.expanduser("~/npcsh_history.db")
|
|
21
|
-
|
|
22
|
-
# Get current npc/team from context if not specified
|
|
23
|
-
if not npc_filter:
|
|
24
|
-
try:
|
|
25
|
-
npc_filter = npc.name if 'npc' in dir() and npc else None
|
|
26
|
-
except:
|
|
27
|
-
pass
|
|
28
|
-
|
|
29
|
-
if not team_filter:
|
|
30
|
-
try:
|
|
31
|
-
team_filter = state.team.name if 'state' in dir() and state and state.team else None
|
|
32
|
-
except:
|
|
33
|
-
pass
|
|
34
|
-
|
|
35
|
-
try:
|
|
36
|
-
cmd_history = CommandHistory(db_path)
|
|
37
|
-
|
|
38
|
-
# Show what we're about to review
|
|
39
|
-
pending = cmd_history.get_pending_memories(limit=limit)
|
|
40
|
-
if npc_filter:
|
|
41
|
-
pending = [m for m in pending if m.get('npc') == npc_filter]
|
|
42
|
-
if team_filter:
|
|
43
|
-
pending = [m for m in pending if m.get('team') == team_filter]
|
|
44
|
-
|
|
45
|
-
if not pending:
|
|
46
|
-
context['output'] = "No pending memories to review."
|
|
47
|
-
else:
|
|
48
|
-
print(f"\nFound {len(pending)} pending memories")
|
|
49
|
-
if npc_filter:
|
|
50
|
-
print(f" NPC filter: {npc_filter}")
|
|
51
|
-
if team_filter:
|
|
52
|
-
print(f" Team filter: {team_filter}")
|
|
53
|
-
|
|
54
|
-
# Run interactive review
|
|
55
|
-
stats = memory_batch_review_ui(
|
|
56
|
-
cmd_history,
|
|
57
|
-
npc_filter=npc_filter,
|
|
58
|
-
team_filter=team_filter,
|
|
59
|
-
limit=limit
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
-
lines = [
|
|
63
|
-
"Review complete:",
|
|
64
|
-
f" Approved: {stats.get('approved', 0)}",
|
|
65
|
-
f" Rejected: {stats.get('rejected', 0)}",
|
|
66
|
-
f" Edited: {stats.get('edited', 0)}",
|
|
67
|
-
f" Skipped: {stats.get('skipped', 0)}",
|
|
68
|
-
]
|
|
69
|
-
context['output'] = "\n".join(lines)
|
|
70
|
-
|
|
71
|
-
except Exception as e:
|
|
72
|
-
import traceback
|
|
73
|
-
context['output'] = "Memory review error: " + str(e) + "\n" + traceback.format_exc()
|