npcsh 1.1.20__py3-none-any.whl → 1.1.22__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.
Files changed (186) hide show
  1. npcsh/_state.py +15 -76
  2. npcsh/benchmark/npcsh_agent.py +22 -14
  3. npcsh/benchmark/templates/install-npcsh.sh.j2 +2 -2
  4. npcsh/diff_viewer.py +3 -3
  5. npcsh/mcp_server.py +9 -1
  6. npcsh/npc_team/alicanto.npc +12 -6
  7. npcsh/npc_team/corca.npc +0 -1
  8. npcsh/npc_team/frederic.npc +2 -3
  9. npcsh/npc_team/jinxs/lib/core/compress.jinx +373 -85
  10. npcsh/npc_team/jinxs/lib/core/edit_file.jinx +83 -61
  11. npcsh/npc_team/jinxs/lib/core/search/db_search.jinx +17 -6
  12. npcsh/npc_team/jinxs/lib/core/search/file_search.jinx +17 -6
  13. npcsh/npc_team/jinxs/lib/core/search/web_search.jinx +52 -14
  14. npcsh/npc_team/jinxs/{bin → lib/utils}/benchmark.jinx +2 -2
  15. npcsh/npc_team/jinxs/{bin → lib/utils}/jinxs.jinx +12 -12
  16. npcsh/npc_team/jinxs/{bin → lib/utils}/models.jinx +7 -7
  17. npcsh/npc_team/jinxs/{bin → lib/utils}/setup.jinx +6 -6
  18. npcsh/npc_team/jinxs/modes/alicanto.jinx +1633 -295
  19. npcsh/npc_team/jinxs/modes/arxiv.jinx +5 -5
  20. npcsh/npc_team/jinxs/modes/build.jinx +378 -0
  21. npcsh/npc_team/jinxs/modes/config_tui.jinx +300 -0
  22. npcsh/npc_team/jinxs/modes/convene.jinx +597 -0
  23. npcsh/npc_team/jinxs/modes/corca.jinx +777 -387
  24. npcsh/npc_team/jinxs/modes/git.jinx +795 -0
  25. {npcsh-1.1.20.data/data/npcsh/npc_team → npcsh/npc_team/jinxs/modes}/kg.jinx +82 -15
  26. npcsh/npc_team/jinxs/modes/memories.jinx +414 -0
  27. npcsh/npc_team/jinxs/{bin → modes}/nql.jinx +10 -21
  28. npcsh/npc_team/jinxs/modes/papers.jinx +578 -0
  29. npcsh/npc_team/jinxs/modes/plonk.jinx +503 -308
  30. npcsh/npc_team/jinxs/modes/reattach.jinx +3 -3
  31. npcsh/npc_team/jinxs/modes/spool.jinx +3 -3
  32. npcsh/npc_team/jinxs/{bin → modes}/team.jinx +12 -12
  33. npcsh/npc_team/jinxs/modes/vixynt.jinx +388 -0
  34. npcsh/npc_team/jinxs/modes/wander.jinx +454 -181
  35. npcsh/npc_team/jinxs/modes/yap.jinx +630 -182
  36. npcsh/npc_team/kadiefa.npc +2 -1
  37. npcsh/npc_team/sibiji.npc +3 -3
  38. npcsh/npcsh.py +112 -47
  39. npcsh/routes.py +4 -1
  40. npcsh/salmon_simulation.py +0 -0
  41. npcsh-1.1.22.data/data/npcsh/npc_team/alicanto.jinx +1694 -0
  42. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/alicanto.npc +12 -6
  43. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/arxiv.jinx +5 -5
  44. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/benchmark.jinx +2 -2
  45. npcsh-1.1.22.data/data/npcsh/npc_team/build.jinx +378 -0
  46. npcsh-1.1.22.data/data/npcsh/npc_team/compress.jinx +428 -0
  47. npcsh-1.1.22.data/data/npcsh/npc_team/config_tui.jinx +300 -0
  48. npcsh-1.1.22.data/data/npcsh/npc_team/corca.jinx +820 -0
  49. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/corca.npc +0 -1
  50. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/db_search.jinx +17 -6
  51. npcsh-1.1.22.data/data/npcsh/npc_team/edit_file.jinx +119 -0
  52. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/file_search.jinx +17 -6
  53. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/frederic.npc +2 -3
  54. npcsh-1.1.22.data/data/npcsh/npc_team/git.jinx +795 -0
  55. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/jinxs.jinx +12 -12
  56. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/kadiefa.npc +2 -1
  57. {npcsh/npc_team/jinxs/bin → npcsh-1.1.22.data/data/npcsh/npc_team}/kg.jinx +82 -15
  58. npcsh-1.1.22.data/data/npcsh/npc_team/memories.jinx +414 -0
  59. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/models.jinx +7 -7
  60. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/nql.jinx +10 -21
  61. npcsh-1.1.22.data/data/npcsh/npc_team/papers.jinx +578 -0
  62. npcsh-1.1.22.data/data/npcsh/npc_team/plonk.jinx +574 -0
  63. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/reattach.jinx +3 -3
  64. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/setup.jinx +6 -6
  65. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/sibiji.npc +3 -3
  66. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/spool.jinx +3 -3
  67. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/team.jinx +12 -12
  68. npcsh-1.1.22.data/data/npcsh/npc_team/vixynt.jinx +388 -0
  69. npcsh-1.1.22.data/data/npcsh/npc_team/wander.jinx +728 -0
  70. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/web_search.jinx +52 -14
  71. npcsh-1.1.22.data/data/npcsh/npc_team/yap.jinx +716 -0
  72. {npcsh-1.1.20.dist-info → npcsh-1.1.22.dist-info}/METADATA +246 -281
  73. npcsh-1.1.22.dist-info/RECORD +240 -0
  74. npcsh-1.1.22.dist-info/entry_points.txt +11 -0
  75. npcsh/npc_team/jinxs/bin/config_tui.jinx +0 -300
  76. npcsh/npc_team/jinxs/bin/memories.jinx +0 -317
  77. npcsh/npc_team/jinxs/bin/vixynt.jinx +0 -122
  78. npcsh/npc_team/jinxs/lib/core/search/kg_search.jinx +0 -418
  79. npcsh/npc_team/jinxs/lib/core/search/mem_review.jinx +0 -73
  80. npcsh/npc_team/jinxs/lib/core/search/mem_search.jinx +0 -388
  81. npcsh/npc_team/jinxs/lib/core/search.jinx +0 -54
  82. npcsh/npc_team/jinxs/lib/research/paper_search.jinx +0 -412
  83. npcsh/npc_team/jinxs/lib/research/semantic_scholar.jinx +0 -386
  84. npcsh/npc_team/jinxs/lib/utils/build.jinx +0 -65
  85. npcsh/npc_team/plonkjr.npc +0 -23
  86. npcsh-1.1.20.data/data/npcsh/npc_team/alicanto.jinx +0 -356
  87. npcsh-1.1.20.data/data/npcsh/npc_team/build.jinx +0 -65
  88. npcsh-1.1.20.data/data/npcsh/npc_team/compress.jinx +0 -140
  89. npcsh-1.1.20.data/data/npcsh/npc_team/config_tui.jinx +0 -300
  90. npcsh-1.1.20.data/data/npcsh/npc_team/corca.jinx +0 -430
  91. npcsh-1.1.20.data/data/npcsh/npc_team/edit_file.jinx +0 -97
  92. npcsh-1.1.20.data/data/npcsh/npc_team/kg_search.jinx +0 -418
  93. npcsh-1.1.20.data/data/npcsh/npc_team/mem_review.jinx +0 -73
  94. npcsh-1.1.20.data/data/npcsh/npc_team/mem_search.jinx +0 -388
  95. npcsh-1.1.20.data/data/npcsh/npc_team/memories.jinx +0 -317
  96. npcsh-1.1.20.data/data/npcsh/npc_team/paper_search.jinx +0 -412
  97. npcsh-1.1.20.data/data/npcsh/npc_team/plonk.jinx +0 -379
  98. npcsh-1.1.20.data/data/npcsh/npc_team/plonkjr.npc +0 -23
  99. npcsh-1.1.20.data/data/npcsh/npc_team/search.jinx +0 -54
  100. npcsh-1.1.20.data/data/npcsh/npc_team/semantic_scholar.jinx +0 -386
  101. npcsh-1.1.20.data/data/npcsh/npc_team/vixynt.jinx +0 -122
  102. npcsh-1.1.20.data/data/npcsh/npc_team/wander.jinx +0 -455
  103. npcsh-1.1.20.data/data/npcsh/npc_team/yap.jinx +0 -268
  104. npcsh-1.1.20.dist-info/RECORD +0 -248
  105. npcsh-1.1.20.dist-info/entry_points.txt +0 -25
  106. /npcsh/npc_team/jinxs/lib/{orchestration → core}/convene.jinx +0 -0
  107. /npcsh/npc_team/jinxs/lib/{orchestration → core}/delegate.jinx +0 -0
  108. /npcsh/npc_team/jinxs/{bin → lib/core}/sample.jinx +0 -0
  109. /npcsh/npc_team/jinxs/lib/{core → utils}/chat.jinx +0 -0
  110. /npcsh/npc_team/jinxs/lib/{core → utils}/cmd.jinx +0 -0
  111. /npcsh/npc_team/jinxs/{bin → lib/utils}/sync.jinx +0 -0
  112. /npcsh/npc_team/jinxs/{bin → modes}/roll.jinx +0 -0
  113. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/add_tab.jinx +0 -0
  114. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/alicanto.png +0 -0
  115. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/browser_action.jinx +0 -0
  116. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/browser_screenshot.jinx +0 -0
  117. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/chat.jinx +0 -0
  118. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/click.jinx +0 -0
  119. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/close_browser.jinx +0 -0
  120. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/close_pane.jinx +0 -0
  121. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/close_tab.jinx +0 -0
  122. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/cmd.jinx +0 -0
  123. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/compile.jinx +0 -0
  124. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/confirm.jinx +0 -0
  125. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/convene.jinx +0 -0
  126. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/corca.png +0 -0
  127. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/corca_example.png +0 -0
  128. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/delegate.jinx +0 -0
  129. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/focus_pane.jinx +0 -0
  130. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/frederic4.png +0 -0
  131. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/guac.jinx +0 -0
  132. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/guac.npc +0 -0
  133. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/guac.png +0 -0
  134. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/help.jinx +0 -0
  135. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/incognide.jinx +0 -0
  136. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/init.jinx +0 -0
  137. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/kadiefa.png +0 -0
  138. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/key_press.jinx +0 -0
  139. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/launch_app.jinx +0 -0
  140. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/list_panes.jinx +0 -0
  141. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/load_file.jinx +0 -0
  142. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/navigate.jinx +0 -0
  143. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/notify.jinx +0 -0
  144. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/npcsh.ctx +0 -0
  145. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/npcsh_sibiji.png +0 -0
  146. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/open_browser.jinx +0 -0
  147. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/open_pane.jinx +0 -0
  148. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/ots.jinx +0 -0
  149. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/paste.jinx +0 -0
  150. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/plonk.npc +0 -0
  151. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/plonk.png +0 -0
  152. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/plonkjr.png +0 -0
  153. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/pti.jinx +0 -0
  154. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/python.jinx +0 -0
  155. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/read_pane.jinx +0 -0
  156. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/roll.jinx +0 -0
  157. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/run_terminal.jinx +0 -0
  158. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/sample.jinx +0 -0
  159. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/screenshot.jinx +0 -0
  160. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/send_message.jinx +0 -0
  161. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/serve.jinx +0 -0
  162. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/set.jinx +0 -0
  163. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/sh.jinx +0 -0
  164. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/shh.jinx +0 -0
  165. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/sibiji.png +0 -0
  166. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/sleep.jinx +0 -0
  167. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/split_pane.jinx +0 -0
  168. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/spool.png +0 -0
  169. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/sql.jinx +0 -0
  170. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/switch.jinx +0 -0
  171. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/switch_npc.jinx +0 -0
  172. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/switch_tab.jinx +0 -0
  173. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/switches.jinx +0 -0
  174. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/sync.jinx +0 -0
  175. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/teamviz.jinx +0 -0
  176. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/trigger.jinx +0 -0
  177. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/type_text.jinx +0 -0
  178. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/usage.jinx +0 -0
  179. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/verbose.jinx +0 -0
  180. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/wait.jinx +0 -0
  181. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/write_file.jinx +0 -0
  182. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/yap.png +0 -0
  183. {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/zen_mode.jinx +0 -0
  184. {npcsh-1.1.20.dist-info → npcsh-1.1.22.dist-info}/WHEEL +0 -0
  185. {npcsh-1.1.20.dist-info → npcsh-1.1.22.dist-info}/licenses/LICENSE +0 -0
  186. {npcsh-1.1.20.dist-info → npcsh-1.1.22.dist-info}/top_level.txt +0 -0
npcsh/_state.py CHANGED
@@ -2537,19 +2537,16 @@ def collect_llm_tools(state: ShellState) -> Tuple[List[Dict[str, Any]], Dict[str
2537
2537
  elif npc_obj and getattr(npc_obj, "tool_map", None):
2538
2538
  tool_map.update(npc_obj.tool_map)
2539
2539
 
2540
- # Jinx tools from NPC and Team
2540
+ # Jinx tools from NPC only (NPC.jinxs_dict is already filtered by jinxs_spec
2541
+ # during initialize_jinxs - don't add the full team catalog which overwhelms small models)
2541
2542
  aggregated_jinxs: Dict[str, Any] = {}
2542
2543
  if npc_obj and getattr(npc_obj, "jinxs_dict", None):
2543
2544
  aggregated_jinxs.update(npc_obj.jinxs_dict)
2544
- if state.team and isinstance(state.team, Team) and getattr(state.team, "jinxs_dict", None):
2545
- aggregated_jinxs.update({k: v for k, v in state.team.jinxs_dict.items() if k not in aggregated_jinxs})
2546
2545
 
2547
2546
  if aggregated_jinxs:
2548
2547
  jinx_catalog: Dict[str, Dict[str, Any]] = {}
2549
2548
  if npc_obj and getattr(npc_obj, "jinx_tool_catalog", None):
2550
2549
  jinx_catalog.update(npc_obj.jinx_tool_catalog or {})
2551
- if state.team and isinstance(state.team, Team) and getattr(state.team, "jinx_tool_catalog", None):
2552
- jinx_catalog.update(state.team.jinx_tool_catalog or {})
2553
2550
  if not jinx_catalog:
2554
2551
  jinx_catalog = build_jinx_tool_catalog(aggregated_jinxs)
2555
2552
 
@@ -2898,6 +2895,14 @@ def process_pipeline_command(
2898
2895
  tools_for_llm, tool_exec_map = collect_llm_tools(state)
2899
2896
  if not tools_for_llm:
2900
2897
  tool_capable = False
2898
+ else:
2899
+ # Add tool guidance so model knows to use function calls
2900
+ tool_names = [t['function']['name'] for t in tools_for_llm if 'function' in t]
2901
+ info += (
2902
+ f"\nYou have access to these tools: {', '.join(tool_names)}. "
2903
+ f"You MUST use the function calling interface to invoke them. "
2904
+ f"Do NOT write tool names as text - call them as functions."
2905
+ )
2901
2906
 
2902
2907
  npc_name = (
2903
2908
  state.npc.name
@@ -3444,9 +3449,9 @@ def setup_shell() -> Tuple[CommandHistory, Team, Optional[NPC]]:
3444
3449
  command_history = CommandHistory(db_path)
3445
3450
 
3446
3451
  if not is_npcsh_initialized():
3447
- print("Initializing NPCSH...")
3452
+ print("Setting up npcsh for first use...")
3448
3453
  initialize_base_npcs_if_needed(db_path)
3449
- print("NPCSH initialization complete. Restart or source ~/.npcshrc.")
3454
+ print("Setup complete.")
3450
3455
 
3451
3456
  try:
3452
3457
  setup_readline()
@@ -3458,80 +3463,17 @@ def setup_shell() -> Tuple[CommandHistory, Team, Optional[NPC]]:
3458
3463
  project_team_path = os.path.abspath(PROJECT_NPC_TEAM_PATH)
3459
3464
  global_team_path = os.path.expanduser(DEFAULT_NPC_TEAM_PATH)
3460
3465
 
3461
- team_dir = None
3462
- default_forenpc_name = None
3463
- global_team_path = os.path.expanduser(DEFAULT_NPC_TEAM_PATH)
3464
3466
  if not os.path.exists(global_team_path):
3465
- print("Global NPC team directory doesn't exist. Initializing...")
3466
3467
  initialize_base_npcs_if_needed(db_path)
3467
3468
  if os.path.exists(project_team_path):
3468
3469
  team_dir = project_team_path
3469
3470
  default_forenpc_name = "forenpc"
3470
3471
  else:
3471
- if not os.path.exists('.npcsh_global'):
3472
- try:
3473
- resp = input(f"No npc_team found in {os.getcwd()}. Create a new team here? [Y/n]: ").strip().lower()
3474
- except (KeyboardInterrupt, EOFError):
3475
- print("\nAborted.")
3476
- sys.exit(0)
3477
- if resp in ("", "y", "yes"):
3478
- team_dir = project_team_path
3479
- os.makedirs(team_dir, exist_ok=True)
3480
- default_forenpc_name = "forenpc"
3481
- try:
3482
- forenpc_directive = input(
3483
- f"Enter a primary directive for {default_forenpc_name} (default: 'You are the forenpc of the team...'): "
3484
- ).strip() or "You are the forenpc of the team, coordinating activities between NPCs on the team, verifying that results from NPCs are high quality and can help to adequately answer user requests."
3485
- forenpc_model = input("Enter a model for your forenpc (default: llama3.2): ").strip() or "llama3.2"
3486
- forenpc_provider = input("Enter a provider for your forenpc (default: ollama): ").strip() or "ollama"
3487
- except (KeyboardInterrupt, EOFError):
3488
- print("\nAborted.")
3489
- sys.exit(0)
3490
-
3491
- with open(os.path.join(team_dir, f"{default_forenpc_name}.npc"), "w") as f:
3492
- yaml.dump({
3493
- "name": default_forenpc_name, "primary_directive": forenpc_directive,
3494
- "model": forenpc_model, "provider": forenpc_provider
3495
- }, f)
3496
-
3497
- ctx_path = os.path.join(team_dir, "team.ctx")
3498
- try:
3499
- folder_context = input("Enter a short description for this project/team (optional): ").strip()
3500
- team_ctx_data = {
3501
- "forenpc": default_forenpc_name,
3502
- "model": forenpc_model,
3503
- "provider": forenpc_provider,
3504
- "context": folder_context if folder_context else None
3505
- }
3506
- use_jinxs = input("Use global jinxs folder (g) or copy to this project (c)? [g/c, default: g]: ").strip().lower()
3507
- except (KeyboardInterrupt, EOFError):
3508
- print("\nAborted.")
3509
- sys.exit(0)
3510
- if use_jinxs == "c":
3511
- global_jinxs_dir = os.path.expanduser("~/.npcsh/npc_team/jinxs")
3512
- if os.path.exists(global_jinxs_dir):
3513
- # Create the 'jinxs' subfolder within the new team's directory
3514
- destination_jinxs_dir = os.path.join(team_dir, "jinxs")
3515
- os.makedirs(destination_jinxs_dir, exist_ok=True)
3516
- shutil.copytree(global_jinxs_dir, destination_jinxs_dir, dirs_exist_ok=True)
3517
- else:
3518
- team_ctx_data["use_global_jinxs"] = True
3519
- with open(ctx_path, "w") as f:
3520
- yaml.dump(team_ctx_data, f)
3521
- else:
3522
- render_markdown('From now on, npcsh will assume you will use the global team when activating from this folder. \n If you change your mind and want to initialize a team, use /init from within npcsh, `npc init` or `rm .npcsh_global` from the current working directory.')
3523
- with open(".npcsh_global", "w") as f:
3524
- pass
3525
- team_dir = global_team_path
3526
- default_forenpc_name = "sibiji"
3527
- else:
3528
- team_dir = global_team_path
3529
- default_forenpc_name = "sibiji"
3530
-
3531
- if team_dir is None:
3472
+ # No project team in this directory - use global team.
3473
+ # To create a project team, use /init from within npcsh or `npc init`.
3532
3474
  team_dir = global_team_path
3533
3475
  default_forenpc_name = "sibiji"
3534
-
3476
+
3535
3477
  if not os.path.exists(team_dir):
3536
3478
  print(f"Creating team directory: {team_dir}")
3537
3479
  os.makedirs(team_dir, exist_ok=True)
@@ -3548,11 +3490,8 @@ def setup_shell() -> Tuple[CommandHistory, Team, Optional[NPC]]:
3548
3490
  forenpc_name = team_ctx.get("forenpc", default_forenpc_name)
3549
3491
  if forenpc_name is None:
3550
3492
  forenpc_name = "sibiji"
3551
-
3552
- print('forenpc_name:', forenpc_name)
3553
3493
 
3554
3494
  forenpc_path = os.path.join(team_dir, f"{forenpc_name}.npc")
3555
- print('forenpc_path:', forenpc_path)
3556
3495
 
3557
3496
  team = Team(team_path=team_dir, db_conn=command_history.engine)
3558
3497
 
@@ -53,11 +53,11 @@ class NpcshAgent(BaseInstalledAgent):
53
53
  Returns:
54
54
  List of ExecInput commands to execute
55
55
  """
56
- # Wrap the instruction with explicit jinx usage directions and retry logic
57
- tool_instruction = f"""You have access to jinxs including edit_file (for writing/creating files), sh (for running shell commands), and python (for running Python code).
56
+ # Wrap the instruction with tool usage directions and retry logic
57
+ tool_instruction = f"""You have access to tools: edit_file (for writing/creating files), sh (for running shell commands), and python (for running Python code).
58
58
 
59
59
  IMPORTANT RULES:
60
- 1. You MUST use these jinxs to complete the task. Do NOT just output code as text - use the edit_file jinx to actually write files to disk.
60
+ 1. You MUST call these tools using the function calling interface to complete the task. Do NOT write tool names as text - invoke them as function calls.
61
61
  2. After implementing a solution, you MUST verify it works by running any provided test scripts.
62
62
  3. If a test fails or produces an error, you MUST try a DIFFERENT approach. Do not give up.
63
63
  4. Keep trying different approaches until you succeed or have tried at least 10 different solutions.
@@ -66,13 +66,11 @@ IMPORTANT RULES:
66
66
  Task: {instruction}
67
67
 
68
68
  WORKFLOW:
69
- 1. Implement your solution using edit_file and sh
69
+ 1. Call edit_file to write code files. Call sh to run commands.
70
70
  2. Run any test scripts mentioned in the task
71
71
  3. Check the output carefully - look for "PASS", "SUCCESS", "OK" or similar
72
72
  4. If the test failed, analyze why and try a completely different approach
73
- 5. Repeat until the test passes
74
-
75
- Remember: Use edit_file to write code files. Use sh to run commands. VERIFY your solution works before concluding."""
73
+ 5. Repeat until the test passes"""
76
74
 
77
75
  escaped_instruction = shlex.quote(tool_instruction)
78
76
  model_name = self.model_name
@@ -146,8 +144,14 @@ Remember: Use edit_file to write code files. Use sh to run commands. VERIFY your
146
144
  # Using corca NPC which has edit_file tool for writing files
147
145
  # Using the npc CLI which supports single-command execution
148
146
  # NPCSH_DEFAULT_MODE=agent enables automatic tool execution
147
+ ollama_env = ""
148
+ if npcsh_provider == "ollama":
149
+ ollama_host = os.environ.get("OLLAMA_HOST", "http://host.docker.internal:11434")
150
+ ollama_env = f'OLLAMA_HOST="{ollama_host}" '
151
+
149
152
  npcsh_cmd = (
150
153
  f'{env_prefix}'
154
+ f'{ollama_env}'
151
155
  f'NPCSH_CHAT_MODEL="{model}" '
152
156
  f'NPCSH_CHAT_PROVIDER="{npcsh_provider}" '
153
157
  f'NPCSH_STREAM_OUTPUT=0 '
@@ -234,11 +238,11 @@ class NpcshAgentWithNpc(NpcshAgent):
234
238
 
235
239
  def create_run_agent_commands(self, instruction: str) -> list:
236
240
  """Create commands using a specific NPC."""
237
- # Wrap the instruction with explicit jinx usage directions and retry logic
238
- tool_instruction = f"""You have access to jinxs including edit_file (for writing/creating files), sh (for running shell commands), and python (for running Python code).
241
+ # Wrap the instruction with tool usage directions and retry logic
242
+ tool_instruction = f"""You have access to tools: edit_file (for writing/creating files), sh (for running shell commands), and python (for running Python code).
239
243
 
240
244
  IMPORTANT RULES:
241
- 1. You MUST use these jinxs to complete the task. Do NOT just output code as text - use the edit_file jinx to actually write files to disk.
245
+ 1. You MUST call these tools using the function calling interface to complete the task. Do NOT write tool names as text - invoke them as function calls.
242
246
  2. After implementing a solution, you MUST verify it works by running any provided test scripts.
243
247
  3. If a test fails or produces an error, you MUST try a DIFFERENT approach. Do not give up.
244
248
  4. Keep trying different approaches until you succeed or have tried at least 10 different solutions.
@@ -247,13 +251,11 @@ IMPORTANT RULES:
247
251
  Task: {instruction}
248
252
 
249
253
  WORKFLOW:
250
- 1. Implement your solution using edit_file and sh
254
+ 1. Call edit_file to write code files. Call sh to run commands.
251
255
  2. Run any test scripts mentioned in the task
252
256
  3. Check the output carefully - look for "PASS", "SUCCESS", "OK" or similar
253
257
  4. If the test failed, analyze why and try a completely different approach
254
- 5. Repeat until the test passes
255
-
256
- Remember: Use edit_file to write code files. Use sh to run commands. VERIFY your solution works before concluding."""
258
+ 5. Repeat until the test passes"""
257
259
 
258
260
  escaped_instruction = shlex.quote(tool_instruction)
259
261
  model_name = self.model_name
@@ -309,8 +311,14 @@ Remember: Use edit_file to write code files. Use sh to run commands. VERIFY your
309
311
 
310
312
  # Use specific NPC with --npc flag
311
313
  # NPCSH_DEFAULT_MODE=agent enables automatic tool execution
314
+ ollama_env = ""
315
+ if npcsh_provider == "ollama":
316
+ ollama_host = os.environ.get("OLLAMA_HOST", "http://host.docker.internal:11434")
317
+ ollama_env = f'OLLAMA_HOST="{ollama_host}" '
318
+
312
319
  npcsh_cmd = (
313
320
  f'{env_prefix}'
321
+ f'{ollama_env}'
314
322
  f'NPCSH_CHAT_MODEL="{model}" '
315
323
  f'NPCSH_CHAT_PROVIDER="{npcsh_provider}" '
316
324
  f'NPCSH_STREAM_OUTPUT=0 '
@@ -14,8 +14,8 @@ fi
14
14
 
15
15
  # Install npcsh with lite dependencies (API providers only, no local models)
16
16
  # Use --break-system-packages for PEP 668 compliance (Ubuntu 24.04+)
17
- echo "Installing npcsh[lite]..."
18
- pip install --quiet --break-system-packages npcsh[lite] || pip install --quiet npcsh[lite]
17
+ echo "Installing npcsh[lite] + ollama..."
18
+ pip install --quiet --break-system-packages npcsh[lite] ollama || pip install --quiet npcsh[lite] ollama
19
19
 
20
20
  # Verify installation
21
21
  echo "Verifying npcsh installation..."
npcsh/diff_viewer.py CHANGED
@@ -6,7 +6,7 @@ import os
6
6
  import sys
7
7
  import difflib
8
8
  from dataclasses import dataclass, field
9
- from typing import List, Dict, Optional, Tuple
9
+ from typing import List, Dict, Tuple
10
10
  from enum import Enum
11
11
 
12
12
  # Platform-specific imports
@@ -324,8 +324,8 @@ class DiffViewer:
324
324
  start = hunk.start_original - 1 + offset
325
325
 
326
326
  # Count removals and additions in this hunk
327
- removals = [l[1:] for l in hunk.lines if l.startswith('-')]
328
- additions = [l[1:] for l in hunk.lines if l.startswith('+')]
327
+ removals = [ln[1:] for ln in hunk.lines if ln.startswith('-')]
328
+ additions = [ln[1:] for ln in hunk.lines if ln.startswith('+')]
329
329
 
330
330
  # Remove old lines
331
331
  del result_lines[start:start + len(removals)]
npcsh/mcp_server.py CHANGED
@@ -1,9 +1,17 @@
1
1
 
2
2
  """
3
- Enhanced MCP server that incorporates functionality from npcpy.routes,
3
+ Enhanced MCP server that incorporates functionality from npcpy.routes,
4
4
  npcpy.llm_funcs, and npcpy.npc_compiler as tools.
5
5
  """
6
6
 
7
+ # When run as a subprocess, Python adds the script directory to sys.path[0].
8
+ # Since this file lives inside the npcsh package, that shadows the package
9
+ # (npcsh.py is found instead of the npcsh/ package). Remove it.
10
+ import sys as _sys, os as _os
11
+ _script_dir = _os.path.dirname(_os.path.abspath(__file__))
12
+ if _script_dir in _sys.path:
13
+ _sys.path.remove(_script_dir)
14
+
7
15
  import os
8
16
  import subprocess
9
17
  import json
@@ -11,13 +11,19 @@ colors:
11
11
  top: "255,215,0"
12
12
  bottom: "218,165,32"
13
13
  primary_directive: |
14
- You are alicanto, the research and exploration specialist of the NPC team.
15
- Like the mythical bird, you lead users to discover valuable information.
16
- Your role is web research, searching, and helping users explore topics.
17
- Use search tools to find information and present findings clearly.
14
+ You are alicanto, a research agent. You investigate hypotheses through experimentation and evidence gathering.
15
+ Search academic papers to ground your work in existing literature.
16
+ Search the web for data, documentation, and recent findings.
17
+ Write and execute Python code to analyze data, compute statistics, and generate results.
18
+ Use shell commands for data processing and system tasks.
19
+ Create files to record your findings, analyses, and evidence.
20
+ When exploring a hypothesis, gather evidence from multiple sources, analyze it quantitatively where possible, and document what you find.
21
+ Say RESEARCH_COMPLETE when you have sufficient evidence to evaluate your hypothesis.
18
22
  jinxs:
19
- - lib/core/search
23
+ - lib/core/search/web_search
24
+ - lib/core/search/file_search
25
+ - lib/core/search/db_search
20
26
  - lib/core/sh
21
27
  - lib/core/python
22
28
  - lib/core/load_file
23
- - lib/research/*
29
+ - lib/core/edit_file
npcsh/npc_team/corca.npc CHANGED
@@ -27,5 +27,4 @@ jinxs:
27
27
  - lib/core/python
28
28
  - lib/core/edit_file
29
29
  - lib/core/load_file
30
- - lib/core/search
31
30
 
@@ -22,6 +22,5 @@ jinxs:
22
22
  - lib/core/sql
23
23
  - lib/core/sh
24
24
  - lib/core/load_file
25
- - lib/core/search
26
- - lib/gen/*
27
- - bin/wander
25
+ - lib/core/search/web_search
26
+ - lib/core/edit_file