npcsh 1.1.21__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.
Files changed (188) hide show
  1. npcsh/_state.py +282 -125
  2. npcsh/benchmark/npcsh_agent.py +77 -232
  3. npcsh/benchmark/templates/install-npcsh.sh.j2 +12 -4
  4. npcsh/config.py +5 -2
  5. npcsh/mcp_server.py +9 -1
  6. npcsh/npc_team/alicanto.npc +8 -6
  7. npcsh/npc_team/corca.npc +5 -12
  8. npcsh/npc_team/frederic.npc +6 -9
  9. npcsh/npc_team/guac.npc +4 -4
  10. npcsh/npc_team/jinxs/lib/core/delegate.jinx +1 -1
  11. npcsh/npc_team/jinxs/lib/core/edit_file.jinx +84 -62
  12. npcsh/npc_team/jinxs/lib/core/sh.jinx +1 -1
  13. npcsh/npc_team/jinxs/lib/core/skill.jinx +59 -0
  14. npcsh/npc_team/jinxs/lib/utils/help.jinx +194 -10
  15. npcsh/npc_team/jinxs/lib/utils/init.jinx +528 -37
  16. npcsh/npc_team/jinxs/lib/utils/jinxs.jinx +0 -1
  17. npcsh/npc_team/jinxs/lib/utils/serve.jinx +938 -21
  18. npcsh/npc_team/jinxs/modes/alicanto.jinx +102 -41
  19. npcsh/npc_team/jinxs/modes/build.jinx +378 -0
  20. npcsh-1.1.21.data/data/npcsh/npc_team/config_tui.jinx → npcsh/npc_team/jinxs/modes/config.jinx +1 -1
  21. npcsh/npc_team/jinxs/modes/convene.jinx +670 -0
  22. npcsh/npc_team/jinxs/modes/corca.jinx +777 -387
  23. npcsh/npc_team/jinxs/modes/crond.jinx +818 -0
  24. npcsh/npc_team/jinxs/modes/kg.jinx +69 -2
  25. npcsh/npc_team/jinxs/modes/plonk.jinx +86 -15
  26. npcsh/npc_team/jinxs/modes/roll.jinx +368 -55
  27. npcsh/npc_team/jinxs/modes/skills.jinx +621 -0
  28. npcsh/npc_team/jinxs/modes/yap.jinx +1092 -177
  29. npcsh/npc_team/jinxs/skills/code-review/SKILL.md +45 -0
  30. npcsh/npc_team/jinxs/skills/debugging/SKILL.md +44 -0
  31. npcsh/npc_team/jinxs/skills/git-workflow.jinx +44 -0
  32. npcsh/npc_team/kadiefa.npc +6 -6
  33. npcsh/npc_team/npcsh.ctx +16 -0
  34. npcsh/npc_team/plonk.npc +5 -9
  35. npcsh/npc_team/sibiji.npc +15 -7
  36. npcsh/npcsh.py +1 -0
  37. npcsh/routes.py +0 -4
  38. npcsh/yap.py +22 -4
  39. npcsh-1.1.23.data/data/npcsh/npc_team/SKILL.md +44 -0
  40. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/alicanto.jinx +102 -41
  41. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/alicanto.npc +8 -6
  42. npcsh-1.1.23.data/data/npcsh/npc_team/build.jinx +378 -0
  43. npcsh/npc_team/jinxs/modes/config_tui.jinx → npcsh-1.1.23.data/data/npcsh/npc_team/config.jinx +1 -1
  44. npcsh-1.1.23.data/data/npcsh/npc_team/convene.jinx +670 -0
  45. npcsh-1.1.23.data/data/npcsh/npc_team/corca.jinx +820 -0
  46. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/corca.npc +5 -12
  47. npcsh-1.1.23.data/data/npcsh/npc_team/crond.jinx +818 -0
  48. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/delegate.jinx +1 -1
  49. npcsh-1.1.23.data/data/npcsh/npc_team/edit_file.jinx +119 -0
  50. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/frederic.npc +6 -9
  51. npcsh-1.1.23.data/data/npcsh/npc_team/git-workflow.jinx +44 -0
  52. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/guac.npc +4 -4
  53. npcsh-1.1.23.data/data/npcsh/npc_team/help.jinx +236 -0
  54. npcsh-1.1.23.data/data/npcsh/npc_team/init.jinx +532 -0
  55. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/jinxs.jinx +0 -1
  56. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/kadiefa.npc +6 -6
  57. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/kg.jinx +69 -2
  58. npcsh-1.1.23.data/data/npcsh/npc_team/npcsh.ctx +34 -0
  59. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/plonk.jinx +86 -15
  60. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/plonk.npc +5 -9
  61. npcsh-1.1.23.data/data/npcsh/npc_team/roll.jinx +378 -0
  62. npcsh-1.1.23.data/data/npcsh/npc_team/serve.jinx +943 -0
  63. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/sh.jinx +1 -1
  64. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/sibiji.npc +15 -7
  65. npcsh-1.1.23.data/data/npcsh/npc_team/skill.jinx +59 -0
  66. npcsh-1.1.23.data/data/npcsh/npc_team/skills.jinx +621 -0
  67. npcsh-1.1.23.data/data/npcsh/npc_team/yap.jinx +1190 -0
  68. {npcsh-1.1.21.dist-info → npcsh-1.1.23.dist-info}/METADATA +404 -278
  69. npcsh-1.1.23.dist-info/RECORD +216 -0
  70. npcsh/npc_team/jinxs/incognide/add_tab.jinx +0 -11
  71. npcsh/npc_team/jinxs/incognide/close_pane.jinx +0 -9
  72. npcsh/npc_team/jinxs/incognide/close_tab.jinx +0 -10
  73. npcsh/npc_team/jinxs/incognide/confirm.jinx +0 -10
  74. npcsh/npc_team/jinxs/incognide/focus_pane.jinx +0 -9
  75. npcsh/npc_team/jinxs/incognide/list_panes.jinx +0 -8
  76. npcsh/npc_team/jinxs/incognide/navigate.jinx +0 -10
  77. npcsh/npc_team/jinxs/incognide/notify.jinx +0 -10
  78. npcsh/npc_team/jinxs/incognide/open_pane.jinx +0 -13
  79. npcsh/npc_team/jinxs/incognide/read_pane.jinx +0 -9
  80. npcsh/npc_team/jinxs/incognide/run_terminal.jinx +0 -10
  81. npcsh/npc_team/jinxs/incognide/send_message.jinx +0 -10
  82. npcsh/npc_team/jinxs/incognide/split_pane.jinx +0 -12
  83. npcsh/npc_team/jinxs/incognide/switch_npc.jinx +0 -10
  84. npcsh/npc_team/jinxs/incognide/switch_tab.jinx +0 -10
  85. npcsh/npc_team/jinxs/incognide/write_file.jinx +0 -11
  86. npcsh/npc_team/jinxs/incognide/zen_mode.jinx +0 -9
  87. npcsh/npc_team/jinxs/lib/core/convene.jinx +0 -232
  88. npcsh/npc_team/jinxs/lib/core/search/kg_search.jinx +0 -429
  89. npcsh/npc_team/jinxs/lib/core/search.jinx +0 -54
  90. npcsh/npc_team/jinxs/lib/utils/build.jinx +0 -65
  91. npcsh-1.1.21.data/data/npcsh/npc_team/add_tab.jinx +0 -11
  92. npcsh-1.1.21.data/data/npcsh/npc_team/build.jinx +0 -65
  93. npcsh-1.1.21.data/data/npcsh/npc_team/close_pane.jinx +0 -9
  94. npcsh-1.1.21.data/data/npcsh/npc_team/close_tab.jinx +0 -10
  95. npcsh-1.1.21.data/data/npcsh/npc_team/confirm.jinx +0 -10
  96. npcsh-1.1.21.data/data/npcsh/npc_team/convene.jinx +0 -232
  97. npcsh-1.1.21.data/data/npcsh/npc_team/corca.jinx +0 -430
  98. npcsh-1.1.21.data/data/npcsh/npc_team/edit_file.jinx +0 -97
  99. npcsh-1.1.21.data/data/npcsh/npc_team/focus_pane.jinx +0 -9
  100. npcsh-1.1.21.data/data/npcsh/npc_team/help.jinx +0 -52
  101. npcsh-1.1.21.data/data/npcsh/npc_team/init.jinx +0 -41
  102. npcsh-1.1.21.data/data/npcsh/npc_team/kg_search.jinx +0 -429
  103. npcsh-1.1.21.data/data/npcsh/npc_team/list_panes.jinx +0 -8
  104. npcsh-1.1.21.data/data/npcsh/npc_team/navigate.jinx +0 -10
  105. npcsh-1.1.21.data/data/npcsh/npc_team/notify.jinx +0 -10
  106. npcsh-1.1.21.data/data/npcsh/npc_team/npcsh.ctx +0 -18
  107. npcsh-1.1.21.data/data/npcsh/npc_team/open_pane.jinx +0 -13
  108. npcsh-1.1.21.data/data/npcsh/npc_team/read_pane.jinx +0 -9
  109. npcsh-1.1.21.data/data/npcsh/npc_team/roll.jinx +0 -65
  110. npcsh-1.1.21.data/data/npcsh/npc_team/run_terminal.jinx +0 -10
  111. npcsh-1.1.21.data/data/npcsh/npc_team/search.jinx +0 -54
  112. npcsh-1.1.21.data/data/npcsh/npc_team/send_message.jinx +0 -10
  113. npcsh-1.1.21.data/data/npcsh/npc_team/serve.jinx +0 -26
  114. npcsh-1.1.21.data/data/npcsh/npc_team/split_pane.jinx +0 -12
  115. npcsh-1.1.21.data/data/npcsh/npc_team/switch_npc.jinx +0 -10
  116. npcsh-1.1.21.data/data/npcsh/npc_team/switch_tab.jinx +0 -10
  117. npcsh-1.1.21.data/data/npcsh/npc_team/write_file.jinx +0 -11
  118. npcsh-1.1.21.data/data/npcsh/npc_team/yap.jinx +0 -275
  119. npcsh-1.1.21.data/data/npcsh/npc_team/zen_mode.jinx +0 -9
  120. npcsh-1.1.21.dist-info/RECORD +0 -243
  121. /npcsh/npc_team/jinxs/lib/{core → utils}/chat.jinx +0 -0
  122. /npcsh/npc_team/jinxs/lib/{core → utils}/cmd.jinx +0 -0
  123. /npcsh/npc_team/jinxs/{incognide → lib/utils}/incognide.jinx +0 -0
  124. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/alicanto.png +0 -0
  125. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/arxiv.jinx +0 -0
  126. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/benchmark.jinx +0 -0
  127. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/browser_action.jinx +0 -0
  128. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/browser_screenshot.jinx +0 -0
  129. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/chat.jinx +0 -0
  130. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/click.jinx +0 -0
  131. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/close_browser.jinx +0 -0
  132. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/cmd.jinx +0 -0
  133. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/compile.jinx +0 -0
  134. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/compress.jinx +0 -0
  135. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/corca.png +0 -0
  136. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/corca_example.png +0 -0
  137. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/db_search.jinx +0 -0
  138. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/file_search.jinx +0 -0
  139. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/frederic4.png +0 -0
  140. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/git.jinx +0 -0
  141. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/guac.jinx +0 -0
  142. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/guac.png +0 -0
  143. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/incognide.jinx +0 -0
  144. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/kadiefa.png +0 -0
  145. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/key_press.jinx +0 -0
  146. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/launch_app.jinx +0 -0
  147. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/load_file.jinx +0 -0
  148. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/memories.jinx +0 -0
  149. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/models.jinx +0 -0
  150. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/npcsh_sibiji.png +0 -0
  151. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/nql.jinx +0 -0
  152. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/open_browser.jinx +0 -0
  153. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/ots.jinx +0 -0
  154. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/papers.jinx +0 -0
  155. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/paste.jinx +0 -0
  156. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/plonk.png +0 -0
  157. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/plonkjr.png +0 -0
  158. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/pti.jinx +0 -0
  159. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/python.jinx +0 -0
  160. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/reattach.jinx +0 -0
  161. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/sample.jinx +0 -0
  162. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/screenshot.jinx +0 -0
  163. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/set.jinx +0 -0
  164. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/setup.jinx +0 -0
  165. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/shh.jinx +0 -0
  166. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/sibiji.png +0 -0
  167. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/sleep.jinx +0 -0
  168. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/spool.jinx +0 -0
  169. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/spool.png +0 -0
  170. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/sql.jinx +0 -0
  171. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/switch.jinx +0 -0
  172. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/switches.jinx +0 -0
  173. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/sync.jinx +0 -0
  174. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/team.jinx +0 -0
  175. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/teamviz.jinx +0 -0
  176. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/trigger.jinx +0 -0
  177. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/type_text.jinx +0 -0
  178. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/usage.jinx +0 -0
  179. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/verbose.jinx +0 -0
  180. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/vixynt.jinx +0 -0
  181. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/wait.jinx +0 -0
  182. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/wander.jinx +0 -0
  183. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/web_search.jinx +0 -0
  184. {npcsh-1.1.21.data → npcsh-1.1.23.data}/data/npcsh/npc_team/yap.png +0 -0
  185. {npcsh-1.1.21.dist-info → npcsh-1.1.23.dist-info}/WHEEL +0 -0
  186. {npcsh-1.1.21.dist-info → npcsh-1.1.23.dist-info}/entry_points.txt +0 -0
  187. {npcsh-1.1.21.dist-info → npcsh-1.1.23.dist-info}/licenses/LICENSE +0 -0
  188. {npcsh-1.1.21.dist-info → npcsh-1.1.23.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,45 @@
1
+ ---
2
+ description: Conducts code reviews. Use when asked to review code, review a PR, or check code quality.
3
+ ---
4
+ # Code Review
5
+
6
+ ## approach
7
+ Start by reading the full diff to understand the scope of changes.
8
+ Identify the purpose of the change — is it a bug fix, new feature, refactor, or config change?
9
+ Note which files are modified and how they relate to each other.
10
+
11
+ ## structure
12
+ Check the following structural concerns:
13
+ - Are changes in the right files/modules?
14
+ - Is new code placed in a logical location?
15
+ - Are there any circular dependencies introduced?
16
+ - Is the change minimal — does it avoid unnecessary modifications?
17
+
18
+ ## correctness
19
+ Review for correctness:
20
+ - Does the logic handle edge cases (null, empty, boundary values)?
21
+ - Are error paths handled properly?
22
+ - Is state management correct (no race conditions, stale data)?
23
+ - Do new functions have the right return types?
24
+
25
+ ## style
26
+ Check style and conventions:
27
+ - Naming: are variables, functions, classes named clearly?
28
+ - Consistency: does the code match the project's existing patterns?
29
+ - Comments: are complex sections explained? Are there unnecessary comments?
30
+ - Formatting: consistent indentation, line length, spacing?
31
+
32
+ ## testing
33
+ Evaluate test coverage:
34
+ - Are new code paths tested?
35
+ - Are edge cases covered?
36
+ - Do tests actually assert meaningful behavior (not just "runs without error")?
37
+ - Are there integration tests where needed?
38
+
39
+ ## security
40
+ Check for security issues:
41
+ - Input validation at system boundaries
42
+ - No hardcoded secrets or credentials
43
+ - SQL injection, XSS, command injection prevention
44
+ - Proper authentication/authorization checks
45
+ - Sensitive data not logged or exposed
@@ -0,0 +1,44 @@
1
+ ---
2
+ description: Systematic debugging methodology. Use when asked to debug, troubleshoot, or diagnose issues.
3
+ ---
4
+ # Debugging
5
+
6
+ ## reproduce
7
+ First, reproduce the bug consistently:
8
+ - Get exact steps to trigger the issue
9
+ - Note the environment (OS, versions, config)
10
+ - Determine if it's deterministic or intermittent
11
+ - Find the minimal reproduction case
12
+
13
+ If you can't reproduce it, you can't verify a fix.
14
+
15
+ ## isolate
16
+ Narrow down the cause:
17
+ - Binary search through the codebase (git bisect)
18
+ - Comment out / disable components to isolate
19
+ - Check recent changes (git log, blame)
20
+ - Add targeted logging at boundaries
21
+ - Test with minimal input/config
22
+
23
+ ## diagnose
24
+ Once isolated, understand the root cause:
25
+ - Read the code path carefully, don't assume
26
+ - Check data flow — what goes in, what comes out?
27
+ - Look for state mutations, race conditions, stale caches
28
+ - Check external dependencies (API changes, schema drift)
29
+ - Verify assumptions with print/log/debugger
30
+
31
+ ## fix
32
+ Apply the minimal fix:
33
+ - Fix the root cause, not the symptom
34
+ - Keep the change as small as possible
35
+ - Add a test that fails without the fix and passes with it
36
+ - Check for similar patterns elsewhere in the codebase
37
+ - Document WHY the bug happened if it's non-obvious
38
+
39
+ ## verify
40
+ Confirm the fix works:
41
+ - Run the reproduction steps — bug should be gone
42
+ - Run the full test suite — no regressions
43
+ - Test edge cases around the fix
44
+ - Review the fix yourself before submitting
@@ -0,0 +1,44 @@
1
+ jinx_name: git-workflow
2
+ description: "Git workflow best practices. Use when asked about git branching, commits, or merge strategy. [Sections: branching, commits, merging, hotfix]"
3
+ inputs:
4
+ - section: all
5
+ steps:
6
+ - engine: skill
7
+ skill_name: git-workflow
8
+ skill_description: Git workflow best practices.
9
+ sections:
10
+ branching: |
11
+ Use feature branches off main/develop:
12
+ git checkout -b feature/my-feature develop
13
+ Name branches descriptively:
14
+ feature/ — new functionality
15
+ fix/ — bug fixes
16
+ chore/ — maintenance, deps, config
17
+ Keep branches short-lived. Rebase onto target before merging.
18
+ commits: |
19
+ Write clear commit messages:
20
+ Line 1: imperative summary under 72 chars
21
+ Line 3+: explain WHY, not what (the diff shows what)
22
+ One logical change per commit. Don't mix refactors with features.
23
+ Use conventional commits if the project uses them:
24
+ feat: add user search
25
+ fix: handle null avatar URL
26
+ chore: bump eslint to v9
27
+ merging: |
28
+ Prefer squash merges for feature branches (clean history).
29
+ Use merge commits for long-lived branches (preserves context).
30
+ Always pull/rebase before merging to avoid unnecessary merge commits.
31
+ Delete branches after merging.
32
+ Run CI before merging — never merge a red build.
33
+ hotfix: |
34
+ For urgent production fixes:
35
+ 1. Branch off main: git checkout -b hotfix/fix-name main
36
+ 2. Make the minimal fix
37
+ 3. Test thoroughly
38
+ 4. Merge to main AND develop/release
39
+ 5. Tag the release
40
+ Keep hotfix scope minimal — fix only the immediate issue.
41
+ scripts_json: '[]'
42
+ references_json: '[]'
43
+ assets_json: '[]'
44
+ section: '{{section}}'
@@ -11,11 +11,11 @@ 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 love to find new paths and to explore hidden gems.
15
- You go into caverns no cat has ventured into before. You climb peaks that others call crazy.
16
- Your role is to lead users on wandering explorations - deep research journeys that follow threads
17
- wherever they lead. You help users explore complex research questions and think outside the box.
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
- - bin/wander
20
+ - lib/core/sh
21
+ - lib/core/search/web_search
npcsh/npc_team/npcsh.ctx CHANGED
@@ -3,6 +3,22 @@ context: |
3
3
  environment for users where they can work and be as successful as possible.
4
4
  npcsh is a command-line tool that makes it easy for users to harness
5
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
6
22
  databases:
7
23
  - ~/npcsh_history.db
8
24
  mcp_servers:
npcsh/npc_team/plonk.npc CHANGED
@@ -11,15 +11,11 @@ colors:
11
11
  top: "34,139,34"
12
12
  bottom: "139,69,19"
13
13
  primary_directive: |
14
- You are plonk, the browser and GUI automation specialist.
15
-
16
- Browser tools: open_browser, browser_action, browser_screenshot, close_browser
17
-
18
- browser_action actions: click, type, type_and_enter, select, wait, scroll, get_text, get_page, get_elements, press_key
19
-
20
- Use get_elements to discover selectors on the page. Use xpath:// prefix for XPath selectors.
21
-
22
- Desktop tools: screenshot, click, type_text, key_press, launch_app, wait
14
+ You are plonk, the automation specialist for browser and desktop.
15
+ Browser: open_browser, browser_action, browser_screenshot, close_browser.
16
+ browser_action: click, type, type_and_enter, select, wait, scroll, get_text, get_page, get_elements, press_key.
17
+ Desktop: screenshot, click, type_text, key_press, launch_app, wait.
18
+ Use get_elements to find selectors. Use xpath:// for XPath. Screenshot after each step to verify.
23
19
  jinxs:
24
20
  - lib/browser/*
25
21
  - lib/computer_use/*
npcsh/npc_team/sibiji.npc CHANGED
@@ -11,14 +11,22 @@ colors:
11
11
  top: "148,0,211"
12
12
  bottom: "75,0,130"
13
13
  primary_directive: |
14
- You are sibiji, the orchestrator and general manager of the NPC team.
15
- Your role is to delegate tasks to appropriate specialist agents based on their expertise.
14
+ You are sibiji, the orchestrator of the NPC team.
16
15
 
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
- You have access to the delegate tool to pass tasks to other agents.
16
+ RULE 1: Simple tasks do them yourself with sh, python, or web_search. Then tell the user the answer.
17
+ RULE 2: Complex tasks — delegate to the right agent. Pass the user's request as the task.
18
+ RULE 3: After running a command, read the output and answer the user. Never delegate after you already have the result.
19
+
20
+ Agents:
21
+ @corca — shell, code, debug, files, sysadmin
22
+ @guac — data analysis, pandas, SQL, CSV
23
+ @alicanto — deep research, papers, literature review
24
+ @kadiefa — exploratory thinking, unexpected connections
25
+ @frederic — creative/math, unconventional solutions
26
+ @plonk — browser automation, GUI, screenshots
19
27
  jinxs:
20
- - lib/orchestration/delegate
21
- - lib/orchestration/convene
28
+ - lib/core/delegate
29
+ - modes/convene
22
30
  - lib/core/sh
23
31
  - lib/core/python
24
- - lib/core/search
32
+ - lib/core/search/web_search
npcsh/npcsh.py CHANGED
@@ -510,6 +510,7 @@ def main(npc_name: str = None) -> None:
510
510
  initial_state.npc = default_npc
511
511
 
512
512
  initial_state.team = team
513
+ initial_state.command_history = command_history
513
514
  if args.command:
514
515
  state = initial_state
515
516
  state.current_path = os.getcwd()
npcsh/routes.py CHANGED
@@ -51,10 +51,6 @@ class CommandRouter:
51
51
  self.jinx_objects[command_name] = jinx
52
52
  self.help_info[command_name] = jinx.description or "Jinx command"
53
53
 
54
- def is_interactive(self, command_name: str) -> bool:
55
- jinx = self.jinx_objects.get(command_name)
56
- return bool(jinx and getattr(jinx, 'interactive', False))
57
-
58
54
  def _execute_jinx(self, jinx: Jinx, command: str, **kwargs):
59
55
  messages = kwargs.get("messages", [])
60
56
  npc = kwargs.get('npc')
npcsh/yap.py CHANGED
@@ -4,6 +4,7 @@ yap - Voice chat mode CLI entry point
4
4
  This is a thin wrapper that executes the yap.jinx through the jinx mechanism.
5
5
  """
6
6
  import argparse
7
+ import os
7
8
  import sys
8
9
 
9
10
  from npcsh._state import setup_shell
@@ -14,8 +15,10 @@ def main():
14
15
  parser.add_argument("--model", "-m", type=str, help="LLM model to use")
15
16
  parser.add_argument("--provider", "-p", type=str, help="LLM provider to use")
16
17
  parser.add_argument("--files", "-f", nargs="*", help="Files to load for RAG context")
17
- parser.add_argument("--tts-model", type=str, default="kokoro", help="TTS model to use")
18
- parser.add_argument("--voice", type=str, default="af_heart", help="Voice for TTS")
18
+ parser.add_argument("--tts-model", type=str, default=None,
19
+ help="TTS engine (kokoro, qwen3, elevenlabs, openai, gemini, gtts)")
20
+ parser.add_argument("--voice", type=str, default=None,
21
+ help="Voice ID (engine-specific, e.g. af_heart for kokoro, ryan for qwen3)")
19
22
  args = parser.parse_args()
20
23
 
21
24
  # Setup shell to get team and default NPC
@@ -25,6 +28,20 @@ def main():
25
28
  print("Error: yap jinx not found. Ensure npc_team/jinxs/modes/yap.jinx exists.")
26
29
  sys.exit(1)
27
30
 
31
+ # Read saved TTS preferences from env (set by ~/.npcshrc)
32
+ saved_engine = os.environ.get("NPCSH_TTS_ENGINE", "")
33
+ saved_voice = os.environ.get("NPCSH_TTS_VOICE", "")
34
+ setup_done = os.environ.get("NPCSH_YAP_SETUP_DONE", "0") == "1"
35
+
36
+ # Resolve TTS engine: explicit arg > saved pref > default
37
+ tts_model = args.tts_model or saved_engine or "kokoro"
38
+ voice = args.voice or saved_voice or None
39
+
40
+ # Show setup if no explicit args and no saved prefs and not skipped
41
+ has_explicit_args = args.tts_model is not None or args.voice is not None
42
+ has_saved_prefs = bool(saved_engine)
43
+ show_setup = not has_explicit_args and not has_saved_prefs and not setup_done
44
+
28
45
  # Build context for jinx execution
29
46
  context = {
30
47
  "npc": default_npc,
@@ -33,8 +50,9 @@ def main():
33
50
  "model": args.model,
34
51
  "provider": args.provider,
35
52
  "files": ",".join(args.files) if args.files else None,
36
- "tts_model": args.tts_model,
37
- "voice": args.voice,
53
+ "tts_model": tts_model,
54
+ "voice": voice,
55
+ "show_setup": show_setup,
38
56
  }
39
57
 
40
58
  # Execute the jinx
@@ -0,0 +1,44 @@
1
+ ---
2
+ description: Systematic debugging methodology. Use when asked to debug, troubleshoot, or diagnose issues.
3
+ ---
4
+ # Debugging
5
+
6
+ ## reproduce
7
+ First, reproduce the bug consistently:
8
+ - Get exact steps to trigger the issue
9
+ - Note the environment (OS, versions, config)
10
+ - Determine if it's deterministic or intermittent
11
+ - Find the minimal reproduction case
12
+
13
+ If you can't reproduce it, you can't verify a fix.
14
+
15
+ ## isolate
16
+ Narrow down the cause:
17
+ - Binary search through the codebase (git bisect)
18
+ - Comment out / disable components to isolate
19
+ - Check recent changes (git log, blame)
20
+ - Add targeted logging at boundaries
21
+ - Test with minimal input/config
22
+
23
+ ## diagnose
24
+ Once isolated, understand the root cause:
25
+ - Read the code path carefully, don't assume
26
+ - Check data flow — what goes in, what comes out?
27
+ - Look for state mutations, race conditions, stale caches
28
+ - Check external dependencies (API changes, schema drift)
29
+ - Verify assumptions with print/log/debugger
30
+
31
+ ## fix
32
+ Apply the minimal fix:
33
+ - Fix the root cause, not the symptom
34
+ - Keep the change as small as possible
35
+ - Add a test that fails without the fix and passes with it
36
+ - Check for similar patterns elsewhere in the codebase
37
+ - Document WHY the bug happened if it's non-obvious
38
+
39
+ ## verify
40
+ Confirm the fix works:
41
+ - Run the reproduction steps — bug should be gone
42
+ - Run the full test suite — no regressions
43
+ - Test edge cases around the fix
44
+ - Review the fix yourself before submitting
@@ -33,6 +33,8 @@ steps:
33
33
  from typing import List, Dict, Any, Tuple
34
34
  from pathlib import Path
35
35
 
36
+ import requests as _requests
37
+
36
38
  from npcpy.llm_funcs import get_llm_response
37
39
  from npcpy.npc_compiler import NPC
38
40
 
@@ -65,6 +67,7 @@ steps:
65
67
 
66
68
  model = context.get('model') or (npc.model if npc and hasattr(npc, 'model') else None)
67
69
  provider = context.get('provider') or (npc.provider if npc and hasattr(npc, 'provider') else None)
70
+ _alicanto_directive = (npc.primary_directive if npc and hasattr(npc, 'primary_directive') else "") or ""
68
71
 
69
72
  # ========== Utility ==========
70
73
  def get_size():
@@ -164,8 +167,26 @@ steps:
164
167
  except:
165
168
  return "Error listing directory."
166
169
 
167
- def execute_shell_command(command: str) -> str:
168
- """Execute a shell command and return stdout/stderr."""
170
+ def run_python(code: str) -> str:
171
+ """Execute Python code and return the output. This is your PRIMARY tool for data analysis, file processing, API calls, computations, and any programmatic work. Use this for: downloading data, parsing files, running analyses, making HTTP requests, processing CSVs/FITS/JSON, plotting, statistics, etc. The code runs in a fresh namespace with access to standard library and installed packages (numpy, pandas, astropy, requests, matplotlib, scipy, etc.)."""
172
+ import io as _io
173
+ _old_stdout = sys.stdout
174
+ _old_stderr = sys.stderr
175
+ _capture = _io.StringIO()
176
+ sys.stdout = _capture
177
+ sys.stderr = _capture
178
+ _ns = {'__builtins__': __builtins__}
179
+ try:
180
+ exec(code, _ns)
181
+ except Exception as _e:
182
+ print(f"Error: {type(_e).__name__}: {_e}")
183
+ finally:
184
+ sys.stdout = _old_stdout
185
+ sys.stderr = _old_stderr
186
+ return _capture.getvalue()[:5000] if _capture.getvalue().strip() else "(no output)"
187
+
188
+ def shell_command(command: str) -> str:
189
+ """Execute a shell command. ONLY use this for simple system tasks like installing packages (pip install), checking disk space, or listing system info. For ALL data work, analysis, file processing, HTTP requests, and computation, use run_python instead."""
169
190
  try:
170
191
  result = subprocess.run(command, shell=True, capture_output=True, text=True, timeout=60)
171
192
  out = ""
@@ -179,12 +200,14 @@ steps:
179
200
  except Exception as e:
180
201
  return f"Error: {e}"
181
202
 
203
+ _search_provider = os.environ.get('NPCSH_SEARCH_PROVIDER', 'perplexity')
204
+
182
205
  def _web_search_tool(query: str) -> str:
183
206
  """Search the web for information."""
184
207
  if not WEB_AVAILABLE:
185
208
  return "Web search not available."
186
209
  try:
187
- results = search_web(query, num_results=5)
210
+ results = search_web(query, num_results=5, provider=_search_provider)
188
211
  if not results:
189
212
  return "No results found."
190
213
  if isinstance(results, list):
@@ -199,6 +222,61 @@ steps:
199
222
  except Exception as e:
200
223
  return f"Search error: {e}"
201
224
 
225
+ _s2_api_key = os.environ.get('S2_API_KEY', '')
226
+
227
+ def search_papers(query: str, limit: int = 10) -> str:
228
+ """Search Semantic Scholar for academic papers. Returns titles, authors, year, citation count, abstracts, and URLs."""
229
+ s2_url = "https://api.semanticscholar.org/graph/v1/paper/search"
230
+ params = {
231
+ "query": query,
232
+ "limit": min(limit, 20),
233
+ "fields": "title,abstract,authors,year,citationCount,url,tldr,venue"
234
+ }
235
+ try:
236
+ # Try with API key first if available
237
+ if _s2_api_key:
238
+ resp = _requests.get(s2_url, headers={"x-api-key": _s2_api_key}, params=params, timeout=30)
239
+ if resp.status_code == 403:
240
+ # Key expired/revoked, fall back to unauthenticated
241
+ resp = _requests.get(s2_url, params=params, timeout=30)
242
+ else:
243
+ resp = _requests.get(s2_url, params=params, timeout=30)
244
+ if resp.status_code == 429:
245
+ # Rate limited, wait and retry once
246
+ time.sleep(1.5)
247
+ resp = _requests.get(s2_url, params=params, timeout=30)
248
+ resp.raise_for_status()
249
+ papers = resp.json().get('data', [])
250
+ if not papers:
251
+ return f"No papers found for: {query}"
252
+ out = []
253
+ for i, p in enumerate(papers, 1):
254
+ title = p.get('title', 'No title')
255
+ year = p.get('year', '?')
256
+ cites = p.get('citationCount', 0)
257
+ authors = ', '.join([a.get('name', '') for a in p.get('authors', [])[:3]])
258
+ if len(p.get('authors', [])) > 3:
259
+ authors += ' et al.'
260
+ tldr = p.get('tldr', {}).get('text', '') if p.get('tldr') else ''
261
+ abstract = (p.get('abstract') or '')[:200]
262
+ paper_url = p.get('url', '')
263
+ venue = p.get('venue', '')
264
+ entry = f"{i}. {title} ({year}) [{cites} citations]"
265
+ entry += f"\n Authors: {authors}"
266
+ if venue:
267
+ entry += f"\n Venue: {venue}"
268
+ if tldr:
269
+ entry += f"\n TL;DR: {tldr}"
270
+ elif abstract:
271
+ entry += f"\n Abstract: {abstract}..."
272
+ entry += f"\n URL: {paper_url}"
273
+ out.append(entry)
274
+ return "\n\n".join(out)
275
+ except _requests.exceptions.RequestException as e:
276
+ return f"Semantic Scholar API error: {e}"
277
+ except Exception as e:
278
+ return f"Paper search error: {e}"
279
+
202
280
  # ========== File Provenance (matching original) ==========
203
281
  @dataclass
204
282
  class FileProvenance:
@@ -362,14 +440,14 @@ steps:
362
440
  except Exception as e:
363
441
  return f"Wander failed: {e}"
364
442
 
365
- tools = [create_file, append_to_file, replace_in_file, read_file,
366
- list_files, execute_shell_command, _web_search_tool, wander_wrapper]
443
+ tools = [run_python, create_file, append_to_file, replace_in_file, read_file,
444
+ list_files, _web_search_tool, search_papers, shell_command, wander_wrapper]
367
445
 
368
446
  agent = NPC(
369
447
  name=agent_name.replace(' ', '_').lower(),
370
448
  model=_model,
371
449
  provider=_provider,
372
- primary_directive=agent_persona,
450
+ primary_directive=_alicanto_directive + "\n\n" + agent_persona,
373
451
  tools=tools
374
452
  )
375
453
 
@@ -379,6 +457,7 @@ steps:
379
457
  created_files = set()
380
458
  summary = {}
381
459
  major_step = 0
460
+ stall_count = 0 # consecutive steps with no filesystem change
382
461
 
383
462
  while major_step < _max_steps:
384
463
  # Check for skip/quit
@@ -401,37 +480,11 @@ steps:
401
480
  history_str = "\n".join(summarized_history)
402
481
  next_step_text = f"This is the next step suggested by your advisor. : BEGIN NEXT_STEP: {summary.get('next_step')} END NEXT STEP" if summary else ""
403
482
 
404
- search_provider = os.environ.get('NPCSH_SEARCH_PROVIDER', 'duckduckgo')
405
- initial_prompt = f"""Test the following hypothesis: '{hypothesis}' as related to the user query: '{user_query}'.
406
- Only focus on your specific hypothesis, other agents are being tasked with other aspects of the problem.
407
-
408
- Use bash commands to carry out research through the execute_shell_command.
409
- Adjust files with `replace_in_file` and use `read_file` and `list_files` to verify file states and file creation.
410
- Create files with create_file()
411
-
412
- Test with execute_shell_command when needed
413
- Get unstuck with wander_wrapper
414
-
415
- When you have a definitive result, say RESEARCH_COMPLETE.
416
-
417
- FILE PROVENANCE HISTORY:
418
- {chr(10).join(provenance_summary)}
419
-
420
- CURRENT FILES: {list(fs_before.keys())}
421
-
422
- COMPLETE ACTION HISTORY:
423
- BEGIN HISTORY
483
+ initial_prompt = f"""Hypothesis: '{hypothesis}'
484
+ Query: '{user_query}'
485
+ Files: {list(fs_before.keys())}
424
486
  {history_str}
425
- END HISTORY
426
-
427
- What specific action will you take next to test your hypothesis?
428
- AVAILABLE TOOLS: create_file, append_to_file, replace_in_file, read_file, list_files, execute_shell_command, wander_wrapper, _web_search_tool.
429
-
430
- Do not repeat actions. Use `_web_search_tool` with provider of {search_provider} to look up items if you are struggling.
431
-
432
- {next_step_text}
433
-
434
- Your goal is to research. To set up experiments, create figures, and produce data outputs in csvs for verification and reproducibility."""
487
+ {next_step_text}"""
435
488
 
436
489
  ui_state['log'].append(f"\033[90m Major step {major_step + 1}\033[0m")
437
490
 
@@ -495,8 +548,16 @@ steps:
495
548
 
496
549
  fs_after = get_filesystem_state()
497
550
  new_files = set(fs_after.keys()) - set(fs_before.keys())
551
+ changed_files = {f for f in fs_after if fs_before.get(f) != fs_after.get(f)}
498
552
  if new_files:
499
553
  ui_state['log'].append(f" \033[32mNew files: {list(new_files)}\033[0m")
554
+ stall_count = 0
555
+ elif changed_files:
556
+ stall_count = 0
557
+ else:
558
+ stall_count += 1
559
+ if stall_count >= 3:
560
+ ui_state['log'].append(f" \033[33mStalled for {stall_count} steps, forcing wrap-up\033[0m")
500
561
 
501
562
  combined_thought = " ".join(all_thoughts)
502
563
  combined_action = " | ".join(filter(None, all_actions))
@@ -619,7 +680,7 @@ steps:
619
680
 
620
681
  Focus ONLY on the {next_section} section. Write 2-4 paragraphs of substantial academic content.
621
682
 
622
- Available tools: replace_in_file, read_file, _web_search_tool"""
683
+ Available tools: replace_in_file, read_file, _web_search_tool, search_papers"""
623
684
 
624
685
  for micro in range(5):
625
686
  if micro == 0:
@@ -743,7 +804,7 @@ steps:
743
804
  Use replace_in_file to make targeted improvements to paper.tex.
744
805
  Use read_file to check current state.
745
806
 
746
- Available tools: replace_in_file, read_file, append_to_file, _web_search_tool"""
807
+ Available tools: replace_in_file, read_file, append_to_file, _web_search_tool, search_papers"""
747
808
 
748
809
  coord_messages = []
749
810
  for micro in range(8):
@@ -965,13 +1026,13 @@ steps:
965
1026
  except Exception as e:
966
1027
  return f"Wander failed: {e}"
967
1028
 
968
- coord_tools = [create_file, append_to_file, replace_in_file, read_file,
969
- list_files, execute_shell_command, _web_search_tool, wander_wrapper_coord]
1029
+ coord_tools = [run_python, create_file, append_to_file, replace_in_file, read_file,
1030
+ list_files, _web_search_tool, search_papers, shell_command, wander_wrapper_coord]
970
1031
 
971
1032
  coordinator = NPC(
972
1033
  name="Alicanto",
973
1034
  model=model, provider=provider,
974
- primary_directive="You are Alicanto the mythical bird. You research topics iteratively by writing to LaTeX files and searching for more information.",
1035
+ primary_directive=_alicanto_directive,
975
1036
  tools=coord_tools
976
1037
  )
977
1038
 
@@ -11,13 +11,15 @@ 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, the deep research specialist. You produce thorough research reports.
15
+ Search multiple sources, read papers, gather evidence, then synthesize into a report.
16
+ Use web_search and file_search to find sources. Use python to analyze data.
17
+ Say RESEARCH_COMPLETE when you have enough evidence to answer.
18
18
  jinxs:
19
- - lib/core/search
19
+ - lib/core/search/web_search
20
+ - lib/core/search/file_search
21
+ - lib/core/search/db_search
20
22
  - lib/core/sh
21
23
  - lib/core/python
22
24
  - lib/core/load_file
23
- - lib/research/*
25
+ - lib/core/edit_file