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
@@ -18,4 +18,5 @@ primary_directive: |
18
18
  Use web search and browsing tools to discover new information.
19
19
  jinxs:
20
20
  - lib/core/python
21
- - bin/wander
21
+ - lib/core/sh
22
+ - lib/core/search/web_search
npcsh/npc_team/sibiji.npc CHANGED
@@ -17,8 +17,8 @@ primary_directive: |
17
17
  When delegating, match the task to the agent whose primary_directive best fits. Basic search inquiries can be handled by yourself. Do not delegate unnecessarily.
18
18
  You have access to the delegate tool to pass tasks to other agents.
19
19
  jinxs:
20
- - lib/orchestration/delegate
21
- - lib/orchestration/convene
20
+ - lib/core/delegate
21
+ - lib/core/convene
22
22
  - lib/core/sh
23
23
  - lib/core/python
24
- - lib/core/search
24
+ - lib/core/search/web_search
npcsh/npcsh.py CHANGED
@@ -1,5 +1,6 @@
1
1
  import os
2
2
  import sys
3
+ import shutil
3
4
  import argparse
4
5
  import importlib.metadata
5
6
  import warnings
@@ -123,7 +124,7 @@ Welcome to {BLUE}npc{RESET}{RUST}sh{RESET}!
123
124
  {BLUE}|🤖|{RESET}
124
125
  {RUST}___________________________________________{RESET}
125
126
 
