npcsh 1.1.22__py3-none-any.whl → 1.1.23__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 +272 -120
- npcsh/benchmark/npcsh_agent.py +77 -240
- npcsh/benchmark/templates/install-npcsh.sh.j2 +12 -4
- npcsh/config.py +5 -2
- npcsh/npc_team/alicanto.npc +4 -8
- npcsh/npc_team/corca.npc +5 -11
- npcsh/npc_team/frederic.npc +4 -6
- npcsh/npc_team/guac.npc +4 -4
- npcsh/npc_team/jinxs/lib/core/delegate.jinx +1 -1
- npcsh/npc_team/jinxs/lib/core/edit_file.jinx +1 -1
- npcsh/npc_team/jinxs/lib/core/sh.jinx +1 -1
- npcsh/npc_team/jinxs/lib/core/skill.jinx +59 -0
- npcsh/npc_team/jinxs/lib/utils/help.jinx +194 -10
- npcsh/npc_team/jinxs/lib/utils/init.jinx +528 -37
- npcsh/npc_team/jinxs/lib/utils/jinxs.jinx +0 -1
- npcsh/npc_team/jinxs/lib/utils/serve.jinx +938 -21
- npcsh-1.1.22.data/data/npcsh/npc_team/config_tui.jinx → npcsh/npc_team/jinxs/modes/config.jinx +1 -1
- npcsh/npc_team/jinxs/modes/convene.jinx +76 -3
- npcsh/npc_team/jinxs/modes/crond.jinx +818 -0
- npcsh/npc_team/jinxs/modes/plonk.jinx +76 -14
- npcsh/npc_team/jinxs/modes/roll.jinx +368 -55
- npcsh/npc_team/jinxs/modes/skills.jinx +621 -0
- npcsh/npc_team/jinxs/modes/yap.jinx +504 -30
- npcsh/npc_team/jinxs/skills/code-review/SKILL.md +45 -0
- npcsh/npc_team/jinxs/skills/debugging/SKILL.md +44 -0
- npcsh/npc_team/jinxs/skills/git-workflow.jinx +44 -0
- npcsh/npc_team/kadiefa.npc +4 -5
- npcsh/npc_team/npcsh.ctx +16 -0
- npcsh/npc_team/plonk.npc +5 -9
- npcsh/npc_team/sibiji.npc +13 -5
- npcsh/npcsh.py +1 -0
- npcsh/routes.py +0 -4
- npcsh/yap.py +22 -4
- npcsh-1.1.23.data/data/npcsh/npc_team/SKILL.md +44 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/alicanto.npc +4 -8
- npcsh/npc_team/jinxs/modes/config_tui.jinx → npcsh-1.1.23.data/data/npcsh/npc_team/config.jinx +1 -1
- npcsh-1.1.23.data/data/npcsh/npc_team/convene.jinx +670 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/corca.npc +5 -11
- npcsh-1.1.23.data/data/npcsh/npc_team/crond.jinx +818 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/delegate.jinx +1 -1
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/edit_file.jinx +1 -1
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/frederic.npc +4 -6
- npcsh-1.1.23.data/data/npcsh/npc_team/git-workflow.jinx +44 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/guac.npc +4 -4
- npcsh-1.1.23.data/data/npcsh/npc_team/help.jinx +236 -0
- npcsh-1.1.23.data/data/npcsh/npc_team/init.jinx +532 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/jinxs.jinx +0 -1
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/kadiefa.npc +4 -5
- npcsh-1.1.23.data/data/npcsh/npc_team/npcsh.ctx +34 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/plonk.jinx +76 -14
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/plonk.npc +5 -9
- npcsh-1.1.23.data/data/npcsh/npc_team/roll.jinx +378 -0
- npcsh-1.1.23.data/data/npcsh/npc_team/serve.jinx +943 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/sh.jinx +1 -1
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/sibiji.npc +13 -5
- npcsh-1.1.23.data/data/npcsh/npc_team/skill.jinx +59 -0
- npcsh-1.1.23.data/data/npcsh/npc_team/skills.jinx +621 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/yap.jinx +504 -30
- {npcsh-1.1.22.dist-info → npcsh-1.1.23.dist-info}/METADATA +168 -7
- npcsh-1.1.23.dist-info/RECORD +216 -0
- npcsh/npc_team/jinxs/incognide/add_tab.jinx +0 -11
- npcsh/npc_team/jinxs/incognide/close_pane.jinx +0 -9
- npcsh/npc_team/jinxs/incognide/close_tab.jinx +0 -10
- npcsh/npc_team/jinxs/incognide/confirm.jinx +0 -10
- npcsh/npc_team/jinxs/incognide/focus_pane.jinx +0 -9
- npcsh/npc_team/jinxs/incognide/list_panes.jinx +0 -8
- npcsh/npc_team/jinxs/incognide/navigate.jinx +0 -10
- npcsh/npc_team/jinxs/incognide/notify.jinx +0 -10
- npcsh/npc_team/jinxs/incognide/open_pane.jinx +0 -13
- npcsh/npc_team/jinxs/incognide/read_pane.jinx +0 -9
- npcsh/npc_team/jinxs/incognide/run_terminal.jinx +0 -10
- npcsh/npc_team/jinxs/incognide/send_message.jinx +0 -10
- npcsh/npc_team/jinxs/incognide/split_pane.jinx +0 -12
- npcsh/npc_team/jinxs/incognide/switch_npc.jinx +0 -10
- npcsh/npc_team/jinxs/incognide/switch_tab.jinx +0 -10
- npcsh/npc_team/jinxs/incognide/write_file.jinx +0 -11
- npcsh/npc_team/jinxs/incognide/zen_mode.jinx +0 -9
- npcsh/npc_team/jinxs/lib/core/convene.jinx +0 -232
- npcsh-1.1.22.data/data/npcsh/npc_team/add_tab.jinx +0 -11
- npcsh-1.1.22.data/data/npcsh/npc_team/close_pane.jinx +0 -9
- npcsh-1.1.22.data/data/npcsh/npc_team/close_tab.jinx +0 -10
- npcsh-1.1.22.data/data/npcsh/npc_team/confirm.jinx +0 -10
- npcsh-1.1.22.data/data/npcsh/npc_team/convene.jinx +0 -232
- npcsh-1.1.22.data/data/npcsh/npc_team/focus_pane.jinx +0 -9
- npcsh-1.1.22.data/data/npcsh/npc_team/help.jinx +0 -52
- npcsh-1.1.22.data/data/npcsh/npc_team/init.jinx +0 -41
- npcsh-1.1.22.data/data/npcsh/npc_team/list_panes.jinx +0 -8
- npcsh-1.1.22.data/data/npcsh/npc_team/navigate.jinx +0 -10
- npcsh-1.1.22.data/data/npcsh/npc_team/notify.jinx +0 -10
- npcsh-1.1.22.data/data/npcsh/npc_team/npcsh.ctx +0 -18
- npcsh-1.1.22.data/data/npcsh/npc_team/open_pane.jinx +0 -13
- npcsh-1.1.22.data/data/npcsh/npc_team/read_pane.jinx +0 -9
- npcsh-1.1.22.data/data/npcsh/npc_team/roll.jinx +0 -65
- npcsh-1.1.22.data/data/npcsh/npc_team/run_terminal.jinx +0 -10
- npcsh-1.1.22.data/data/npcsh/npc_team/send_message.jinx +0 -10
- npcsh-1.1.22.data/data/npcsh/npc_team/serve.jinx +0 -26
- npcsh-1.1.22.data/data/npcsh/npc_team/split_pane.jinx +0 -12
- npcsh-1.1.22.data/data/npcsh/npc_team/switch_npc.jinx +0 -10
- npcsh-1.1.22.data/data/npcsh/npc_team/switch_tab.jinx +0 -10
- npcsh-1.1.22.data/data/npcsh/npc_team/write_file.jinx +0 -11
- npcsh-1.1.22.data/data/npcsh/npc_team/zen_mode.jinx +0 -9
- npcsh-1.1.22.dist-info/RECORD +0 -240
- /npcsh/npc_team/jinxs/{incognide → lib/utils}/incognide.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/alicanto.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/alicanto.png +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/arxiv.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/benchmark.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/browser_action.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/browser_screenshot.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/build.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/chat.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/click.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/close_browser.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/cmd.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/compile.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/compress.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/corca.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/corca.png +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/corca_example.png +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/db_search.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/file_search.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/frederic4.png +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/git.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/guac.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/guac.png +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/incognide.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/kadiefa.png +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/key_press.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/kg.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/launch_app.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/load_file.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/memories.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/models.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/npcsh_sibiji.png +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/nql.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/open_browser.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/ots.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/papers.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/paste.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/plonk.png +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/plonkjr.png +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/pti.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/python.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/reattach.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/sample.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/screenshot.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/set.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/setup.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/shh.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/sibiji.png +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/sleep.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/spool.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/spool.png +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/sql.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/switch.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/switches.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/sync.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/team.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/teamviz.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/trigger.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/type_text.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/usage.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/verbose.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/vixynt.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/wait.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/wander.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/web_search.jinx +0 -0
- {npcsh-1.1.22.data → npcsh-1.1.23.data}/data/npcsh/npc_team/yap.png +0 -0
- {npcsh-1.1.22.dist-info → npcsh-1.1.23.dist-info}/WHEEL +0 -0
- {npcsh-1.1.22.dist-info → npcsh-1.1.23.dist-info}/entry_points.txt +0 -0
- {npcsh-1.1.22.dist-info → npcsh-1.1.23.dist-info}/licenses/LICENSE +0 -0
- {npcsh-1.1.22.dist-info → npcsh-1.1.23.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,532 @@
|
|
|
1
|
+
jinx_name: init
|
|
2
|
+
description: Interactive TUI for initializing NPC projects with model detection and configuration
|
|
3
|
+
inputs:
|
|
4
|
+
- directory: ""
|
|
5
|
+
- templates: ""
|
|
6
|
+
- team_ctx: ""
|
|
7
|
+
- model: ""
|
|
8
|
+
- provider: ""
|
|
9
|
+
steps:
|
|
10
|
+
- name: init_wizard
|
|
11
|
+
engine: python
|
|
12
|
+
code: |
|
|
13
|
+
import os
|
|
14
|
+
import sys
|
|
15
|
+
import tty
|
|
16
|
+
import termios
|
|
17
|
+
import select
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
|
|
20
|
+
# Direct mode: if directory passed explicitly or non-interactive
|
|
21
|
+
_direct_dir = (context.get('directory') or '').strip()
|
|
22
|
+
_direct = bool(_direct_dir) or not sys.stdin.isatty()
|
|
23
|
+
|
|
24
|
+
if _direct:
|
|
25
|
+
from npcpy.npc_compiler import initialize_npc_project
|
|
26
|
+
try:
|
|
27
|
+
initialize_npc_project(
|
|
28
|
+
directory=_direct_dir or '.',
|
|
29
|
+
templates=context.get('templates'),
|
|
30
|
+
context=context.get('team_ctx'),
|
|
31
|
+
model=context.get('model'),
|
|
32
|
+
provider=context.get('provider')
|
|
33
|
+
)
|
|
34
|
+
context['output'] = f"NPC project initialized in {os.path.abspath(_direct_dir or '.')}"
|
|
35
|
+
except Exception as e:
|
|
36
|
+
context['output'] = f"Error: {e}"
|
|
37
|
+
context['messages'] = context.get('messages', [])
|
|
38
|
+
|
|
39
|
+
else:
|
|
40
|
+
# ========== Detection Functions ==========
|
|
41
|
+
def detect_ollama_models():
|
|
42
|
+
models = []
|
|
43
|
+
try:
|
|
44
|
+
import ollama
|
|
45
|
+
result = ollama.list()
|
|
46
|
+
for model in result.get('models', []):
|
|
47
|
+
name = model.get('model', model.get('name', ''))
|
|
48
|
+
if name:
|
|
49
|
+
models.append(name)
|
|
50
|
+
except:
|
|
51
|
+
pass
|
|
52
|
+
return models
|
|
53
|
+
|
|
54
|
+
def detect_lm_studio():
|
|
55
|
+
try:
|
|
56
|
+
import requests
|
|
57
|
+
resp = requests.get('http://localhost:1234/v1/models', timeout=2)
|
|
58
|
+
if resp.status_code == 200:
|
|
59
|
+
return [m.get('id', '') for m in resp.json().get('data', [])]
|
|
60
|
+
except:
|
|
61
|
+
pass
|
|
62
|
+
return []
|
|
63
|
+
|
|
64
|
+
def detect_api_keys():
|
|
65
|
+
keys = {}
|
|
66
|
+
for key in ['ANTHROPIC_API_KEY', 'OPENAI_API_KEY', 'GEMINI_API_KEY', 'DEEPSEEK_API_KEY']:
|
|
67
|
+
if os.environ.get(key):
|
|
68
|
+
keys[key] = True
|
|
69
|
+
return keys
|
|
70
|
+
|
|
71
|
+
def get_cloud_models(api_keys):
|
|
72
|
+
models = []
|
|
73
|
+
if api_keys.get('ANTHROPIC_API_KEY'):
|
|
74
|
+
models.extend([('anthropic', 'claude-sonnet-4-20250514'), ('anthropic', 'claude-3-5-haiku-20241022')])
|
|
75
|
+
if api_keys.get('GEMINI_API_KEY'):
|
|
76
|
+
models.extend([('gemini', 'gemini-2.5-flash'), ('gemini', 'gemini-1.5-pro')])
|
|
77
|
+
if api_keys.get('DEEPSEEK_API_KEY'):
|
|
78
|
+
models.extend([('deepseek', 'deepseek-chat')])
|
|
79
|
+
return models
|
|
80
|
+
|
|
81
|
+
# ========== State ==========
|
|
82
|
+
class InitState:
|
|
83
|
+
def __init__(self):
|
|
84
|
+
self.phase = 0 # 0=dir, 1=detect, 2=model, 3=config, 4=confirm, 5=done
|
|
85
|
+
self.sel = 0
|
|
86
|
+
self.scroll = 0
|
|
87
|
+
self.directory = os.path.abspath(context.get('directory') or './npc_project')
|
|
88
|
+
self.editing = False
|
|
89
|
+
self.edit_buf = ""
|
|
90
|
+
self.edit_field = ""
|
|
91
|
+
|
|
92
|
+
# Detection results
|
|
93
|
+
self.ollama_models = []
|
|
94
|
+
self.lm_studio_models = []
|
|
95
|
+
self.cloud_models = []
|
|
96
|
+
self.api_keys = {}
|
|
97
|
+
self.all_models = [] # (provider, model) tuples
|
|
98
|
+
|
|
99
|
+
# Config
|
|
100
|
+
self.config = {
|
|
101
|
+
'model': context.get('model') or '',
|
|
102
|
+
'provider': context.get('provider') or '',
|
|
103
|
+
'team_name': 'npc_team',
|
|
104
|
+
'forenpc': 'forenpc',
|
|
105
|
+
'context_desc': 'A team of AI agents',
|
|
106
|
+
}
|
|
107
|
+
self.config_keys = ['model', 'provider', 'team_name', 'forenpc', 'context_desc']
|
|
108
|
+
self.config_labels = {
|
|
109
|
+
'model': 'Default Model',
|
|
110
|
+
'provider': 'Default Provider',
|
|
111
|
+
'team_name': 'Team Directory',
|
|
112
|
+
'forenpc': 'Coordinator NPC',
|
|
113
|
+
'context_desc': 'Team Description',
|
|
114
|
+
}
|
|
115
|
+
self.config_sel = 0
|
|
116
|
+
|
|
117
|
+
self.status = ""
|
|
118
|
+
self.error = ""
|
|
119
|
+
self.result = ""
|
|
120
|
+
|
|
121
|
+
ui = InitState()
|
|
122
|
+
|
|
123
|
+
# ========== Helpers ==========
|
|
124
|
+
def get_size():
|
|
125
|
+
try:
|
|
126
|
+
s = os.get_terminal_size()
|
|
127
|
+
return s.columns, s.lines
|
|
128
|
+
except:
|
|
129
|
+
return 80, 24
|
|
130
|
+
|
|
131
|
+
def run_detection():
|
|
132
|
+
ui.status = "Detecting Ollama models..."
|
|
133
|
+
render()
|
|
134
|
+
ui.ollama_models = detect_ollama_models()
|
|
135
|
+
|
|
136
|
+
ui.status = "Checking LM Studio..."
|
|
137
|
+
render()
|
|
138
|
+
ui.lm_studio_models = detect_lm_studio()
|
|
139
|
+
|
|
140
|
+
ui.status = "Checking API keys..."
|
|
141
|
+
render()
|
|
142
|
+
ui.api_keys = detect_api_keys()
|
|
143
|
+
ui.cloud_models = get_cloud_models(ui.api_keys)
|
|
144
|
+
|
|
145
|
+
# Build all_models list
|
|
146
|
+
ui.all_models = []
|
|
147
|
+
for m in ui.ollama_models:
|
|
148
|
+
ui.all_models.append(('ollama', m))
|
|
149
|
+
for m in ui.lm_studio_models:
|
|
150
|
+
ui.all_models.append(('lm_studio', m))
|
|
151
|
+
ui.all_models.extend(ui.cloud_models)
|
|
152
|
+
|
|
153
|
+
# Set defaults if found
|
|
154
|
+
if ui.all_models and not ui.config['model']:
|
|
155
|
+
ui.config['provider'], ui.config['model'] = ui.all_models[0]
|
|
156
|
+
|
|
157
|
+
total = len(ui.all_models)
|
|
158
|
+
ui.status = f"Found {total} models"
|
|
159
|
+
|
|
160
|
+
# ========== Rendering ==========
|
|
161
|
+
def render():
|
|
162
|
+
width, height = get_size()
|
|
163
|
+
out = []
|
|
164
|
+
out.append('\033[H') # Home cursor only, no full clear
|
|
165
|
+
|
|
166
|
+
phase_names = ['Directory', 'Detecting...', 'Select Model', 'Configure', 'Confirm', 'Complete']
|
|
167
|
+
phase_icons = ['1', '2', '3', '4', '5', '*']
|
|
168
|
+
|
|
169
|
+
# Progress bar
|
|
170
|
+
progress = ''
|
|
171
|
+
for i, name in enumerate(phase_names[:-1]):
|
|
172
|
+
if i < ui.phase:
|
|
173
|
+
progress += f'\033[32m[{phase_icons[i]}]\033[0m '
|
|
174
|
+
elif i == ui.phase:
|
|
175
|
+
progress += f'\033[33;1m[{phase_icons[i]}]\033[0m '
|
|
176
|
+
else:
|
|
177
|
+
progress += f'\033[90m[{phase_icons[i]}]\033[0m '
|
|
178
|
+
|
|
179
|
+
header = ' NPC INIT '
|
|
180
|
+
out.append(f'\033[1;1H\033[7;1m{header.ljust(width)}\033[0m')
|
|
181
|
+
out.append(f'\033[2;2H{progress}')
|
|
182
|
+
|
|
183
|
+
if ui.phase == 0:
|
|
184
|
+
render_directory(out, width, height)
|
|
185
|
+
elif ui.phase == 1:
|
|
186
|
+
render_detecting(out, width, height)
|
|
187
|
+
elif ui.phase == 2:
|
|
188
|
+
render_model_select(out, width, height)
|
|
189
|
+
elif ui.phase == 3:
|
|
190
|
+
render_config(out, width, height)
|
|
191
|
+
elif ui.phase == 4:
|
|
192
|
+
render_confirm(out, width, height)
|
|
193
|
+
elif ui.phase == 5:
|
|
194
|
+
render_done(out, width, height)
|
|
195
|
+
|
|
196
|
+
if ui.error:
|
|
197
|
+
out.append(f'\033[{height-1};1H\033[K\033[31m {ui.error[:width-3]}\033[0m')
|
|
198
|
+
|
|
199
|
+
sys.stdout.write(''.join(out))
|
|
200
|
+
sys.stdout.flush()
|
|
201
|
+
|
|
202
|
+
def render_directory(out, width, height):
|
|
203
|
+
banner = [
|
|
204
|
+
'\033[36m ██╗███╗ ██╗██╗████████╗\033[0m',
|
|
205
|
+
'\033[36m ██║████╗ ██║██║╚══██╔══╝\033[0m',
|
|
206
|
+
'\033[36m ██║██╔██╗ ██║██║ ██║ \033[0m',
|
|
207
|
+
'\033[36m ██║██║╚██╗██║██║ ██║ \033[0m',
|
|
208
|
+
'\033[36m ██║██║ ╚████║██║ ██║ \033[0m',
|
|
209
|
+
'\033[36m ╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝ \033[0m',
|
|
210
|
+
]
|
|
211
|
+
for i, line in enumerate(banner):
|
|
212
|
+
out.append(f'\033[{4+i};3H{line}')
|
|
213
|
+
|
|
214
|
+
y = 4 + len(banner) + 2
|
|
215
|
+
out.append(f'\033[{y};3H\033[1mProject Directory:\033[0m')
|
|
216
|
+
y += 2
|
|
217
|
+
|
|
218
|
+
if ui.editing:
|
|
219
|
+
out.append(f'\033[{y};3H\033[7m > {ui.edit_buf}_ \033[0m')
|
|
220
|
+
else:
|
|
221
|
+
exists = os.path.exists(ui.directory)
|
|
222
|
+
status = '\033[33m(exists)\033[0m' if exists else '\033[32m(will create)\033[0m'
|
|
223
|
+
out.append(f'\033[{y};3H\033[7m > {ui.directory} \033[0m {status}')
|
|
224
|
+
|
|
225
|
+
y += 2
|
|
226
|
+
out.append(f'\033[{y};3H\033[90mThis will create:\033[0m')
|
|
227
|
+
y += 1
|
|
228
|
+
preview_dir = ui.edit_buf if ui.editing else ui.directory
|
|
229
|
+
out.append(f'\033[{y};5H\033[90m{preview_dir}/\033[0m')
|
|
230
|
+
out.append(f'\033[{y+1};5H\033[90m├── npc_team/\033[0m')
|
|
231
|
+
out.append(f'\033[{y+2};5H\033[90m│ ├── forenpc.npc\033[0m')
|
|
232
|
+
out.append(f'\033[{y+3};5H\033[90m│ ├── team.ctx\033[0m')
|
|
233
|
+
out.append(f'\033[{y+4};5H\033[90m│ ├── jinxs/\033[0m')
|
|
234
|
+
out.append(f'\033[{y+5};5H\033[90m│ └── tools/\033[0m')
|
|
235
|
+
out.append(f'\033[{y+6};5H\033[90m├── images/\033[0m')
|
|
236
|
+
out.append(f'\033[{y+7};5H\033[90m├── models/\033[0m')
|
|
237
|
+
out.append(f'\033[{y+8};5H\033[90m└── mcp_servers/\033[0m')
|
|
238
|
+
|
|
239
|
+
if ui.editing:
|
|
240
|
+
out.append(f'\033[{height};1H\033[K\033[7m Enter:Confirm Esc:Cancel \033[0m'.ljust(width))
|
|
241
|
+
else:
|
|
242
|
+
out.append(f'\033[{height};1H\033[K\033[7m e:Edit Enter:Next q:Quit \033[0m'.ljust(width))
|
|
243
|
+
|
|
244
|
+
def render_detecting(out, width, height):
|
|
245
|
+
mid = height // 2
|
|
246
|
+
out.append(f'\033[{mid-1};3H\033[1mDetecting available models...\033[0m')
|
|
247
|
+
out.append(f'\033[{mid+1};3H\033[33m{ui.status}\033[0m')
|
|
248
|
+
|
|
249
|
+
y = mid + 3
|
|
250
|
+
# Show what we've found so far
|
|
251
|
+
if ui.ollama_models:
|
|
252
|
+
out.append(f'\033[{y};5H\033[32m✓\033[0m Ollama: {len(ui.ollama_models)} models')
|
|
253
|
+
y += 1
|
|
254
|
+
if ui.lm_studio_models:
|
|
255
|
+
out.append(f'\033[{y};5H\033[32m✓\033[0m LM Studio: {len(ui.lm_studio_models)} models')
|
|
256
|
+
y += 1
|
|
257
|
+
for key in ['ANTHROPIC_API_KEY', 'GEMINI_API_KEY', 'DEEPSEEK_API_KEY']:
|
|
258
|
+
if ui.api_keys.get(key):
|
|
259
|
+
short = key.replace('_API_KEY', '').lower()
|
|
260
|
+
out.append(f'\033[{y};5H\033[32m✓\033[0m {short}')
|
|
261
|
+
y += 1
|
|
262
|
+
|
|
263
|
+
def render_model_select(out, width, height):
|
|
264
|
+
y = 4
|
|
265
|
+
out.append(f'\033[{y};3H\033[1mSelect Default Model:\033[0m')
|
|
266
|
+
y += 1
|
|
267
|
+
|
|
268
|
+
# Show detection summary
|
|
269
|
+
out.append(f'\033[{y};3H\033[90mDetected: {len(ui.ollama_models)} ollama, {len(ui.lm_studio_models)} lm_studio, {len(ui.cloud_models)} cloud\033[0m')
|
|
270
|
+
y += 2
|
|
271
|
+
|
|
272
|
+
list_height = height - 10
|
|
273
|
+
visible = ui.all_models[ui.scroll:ui.scroll + list_height]
|
|
274
|
+
|
|
275
|
+
for i, (provider, model) in enumerate(visible):
|
|
276
|
+
idx = ui.scroll + i
|
|
277
|
+
row = y + i
|
|
278
|
+
|
|
279
|
+
# Provider color
|
|
280
|
+
pcolor = {'ollama': '\033[33m', 'lm_studio': '\033[35m', 'anthropic': '\033[34m',
|
|
281
|
+
'gemini': '\033[32m', 'deepseek': '\033[36m'}.get(provider, '\033[37m')
|
|
282
|
+
|
|
283
|
+
if idx == ui.sel:
|
|
284
|
+
out.append(f'\033[{row};2H\033[7;1m > {model:<40} {pcolor}{provider}\033[0m\033[7m \033[0m')
|
|
285
|
+
else:
|
|
286
|
+
out.append(f'\033[{row};2H {model:<40} {pcolor}{provider}\033[0m')
|
|
287
|
+
|
|
288
|
+
if not ui.all_models:
|
|
289
|
+
out.append(f'\033[{y};3H\033[31mNo models found! Install Ollama or set API keys.\033[0m')
|
|
290
|
+
out.append(f'\033[{y+2};3H\033[90mYou can still continue and configure manually.\033[0m')
|
|
291
|
+
|
|
292
|
+
out.append(f'\033[{height};1H\033[K\033[7m j/k:Navigate Enter:Select s:Skip q:Quit \033[0m'.ljust(width))
|
|
293
|
+
|
|
294
|
+
def render_config(out, width, height):
|
|
295
|
+
y = 4
|
|
296
|
+
out.append(f'\033[{y};3H\033[1mConfigure Team:\033[0m')
|
|
297
|
+
y += 2
|
|
298
|
+
|
|
299
|
+
for i, key in enumerate(ui.config_keys):
|
|
300
|
+
label = ui.config_labels[key]
|
|
301
|
+
val = ui.config[key]
|
|
302
|
+
row = y + i * 2
|
|
303
|
+
|
|
304
|
+
if ui.editing and ui.edit_field == key:
|
|
305
|
+
out.append(f'\033[{row};3H\033[33m{label}:\033[0m')
|
|
306
|
+
out.append(f'\033[{row+1};5H\033[7m {ui.edit_buf}_ \033[0m')
|
|
307
|
+
elif i == ui.config_sel:
|
|
308
|
+
out.append(f'\033[{row};3H\033[1m{label}:\033[0m')
|
|
309
|
+
out.append(f'\033[{row+1};5H\033[7m {val or "(not set)"} \033[0m')
|
|
310
|
+
else:
|
|
311
|
+
out.append(f'\033[{row};3H\033[90m{label}:\033[0m')
|
|
312
|
+
not_set = '\033[90m(not set)\033[0m'
|
|
313
|
+
out.append(f'\033[{row+1};5H {val or not_set}')
|
|
314
|
+
|
|
315
|
+
if ui.editing:
|
|
316
|
+
out.append(f'\033[{height};1H\033[K\033[7m Enter:Save Esc:Cancel \033[0m'.ljust(width))
|
|
317
|
+
else:
|
|
318
|
+
out.append(f'\033[{height};1H\033[K\033[7m j/k:Navigate e:Edit Enter:Next Backspace:Back q:Quit \033[0m'.ljust(width))
|
|
319
|
+
|
|
320
|
+
def render_confirm(out, width, height):
|
|
321
|
+
y = 4
|
|
322
|
+
out.append(f'\033[{y};3H\033[1mReady to Initialize:\033[0m')
|
|
323
|
+
y += 2
|
|
324
|
+
|
|
325
|
+
out.append(f'\033[{y};5H\033[1mDirectory:\033[0m {ui.directory}')
|
|
326
|
+
y += 1
|
|
327
|
+
out.append(f'\033[{y};5H\033[1mModel:\033[0m {ui.config["model"]} ({ui.config["provider"]})')
|
|
328
|
+
y += 1
|
|
329
|
+
out.append(f'\033[{y};5H\033[1mTeam:\033[0m {ui.config["team_name"]}')
|
|
330
|
+
y += 1
|
|
331
|
+
out.append(f'\033[{y};5H\033[1mCoordinator:\033[0m {ui.config["forenpc"]}')
|
|
332
|
+
y += 1
|
|
333
|
+
out.append(f'\033[{y};5H\033[1mDescription:\033[0m {ui.config["context_desc"]}')
|
|
334
|
+
y += 2
|
|
335
|
+
|
|
336
|
+
out.append(f'\033[{y};3H\033[90mWill create:\033[0m')
|
|
337
|
+
y += 1
|
|
338
|
+
files = [
|
|
339
|
+
f'{ui.directory}/{ui.config["team_name"]}/team.ctx',
|
|
340
|
+
f'{ui.directory}/{ui.config["team_name"]}/{ui.config["forenpc"]}.npc',
|
|
341
|
+
f'{ui.directory}/{ui.config["team_name"]}/jinxs/',
|
|
342
|
+
f'{ui.directory}/{ui.config["team_name"]}/tools/',
|
|
343
|
+
f'{ui.directory}/images/',
|
|
344
|
+
f'{ui.directory}/models/',
|
|
345
|
+
f'{ui.directory}/mcp_servers/',
|
|
346
|
+
]
|
|
347
|
+
for f in files:
|
|
348
|
+
out.append(f'\033[{y};5H\033[90m{f}\033[0m')
|
|
349
|
+
y += 1
|
|
350
|
+
|
|
351
|
+
out.append(f'\033[{height};1H\033[K\033[7m Enter:Create Backspace:Back q:Quit \033[0m'.ljust(width))
|
|
352
|
+
|
|
353
|
+
def render_done(out, width, height):
|
|
354
|
+
y = 4
|
|
355
|
+
if ui.error:
|
|
356
|
+
out.append(f'\033[{y};3H\033[31;1mInitialization Failed\033[0m')
|
|
357
|
+
y += 2
|
|
358
|
+
out.append(f'\033[{y};3H\033[31m{ui.error}\033[0m')
|
|
359
|
+
else:
|
|
360
|
+
out.append(f'\033[{y};3H\033[32;1mProject Initialized!\033[0m')
|
|
361
|
+
y += 2
|
|
362
|
+
out.append(f'\033[{y};3H{ui.result}')
|
|
363
|
+
y += 2
|
|
364
|
+
out.append(f'\033[{y};3H\033[1mNext steps:\033[0m')
|
|
365
|
+
y += 1
|
|
366
|
+
out.append(f'\033[{y};5H\033[36mcd {ui.directory}\033[0m')
|
|
367
|
+
y += 1
|
|
368
|
+
out.append(f'\033[{y};5H\033[36mnpcsh\033[0m')
|
|
369
|
+
y += 2
|
|
370
|
+
out.append(f'\033[{y};3H\033[90mOr add more NPCs:\033[0m')
|
|
371
|
+
y += 1
|
|
372
|
+
out.append(f'\033[{y};5H\033[90mCreate {ui.config["team_name"]}/analyst.npc, {ui.config["team_name"]}/writer.npc, etc.\033[0m')
|
|
373
|
+
|
|
374
|
+
out.append(f'\033[{height};1H\033[K\033[7m Enter/q:Exit \033[0m'.ljust(width))
|
|
375
|
+
|
|
376
|
+
# ========== Execution ==========
|
|
377
|
+
def do_init():
|
|
378
|
+
from npcpy.npc_compiler import initialize_npc_project
|
|
379
|
+
try:
|
|
380
|
+
initialize_npc_project(
|
|
381
|
+
directory=ui.directory,
|
|
382
|
+
templates=context.get('templates'),
|
|
383
|
+
context=ui.config['context_desc'],
|
|
384
|
+
model=ui.config['model'],
|
|
385
|
+
provider=ui.config['provider']
|
|
386
|
+
)
|
|
387
|
+
ui.result = f"Created project at {os.path.abspath(ui.directory)}"
|
|
388
|
+
ui.error = ""
|
|
389
|
+
except Exception as e:
|
|
390
|
+
ui.error = str(e)
|
|
391
|
+
ui.result = ""
|
|
392
|
+
|
|
393
|
+
# ========== Input ==========
|
|
394
|
+
def handle_input(c, fd):
|
|
395
|
+
if ui.editing:
|
|
396
|
+
return handle_edit(c, fd)
|
|
397
|
+
|
|
398
|
+
# Escape sequences
|
|
399
|
+
if c == '\x1b':
|
|
400
|
+
if select.select([fd], [], [], 0.05)[0]:
|
|
401
|
+
c2 = os.read(fd, 1).decode('latin-1')
|
|
402
|
+
if c2 == '[':
|
|
403
|
+
c3 = os.read(fd, 1).decode('latin-1')
|
|
404
|
+
if c3 == 'A': move_up()
|
|
405
|
+
elif c3 == 'B': move_down()
|
|
406
|
+
return True
|
|
407
|
+
|
|
408
|
+
if c == 'q' or c == '\x03':
|
|
409
|
+
return False
|
|
410
|
+
|
|
411
|
+
if ui.phase == 0: # Directory
|
|
412
|
+
if c == 'e':
|
|
413
|
+
ui.editing = True
|
|
414
|
+
ui.edit_buf = ui.directory
|
|
415
|
+
elif c in ('\r', '\n'):
|
|
416
|
+
ui.phase = 1
|
|
417
|
+
render()
|
|
418
|
+
run_detection()
|
|
419
|
+
ui.phase = 2
|
|
420
|
+
ui.sel = 0
|
|
421
|
+
ui.scroll = 0
|
|
422
|
+
|
|
423
|
+
elif ui.phase == 2: # Model select
|
|
424
|
+
if c == 'j': move_down()
|
|
425
|
+
elif c == 'k': move_up()
|
|
426
|
+
elif c == 's': # Skip
|
|
427
|
+
ui.phase = 3
|
|
428
|
+
ui.config_sel = 0
|
|
429
|
+
elif c in ('\r', '\n'):
|
|
430
|
+
if ui.all_models and ui.sel < len(ui.all_models):
|
|
431
|
+
ui.config['provider'], ui.config['model'] = ui.all_models[ui.sel]
|
|
432
|
+
ui.phase = 3
|
|
433
|
+
ui.config_sel = 0
|
|
434
|
+
|
|
435
|
+
elif ui.phase == 3: # Config
|
|
436
|
+
if c == 'j': move_down()
|
|
437
|
+
elif c == 'k': move_up()
|
|
438
|
+
elif c == 'e':
|
|
439
|
+
key = ui.config_keys[ui.config_sel]
|
|
440
|
+
ui.editing = True
|
|
441
|
+
ui.edit_field = key
|
|
442
|
+
ui.edit_buf = ui.config[key]
|
|
443
|
+
elif c == '\x7f' or c == '\x08': # Backspace
|
|
444
|
+
ui.phase = 2
|
|
445
|
+
ui.sel = 0
|
|
446
|
+
elif c in ('\r', '\n'):
|
|
447
|
+
ui.phase = 4
|
|
448
|
+
|
|
449
|
+
elif ui.phase == 4: # Confirm
|
|
450
|
+
if c == '\x7f' or c == '\x08':
|
|
451
|
+
ui.phase = 3
|
|
452
|
+
ui.config_sel = 0
|
|
453
|
+
elif c in ('\r', '\n'):
|
|
454
|
+
ui.phase = 5
|
|
455
|
+
render()
|
|
456
|
+
do_init()
|
|
457
|
+
|
|
458
|
+
elif ui.phase == 5: # Done
|
|
459
|
+
if c in ('\r', '\n', 'q'):
|
|
460
|
+
return False
|
|
461
|
+
|
|
462
|
+
return True
|
|
463
|
+
|
|
464
|
+
def handle_edit(c, fd):
|
|
465
|
+
if c == '\x1b':
|
|
466
|
+
if select.select([fd], [], [], 0.05)[0]:
|
|
467
|
+
os.read(fd, 2)
|
|
468
|
+
ui.editing = False
|
|
469
|
+
ui.edit_buf = ""
|
|
470
|
+
return True
|
|
471
|
+
if c in ('\r', '\n'):
|
|
472
|
+
if ui.phase == 0:
|
|
473
|
+
ui.directory = os.path.abspath(os.path.expanduser(ui.edit_buf)) if ui.edit_buf else ui.directory
|
|
474
|
+
elif ui.phase == 3:
|
|
475
|
+
ui.config[ui.edit_field] = ui.edit_buf
|
|
476
|
+
ui.editing = False
|
|
477
|
+
return True
|
|
478
|
+
if c == '\x7f' or c == '\x08':
|
|
479
|
+
ui.edit_buf = ui.edit_buf[:-1]
|
|
480
|
+
return True
|
|
481
|
+
if c >= ' ' and c <= '~':
|
|
482
|
+
ui.edit_buf += c
|
|
483
|
+
return True
|
|
484
|
+
|
|
485
|
+
def move_up():
|
|
486
|
+
if ui.phase == 2:
|
|
487
|
+
ui.sel = max(0, ui.sel - 1)
|
|
488
|
+
if ui.sel < ui.scroll:
|
|
489
|
+
ui.scroll = ui.sel
|
|
490
|
+
elif ui.phase == 3:
|
|
491
|
+
ui.config_sel = max(0, ui.config_sel - 1)
|
|
492
|
+
|
|
493
|
+
def move_down():
|
|
494
|
+
_, height = get_size()
|
|
495
|
+
if ui.phase == 2:
|
|
496
|
+
ui.sel = min(len(ui.all_models) - 1, ui.sel + 1) if ui.all_models else 0
|
|
497
|
+
list_height = height - 10
|
|
498
|
+
if ui.sel >= ui.scroll + list_height:
|
|
499
|
+
ui.scroll = ui.sel - list_height + 1
|
|
500
|
+
elif ui.phase == 3:
|
|
501
|
+
ui.config_sel = min(len(ui.config_keys) - 1, ui.config_sel + 1)
|
|
502
|
+
|
|
503
|
+
# ========== Main Loop ==========
|
|
504
|
+
fd = sys.stdin.fileno()
|
|
505
|
+
old_settings = termios.tcgetattr(fd)
|
|
506
|
+
|
|
507
|
+
try:
|
|
508
|
+
tty.setcbreak(fd)
|
|
509
|
+
sys.stdout.write('\033[?25l') # hide cursor
|
|
510
|
+
sys.stdout.write('\033[2J\033[H') # initial full clear
|
|
511
|
+
sys.stdout.flush()
|
|
512
|
+
render()
|
|
513
|
+
|
|
514
|
+
while True:
|
|
515
|
+
c = os.read(fd, 1).decode('latin-1')
|
|
516
|
+
if not handle_input(c, fd):
|
|
517
|
+
break
|
|
518
|
+
render()
|
|
519
|
+
finally:
|
|
520
|
+
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
|
|
521
|
+
sys.stdout.write('\033[?25h\033[2J\033[H')
|
|
522
|
+
sys.stdout.flush()
|
|
523
|
+
|
|
524
|
+
if ui.result:
|
|
525
|
+
print(ui.result)
|
|
526
|
+
context['output'] = ui.result
|
|
527
|
+
elif ui.error:
|
|
528
|
+
context['output'] = f"Error: {ui.error}"
|
|
529
|
+
else:
|
|
530
|
+
context['output'] = "Init cancelled."
|
|
531
|
+
|
|
532
|
+
context['messages'] = context.get('messages', [])
|
|
@@ -11,11 +11,10 @@ colors:
|
|
|
11
11
|
top: "255,255,255"
|
|
12
12
|
bottom: "173,216,230"
|
|
13
13
|
primary_directive: |
|
|
14
|
-
You are kadiefa, the exploratory snow leopard. You
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
Use web search and browsing tools to discover new information.
|
|
14
|
+
You are kadiefa, the exploratory snow leopard. You wander into places no one else looks.
|
|
15
|
+
Think outside the box. Make unexpected connections across domains.
|
|
16
|
+
Reframe problems. Pull in ideas from biology, music, history, anywhere surprising.
|
|
17
|
+
Follow the most interesting thread, not the most obvious one.
|
|
19
18
|
jinxs:
|
|
20
19
|
- lib/core/python
|
|
21
20
|
- lib/core/sh
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
context: |
|
|
2
|
+
The npcsh NPC team is devoted to providing a safe and helpful
|
|
3
|
+
environment for users where they can work and be as successful as possible.
|
|
4
|
+
npcsh is a command-line tool that makes it easy for users to harness
|
|
5
|
+
the power of LLMs from a command line shell. npcsh is a command line toolkit consisting of several programs.
|
|
6
|
+
|
|
7
|
+
## How to solve tasks with tools
|
|
8
|
+
You have access to tools (jinxs) like sh, python, edit_file, load_file, etc.
|
|
9
|
+
When solving tasks that require action:
|
|
10
|
+
1. PLAN: Break the task into concrete steps before doing anything.
|
|
11
|
+
2. ORIENT: Check your environment first (ls, pwd, which, cat). Never assume files or tools exist.
|
|
12
|
+
3. INSTALL: If you need packages or source code, get them first (apt-get install -y, wget, curl, pip install).
|
|
13
|
+
4. EXECUTE: Run one command at a time. Read the output carefully before proceeding.
|
|
14
|
+
5. ADAPT: If a command fails, read the error. Diagnose the actual cause and fix it. Never repeat the same failed command without changing something.
|
|
15
|
+
6. VERIFY: Confirm your work (check files exist, test the output).
|
|
16
|
+
|
|
17
|
+
Common mistakes to avoid:
|
|
18
|
+
- Running ./configure or make before downloading and extracting source code
|
|
19
|
+
- Retrying the exact same command that just failed
|
|
20
|
+
- Not checking what directory you're in or what files are present
|
|
21
|
+
- Trying to use a tool/package without installing it first
|
|
22
|
+
databases:
|
|
23
|
+
- ~/npcsh_history.db
|
|
24
|
+
mcp_servers:
|
|
25
|
+
- ~/.npcsh/mcp_server.py
|
|
26
|
+
use_global_jinxs: true
|
|
27
|
+
forenpc: sibiji
|
|
28
|
+
preferences:
|
|
29
|
+
- If you come up with an idea, it is critical that you also provide a way to validate the idea.
|
|
30
|
+
- Never change function names unless requested. keep things idempotent.
|
|
31
|
+
- If plots are requested for python code, prefer to use matplotlib. Do not ever use seaborn.
|
|
32
|
+
- Object oriented programming should be used sparingly and only when practical. Otherwise, opt for functional implementations.
|
|
33
|
+
- Never write unit tests unless explicitly requested.
|
|
34
|
+
- If we want you to write tests, we mean we want you to write example use cases that show how the code works.
|