npcsh 1.1.19__py3-none-any.whl → 1.1.20__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 +11 -7
- npcsh/npc_team/jinxs/bin/config_tui.jinx +3 -2
- npcsh/npc_team/jinxs/bin/jinxs.jinx +407 -0
- npcsh/npc_team/jinxs/bin/kg.jinx +941 -0
- npcsh/npc_team/jinxs/bin/memories.jinx +3 -2
- npcsh/npc_team/jinxs/bin/models.jinx +343 -0
- npcsh/npc_team/jinxs/bin/nql.jinx +380 -50
- npcsh/npc_team/jinxs/bin/setup.jinx +2 -1
- npcsh/npc_team/jinxs/bin/team.jinx +504 -0
- npcsh/npc_team/jinxs/lib/core/search/db_search.jinx +1 -1
- npcsh/npc_team/jinxs/lib/core/search/file_search.jinx +1 -1
- npcsh/npc_team/jinxs/lib/core/search/kg_search.jinx +1 -1
- npcsh/npc_team/jinxs/lib/core/search/mem_search.jinx +1 -1
- npcsh/npc_team/jinxs/lib/core/search/web_search.jinx +1 -1
- npcsh/npc_team/jinxs/lib/research/paper_search.jinx +1 -1
- npcsh/npc_team/jinxs/lib/research/semantic_scholar.jinx +1 -1
- npcsh/npc_team/jinxs/modes/alicanto.jinx +1 -1
- npcsh/npc_team/jinxs/modes/arxiv.jinx +1 -1
- npcsh/npc_team/jinxs/modes/corca.jinx +1 -1
- npcsh/npc_team/jinxs/modes/guac.jinx +4 -4
- npcsh/npc_team/jinxs/modes/plonk.jinx +1 -1
- npcsh/npc_team/jinxs/modes/pti.jinx +1 -1
- npcsh/npc_team/jinxs/modes/reattach.jinx +1 -1
- npcsh/npc_team/jinxs/modes/spool.jinx +1 -1
- npcsh/npc_team/jinxs/modes/wander.jinx +1 -1
- npcsh/routes.py +8 -2
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/alicanto.jinx +1 -1
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/arxiv.jinx +1 -1
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/config_tui.jinx +3 -2
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/corca.jinx +1 -1
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/db_search.jinx +1 -1
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/file_search.jinx +1 -1
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/guac.jinx +4 -4
- npcsh-1.1.20.data/data/npcsh/npc_team/jinxs.jinx +407 -0
- npcsh-1.1.20.data/data/npcsh/npc_team/kg.jinx +941 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/kg_search.jinx +1 -1
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/mem_search.jinx +1 -1
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/memories.jinx +3 -2
- npcsh-1.1.20.data/data/npcsh/npc_team/models.jinx +343 -0
- npcsh-1.1.20.data/data/npcsh/npc_team/nql.jinx +471 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/paper_search.jinx +1 -1
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/plonk.jinx +1 -1
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/pti.jinx +1 -1
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/reattach.jinx +1 -1
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/semantic_scholar.jinx +1 -1
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/setup.jinx +2 -1
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/spool.jinx +1 -1
- npcsh-1.1.20.data/data/npcsh/npc_team/team.jinx +504 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/wander.jinx +1 -1
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/web_search.jinx +1 -1
- {npcsh-1.1.19.dist-info → npcsh-1.1.20.dist-info}/METADATA +1 -1
- {npcsh-1.1.19.dist-info → npcsh-1.1.20.dist-info}/RECORD +139 -135
- {npcsh-1.1.19.dist-info → npcsh-1.1.20.dist-info}/entry_points.txt +4 -1
- npcsh/npc_team/jinxs/bin/team_tui.jinx +0 -327
- npcsh/npc_team/jinxs/lib/utils/jinxs.jinx +0 -331
- npcsh-1.1.19.data/data/npcsh/npc_team/jinxs.jinx +0 -331
- npcsh-1.1.19.data/data/npcsh/npc_team/nql.jinx +0 -141
- npcsh-1.1.19.data/data/npcsh/npc_team/team_tui.jinx +0 -327
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/add_tab.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/alicanto.npc +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/alicanto.png +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/benchmark.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/browser_action.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/browser_screenshot.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/build.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/chat.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/click.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/close_browser.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/close_pane.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/close_tab.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/cmd.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/compile.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/compress.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/confirm.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/convene.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/corca.npc +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/corca.png +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/corca_example.png +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/delegate.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/edit_file.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/focus_pane.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/frederic.npc +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/frederic4.png +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/guac.npc +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/guac.png +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/help.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/incognide.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/init.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/kadiefa.npc +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/kadiefa.png +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/key_press.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/launch_app.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/list_panes.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/load_file.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/mem_review.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/navigate.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/notify.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/npcsh.ctx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/npcsh_sibiji.png +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/open_browser.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/open_pane.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/ots.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/paste.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/plonk.npc +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/plonk.png +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/plonkjr.npc +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/plonkjr.png +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/python.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/read_pane.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/roll.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/run_terminal.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/sample.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/screenshot.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/search.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/send_message.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/serve.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/set.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/sh.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/shh.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/sibiji.npc +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/sibiji.png +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/sleep.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/split_pane.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/spool.png +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/sql.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/switch.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/switch_npc.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/switch_tab.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/switches.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/sync.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/teamviz.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/trigger.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/type_text.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/usage.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/verbose.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/vixynt.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/wait.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/write_file.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/yap.jinx +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/yap.png +0 -0
- {npcsh-1.1.19.data → npcsh-1.1.20.data}/data/npcsh/npc_team/zen_mode.jinx +0 -0
- {npcsh-1.1.19.dist-info → npcsh-1.1.20.dist-info}/WHEEL +0 -0
- {npcsh-1.1.19.dist-info → npcsh-1.1.20.dist-info}/licenses/LICENSE +0 -0
- {npcsh-1.1.19.dist-info → npcsh-1.1.20.dist-info}/top_level.txt +0 -0
|
@@ -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."
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|