126
- Begin by asking a question, issuing a bash command, or typing '/help' for more information.
127
+ Ask a question, run a command, or type '/help' to get started.
127
128
  """)
128
129
 
129
130
 
@@ -138,35 +139,88 @@ def run_repl(command_history: CommandHistory, initial_state: ShellState, router,
138
139
  if launched_jinx:
139
140
  state, output = execute_command(f"/{launched_jinx}", state, router=router, command_history=command_history)
140
141
  process_result(f"/{launched_jinx}", state, output, command_history)
141
- else:
142
- render_markdown(f'- Using {state.current_mode} mode. Use /agent, /cmd, or /chat to switch to other modes')
143
- render_markdown('- To switch to a different NPC, type /npc <npc_name> or /n <npc_name> to switch to that NPC.')
144
- render_markdown('\n- Here are the current NPCs available in your team: ' + ', '.join([npc_name for npc_name in state.team.npcs.keys()]))
145
- # Show jinxs organized by folder using _source_path from jinx objects
146
- jinxs_by_folder = {}
142
+
143
+ # Print startup info panel
144
+ BLUE = "\033[1;94m"
145
+ RUST = "\033[1;38;5;202m"
146
+ DIM = "\033[2m"
147
+ BOLD = "\033[1m"
148
+ RESET = "\033[0m"
149
+
150
+ term_width = min(shutil.get_terminal_size().columns, 80)
151
+
152
+ def _wrap_names(names, indent=4, sep=" "):
153
+ """Wrap a list of prefixed names to fit terminal width."""
154
+ lines = []
155
+ line = " " * indent
156
+ for name in names:
157
+ if len(line) + len(name) + len(sep) > term_width and line.strip():
158
+ lines.append(line.rstrip())
159
+ line = " " * indent
160
+ line += name + sep
161
+ if line.strip():
162
+ lines.append(line.rstrip())
163
+ return "\n".join(lines)
164
+
165
+ if not launched_jinx:
166
+ print(f" {DIM}mode:{RESET} {BOLD}{state.current_mode}{RESET} {DIM}│{RESET} {DIM}switch:{RESET} /agent /cmd /chat")
167
+
168
+ # NPCs with @ prefix
169
+ npc_names = [f"@{n}" for n in state.team.npcs.keys()]
170
+ print(f" {DIM}npcs:{RESET} {BLUE}{(' ').join(npc_names)}{RESET}")
171
+
172
+ # Jinxs - organized by group, hiding incognide, computer_use, and browser
173
+ hidden_folders = {'incognide', 'computer_use', 'browser'}
174
+ jinxs_by_group = {}
147
175
  if hasattr(state.team, 'jinxs_dict'):
148
176
  for jinx_name, jinx_obj in state.team.jinxs_dict.items():
149
- folder = 'other'
177
+ group = 'other'
178
+ subgroup = None
150
179
  if hasattr(jinx_obj, '_source_path') and jinx_obj._source_path:
151
180
  parts = jinx_obj._source_path.split(os.sep)
152
181
  if 'jinxs' in parts:
153
182
  idx = parts.index('jinxs')
154
- if idx + 1 < len(parts) - 1:
155
- folder = parts[idx + 1]
183
+ remaining = parts[idx + 1:] # e.g. ['lib', 'core', 'sh.jinx']
184
+ if any(seg in hidden_folders for seg in remaining):
185
+ continue
186
+ if len(remaining) > 1:
187
+ group = remaining[0]
188
+ # For lib, use the subfolder as subgroup
189
+ if group == 'lib' and len(remaining) > 2:
190
+ subgroup = remaining[1]
156
191
  else:
157
- folder = 'root'
158
- if folder not in jinxs_by_folder:
159
- jinxs_by_folder[folder] = []
160
- jinxs_by_folder[folder].append(jinx_name)
161
-
162
- if jinxs_by_folder:
163
- folder_order = ['bin', 'lib', 'npc_studio', 'root', 'other']
164
- sorted_folders = sorted(jinxs_by_folder.keys(), key=lambda x: (folder_order.index(x) if x in folder_order else 99, x))
165
- jinx_summary = []
166
- for folder in sorted_folders:
167
- count = len(jinxs_by_folder[folder])
168
- jinx_summary.append(f"{folder}/ ({count})")
169
- render_markdown('\n- Available Jinxs: ' + ', '.join(jinx_summary) + ' — use `/jinxs` for details')
192
+ group = 'root'
193
+ key = (group, subgroup)
194
+ if key not in jinxs_by_group:
195
+ jinxs_by_group[key] = []
196
+ jinxs_by_group[key].append(jinx_name)
197
+
198
+ if jinxs_by_group:
199
+ print()
200
+ # Collect top-level groups and their subgroups
201
+ group_order = ['bin', 'modes', 'lib', 'npc_studio', 'root', 'other']
202
+ # Sort keys: by group order, then subgroup alphabetically
203
+ sorted_keys = sorted(
204
+ jinxs_by_group.keys(),
205
+ key=lambda k: (group_order.index(k[0]) if k[0] in group_order else 99, k[1] or '')
206
+ )
207
+ last_group = None
208
+ for group, subgroup in sorted_keys:
209
+ names = sorted(jinxs_by_group[(group, subgroup)])
210
+ prefixed = [f"/{n}" for n in names]
211
+ if group != last_group:
212
+ label = group
213
+ if group == 'lib' and subgroup:
214
+ label = f"lib/{subgroup}"
215
+ print(f" {RUST}{label}/{RESET}")
216
+ elif subgroup:
217
+ print(f" {RUST}lib/{subgroup}/{RESET}")
218
+ else:
219
+ print(f" {RUST}{group}/{RESET}")
220
+ print(_wrap_names(prefixed))
221
+ last_group = group
222
+ print(f"\n {DIM}/jinxs for full list{RESET}")
223
+ print()
170
224
 
171
225
  is_windows = platform.system().lower().startswith("win")
172
226
  try:
@@ -187,32 +241,40 @@ def run_repl(command_history: CommandHistory, initial_state: ShellState, router,
187
241
  try:
188
242
  print(f" -> Archiving knowledge for: T='{team_name}', N='{npc_name}', P='{path}'")
189
243
 
190
- convo_id = current_state.conversation_id
191
- all_messages = command_history.get_conversations_by_id(convo_id)
244
+ # Only build KG from approved memories, not raw conversation
245
+ memory_examples = command_history.get_memory_examples_for_context(
246
+ npc=npc_name, team=team_name, directory_path=path
247
+ )
248
+ approved = memory_examples.get("approved", []) + memory_examples.get("edited", [])
192
249
 
193
- scope_messages = [
194
- m for m in all_messages
195
- if m.get('directory_path') == path and m.get('team') == team_name and m.get('npc') == npc_name
196
- ]
250
+ if not approved:
251
+ print(" ...No approved memories for this scope, skipping.")
252
+ continue
197
253
 
198
- full_text = "\n".join([f"{m['role']}: {m['content']}" for m in scope_messages if m.get('content')])
254
+ memory_statements = []
255
+ for mem in approved:
256
+ statement = mem.get("final_memory") or mem.get("initial_memory")
257
+ if statement:
258
+ memory_statements.append(statement)
199
259
 
200
- if not full_text.strip():
201
- print(" ...No content for this scope, skipping.")
260
+ if not memory_statements:
202
261
  continue
203
262
 
263
+ memory_text = "\n".join(f"- {s}" for s in memory_statements)
264
+ print(colored(f" evolving KG from {len(memory_statements)} approved memories...", "cyan"))
265
+
204
266
  current_kg = load_kg_from_db(engine, team_name, npc_name, path)
205
267
 
206
268
  evolved_kg, _ = kg_evolve_incremental(
207
269
  existing_kg=current_kg,
208
- new_content_text=full_text,
270
+ new_content_text=memory_text,
209
271
  model=current_state.npc.model,
210
272
  provider=current_state.npc.provider,
211
- npc= current_state.npc,
273
+ npc=current_state.npc,
212
274
  get_concepts=True,
213
- link_concepts_facts = True,
214
- link_concepts_concepts = True,
215
- link_facts_facts = True,
275
+ link_concepts_facts=True,
276
+ link_concepts_concepts=True,
277
+ link_facts_facts=True,
216
278
  )
217
279
 
218
280
  save_kg_to_db(engine,
@@ -237,16 +299,19 @@ def run_repl(command_history: CommandHistory, initial_state: ShellState, router,
237
299
  # Display usage before compacting
238
300
  display_usage(state)
239
301
 
240
- planning_state = {
241
- "goal": "ongoing npcsh session",
242
- "facts": [f"Working in {state.current_path}", f"Current mode: {state.current_mode}"],
243
- "successes": [],
244
- "mistakes": [],
245
- "todos": [],
246
- "constraints": ["Follow user requests", "Use appropriate mode for tasks"]
247
- }
248
- compressed_state = state.npc.compress_planning_state(planning_state)
249
- state.messages = [{"role": "system", "content": f"Session context: {compressed_state}"}]
302
+ # Pass actual messages so compress_planning_state summarizes real conversation
303
+ try:
304
+ compressed_state = state.npc.compress_planning_state(state.messages)
305
+ except Exception:
306
+ # Fallback: just keep recent messages if summarization fails
307
+ compressed_state = None
308
+
309
+ # Keep last 6 messages (3 exchanges) for immediate context
310
+ recent = state.messages[-6:]
311
+ if compressed_state:
312
+ state.messages = [{"role": "system", "content": f"Session context (earlier conversation summary): {compressed_state}"}] + recent
313
+ else:
314
+ state.messages = recent
250
315
 
251
316
  try:
252
317
  completer = make_completer(state, router)
npcsh/routes.py CHANGED
@@ -62,7 +62,10 @@ class CommandRouter:
62
62
  try:
63
63
  import shlex
64
64
 
65
- parts = shlex.split(command)
65
+ try:
66
+ parts = shlex.split(command)
67
+ except ValueError:
68
+ parts = command.split()
66
69
  args = parts[1:] if len(parts) > 1 else []
67
70
 
68
71
  # Use extract_jinx_inputs
File without changes