npcsh 1.1.16__py3-none-any.whl → 1.1.17__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 (176) hide show
  1. npcsh/_state.py +24 -9
  2. npcsh/benchmark/__init__.py +22 -0
  3. npcsh/benchmark/npcsh_agent.py +262 -0
  4. npcsh/benchmark/runner.py +569 -0
  5. npcsh/npc_team/jinxs/bin/benchmark.jinx +146 -0
  6. npcsh/npc_team/jinxs/bin/nql.jinx +7 -7
  7. npcsh/npc_team/jinxs/bin/roll.jinx +20 -23
  8. npcsh/npc_team/jinxs/bin/sample.jinx +6 -7
  9. npcsh/npc_team/jinxs/bin/spool.jinx +4 -4
  10. npcsh/npc_team/jinxs/bin/sync.jinx +6 -6
  11. npcsh/npc_team/jinxs/bin/vixynt.jinx +8 -8
  12. npcsh/npc_team/jinxs/bin/wander.jinx +109 -19
  13. npcsh/npc_team/jinxs/bin/yap.jinx +5 -5
  14. npcsh/npc_team/jinxs/incognide/add_tab.jinx +11 -0
  15. npcsh/npc_team/jinxs/incognide/close_pane.jinx +9 -0
  16. npcsh/npc_team/jinxs/incognide/close_tab.jinx +10 -0
  17. npcsh/npc_team/jinxs/incognide/confirm.jinx +10 -0
  18. npcsh/npc_team/jinxs/incognide/focus_pane.jinx +9 -0
  19. npcsh/npc_team/jinxs/{npc_studio/npc-studio.jinx → incognide/incognide.jinx} +2 -2
  20. npcsh/npc_team/jinxs/incognide/list_panes.jinx +8 -0
  21. npcsh/npc_team/jinxs/incognide/navigate.jinx +10 -0
  22. npcsh/npc_team/jinxs/incognide/notify.jinx +10 -0
  23. npcsh/npc_team/jinxs/incognide/open_pane.jinx +13 -0
  24. npcsh/npc_team/jinxs/incognide/read_pane.jinx +9 -0
  25. npcsh/npc_team/jinxs/incognide/run_terminal.jinx +10 -0
  26. npcsh/npc_team/jinxs/incognide/send_message.jinx +10 -0
  27. npcsh/npc_team/jinxs/incognide/split_pane.jinx +12 -0
  28. npcsh/npc_team/jinxs/incognide/switch_npc.jinx +10 -0
  29. npcsh/npc_team/jinxs/incognide/switch_tab.jinx +10 -0
  30. npcsh/npc_team/jinxs/incognide/write_file.jinx +11 -0
  31. npcsh/npc_team/jinxs/incognide/zen_mode.jinx +9 -0
  32. npcsh/npc_team/jinxs/lib/browser/browser_action.jinx +4 -4
  33. npcsh/npc_team/jinxs/lib/browser/browser_screenshot.jinx +1 -1
  34. npcsh/npc_team/jinxs/lib/browser/open_browser.jinx +2 -2
  35. npcsh/npc_team/jinxs/lib/computer_use/click.jinx +2 -2
  36. npcsh/npc_team/jinxs/lib/computer_use/key_press.jinx +1 -1
  37. npcsh/npc_team/jinxs/lib/computer_use/launch_app.jinx +1 -1
  38. npcsh/npc_team/jinxs/lib/computer_use/screenshot.jinx +1 -1
  39. npcsh/npc_team/jinxs/lib/computer_use/trigger.jinx +2 -2
  40. npcsh/npc_team/jinxs/lib/computer_use/type_text.jinx +1 -1
  41. npcsh/npc_team/jinxs/lib/computer_use/wait.jinx +1 -1
  42. npcsh/npc_team/jinxs/lib/core/chat.jinx +4 -4
  43. npcsh/npc_team/jinxs/lib/core/cmd.jinx +4 -4
  44. npcsh/npc_team/jinxs/lib/core/compress.jinx +8 -8
  45. npcsh/npc_team/jinxs/lib/core/edit_file.jinx +3 -0
  46. npcsh/npc_team/jinxs/lib/core/ots.jinx +7 -7
  47. npcsh/npc_team/jinxs/lib/core/search/db_search.jinx +44 -0
  48. npcsh/npc_team/jinxs/lib/core/search/file_search.jinx +94 -0
  49. npcsh/npc_team/jinxs/lib/core/search/kg_search.jinx +96 -0
  50. npcsh/npc_team/jinxs/lib/core/search/mem_search.jinx +80 -0
  51. npcsh/npc_team/jinxs/lib/core/search/web_search.jinx +51 -0
  52. npcsh/npc_team/jinxs/lib/core/search.jinx +52 -129
  53. npcsh/npc_team/jinxs/lib/core/sh.jinx +1 -1
  54. npcsh/npc_team/jinxs/lib/core/sleep.jinx +7 -7
  55. npcsh/npc_team/jinxs/lib/core/sql.jinx +7 -7
  56. npcsh/npc_team/jinxs/lib/orchestration/convene.jinx +7 -7
  57. npcsh/npc_team/jinxs/lib/orchestration/delegate.jinx +8 -9
  58. npcsh/npc_team/jinxs/lib/research/arxiv.jinx +2 -2
  59. npcsh/npc_team/jinxs/lib/research/paper_search.jinx +3 -3
  60. npcsh/npc_team/jinxs/lib/research/semantic_scholar.jinx +2 -2
  61. npcsh/npc_team/jinxs/lib/utils/build.jinx +5 -5
  62. npcsh/npc_team/jinxs/lib/utils/compile.jinx +2 -2
  63. npcsh/npc_team/jinxs/lib/utils/help.jinx +1 -1
  64. npcsh/npc_team/jinxs/lib/utils/init.jinx +5 -5
  65. npcsh/npc_team/jinxs/lib/utils/jinxs.jinx +1 -1
  66. npcsh/npc_team/jinxs/lib/utils/serve.jinx +2 -2
  67. npcsh/npc_team/jinxs/lib/utils/set.jinx +2 -2
  68. npcsh/npc_team/jinxs/lib/utils/switch.jinx +3 -3
  69. npcsh/npc_team/jinxs/lib/utils/switches.jinx +1 -1
  70. npcsh/npc_team/jinxs/lib/utils/teamviz.jinx +2 -2
  71. npcsh/npc_team/sibiji.npc +1 -1
  72. npcsh/npcsh.py +81 -43
  73. npcsh-1.1.17.data/data/npcsh/npc_team/add_tab.jinx +11 -0
  74. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/arxiv.jinx +2 -2
  75. npcsh-1.1.17.data/data/npcsh/npc_team/benchmark.jinx +146 -0
  76. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/browser_action.jinx +4 -4
  77. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/browser_screenshot.jinx +1 -1
  78. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/build.jinx +5 -5
  79. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/chat.jinx +4 -4
  80. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/click.jinx +2 -2
  81. npcsh-1.1.17.data/data/npcsh/npc_team/close_pane.jinx +9 -0
  82. npcsh-1.1.17.data/data/npcsh/npc_team/close_tab.jinx +10 -0
  83. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/cmd.jinx +4 -4
  84. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/compile.jinx +2 -2
  85. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/compress.jinx +8 -8
  86. npcsh-1.1.17.data/data/npcsh/npc_team/confirm.jinx +10 -0
  87. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/convene.jinx +7 -7
  88. npcsh-1.1.17.data/data/npcsh/npc_team/db_search.jinx +44 -0
  89. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/delegate.jinx +8 -9
  90. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/edit_file.jinx +3 -0
  91. npcsh-1.1.17.data/data/npcsh/npc_team/file_search.jinx +94 -0
  92. npcsh-1.1.17.data/data/npcsh/npc_team/focus_pane.jinx +9 -0
  93. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/help.jinx +1 -1
  94. npcsh-1.1.16.data/data/npcsh/npc_team/npc-studio.jinx → npcsh-1.1.17.data/data/npcsh/npc_team/incognide.jinx +2 -2
  95. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/init.jinx +5 -5
  96. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/jinxs.jinx +1 -1
  97. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/key_press.jinx +1 -1
  98. npcsh-1.1.17.data/data/npcsh/npc_team/kg_search.jinx +96 -0
  99. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/launch_app.jinx +1 -1
  100. npcsh-1.1.17.data/data/npcsh/npc_team/list_panes.jinx +8 -0
  101. npcsh-1.1.17.data/data/npcsh/npc_team/mem_search.jinx +80 -0
  102. npcsh-1.1.17.data/data/npcsh/npc_team/navigate.jinx +10 -0
  103. npcsh-1.1.17.data/data/npcsh/npc_team/notify.jinx +10 -0
  104. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/nql.jinx +7 -7
  105. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/open_browser.jinx +2 -2
  106. npcsh-1.1.17.data/data/npcsh/npc_team/open_pane.jinx +13 -0
  107. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/ots.jinx +7 -7
  108. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/paper_search.jinx +3 -3
  109. npcsh-1.1.17.data/data/npcsh/npc_team/read_pane.jinx +9 -0
  110. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/roll.jinx +20 -23
  111. npcsh-1.1.17.data/data/npcsh/npc_team/run_terminal.jinx +10 -0
  112. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/sample.jinx +6 -7
  113. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/screenshot.jinx +1 -1
  114. npcsh-1.1.17.data/data/npcsh/npc_team/search.jinx +54 -0
  115. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/semantic_scholar.jinx +2 -2
  116. npcsh-1.1.17.data/data/npcsh/npc_team/send_message.jinx +10 -0
  117. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/serve.jinx +2 -2
  118. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/set.jinx +2 -2
  119. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/sh.jinx +1 -1
  120. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/sibiji.npc +1 -1
  121. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/sleep.jinx +7 -7
  122. npcsh-1.1.17.data/data/npcsh/npc_team/split_pane.jinx +12 -0
  123. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/spool.jinx +4 -4
  124. npcsh-1.1.17.data/data/npcsh/npc_team/sql.jinx +16 -0
  125. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/switch.jinx +3 -3
  126. npcsh-1.1.17.data/data/npcsh/npc_team/switch_npc.jinx +10 -0
  127. npcsh-1.1.17.data/data/npcsh/npc_team/switch_tab.jinx +10 -0
  128. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/switches.jinx +1 -1
  129. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/sync.jinx +6 -6
  130. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/teamviz.jinx +2 -2
  131. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/trigger.jinx +2 -2
  132. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/type_text.jinx +1 -1
  133. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/vixynt.jinx +8 -8
  134. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/wait.jinx +1 -1
  135. npcsh-1.1.17.data/data/npcsh/npc_team/wander.jinx +242 -0
  136. npcsh-1.1.17.data/data/npcsh/npc_team/web_search.jinx +51 -0
  137. npcsh-1.1.17.data/data/npcsh/npc_team/write_file.jinx +11 -0
  138. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/yap.jinx +5 -5
  139. npcsh-1.1.17.data/data/npcsh/npc_team/zen_mode.jinx +9 -0
  140. {npcsh-1.1.16.dist-info → npcsh-1.1.17.dist-info}/METADATA +10 -7
  141. npcsh-1.1.17.dist-info/RECORD +219 -0
  142. {npcsh-1.1.16.dist-info → npcsh-1.1.17.dist-info}/entry_points.txt +2 -0
  143. npcsh-1.1.16.data/data/npcsh/npc_team/search.jinx +0 -131
  144. npcsh-1.1.16.data/data/npcsh/npc_team/sql.jinx +0 -16
  145. npcsh-1.1.16.data/data/npcsh/npc_team/wander.jinx +0 -152
  146. npcsh-1.1.16.dist-info/RECORD +0 -170
  147. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/alicanto.npc +0 -0
  148. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/alicanto.png +0 -0
  149. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/close_browser.jinx +0 -0
  150. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/corca.npc +0 -0
  151. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/corca.png +0 -0
  152. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/corca_example.png +0 -0
  153. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/frederic.npc +0 -0
  154. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/frederic4.png +0 -0
  155. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/guac.npc +0 -0
  156. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/guac.png +0 -0
  157. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/kadiefa.npc +0 -0
  158. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/kadiefa.png +0 -0
  159. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/load_file.jinx +0 -0
  160. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/npcsh.ctx +0 -0
  161. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/npcsh_sibiji.png +0 -0
  162. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/paste.jinx +0 -0
  163. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/plonk.npc +0 -0
  164. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/plonk.png +0 -0
  165. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/plonkjr.npc +0 -0
  166. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/plonkjr.png +0 -0
  167. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/python.jinx +0 -0
  168. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/shh.jinx +0 -0
  169. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/sibiji.png +0 -0
  170. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/spool.png +0 -0
  171. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/usage.jinx +0 -0
  172. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/verbose.jinx +0 -0
  173. {npcsh-1.1.16.data → npcsh-1.1.17.data}/data/npcsh/npc_team/yap.png +0 -0
  174. {npcsh-1.1.16.dist-info → npcsh-1.1.17.dist-info}/WHEEL +0 -0
  175. {npcsh-1.1.16.dist-info → npcsh-1.1.17.dist-info}/licenses/LICENSE +0 -0
  176. {npcsh-1.1.16.dist-info → npcsh-1.1.17.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,94 @@
1
+ jinx_name: file_search
2
+ description: Search file contents using RAG (Retrieval Augmented Generation)
3
+ inputs:
4
+ - query: ""
5
+ - file_paths: ""
6
+ - emodel: ""
7
+ - eprovider: ""
8
+ - vector_db_path: ""
9
+ - recursive: "false"
10
+
11
+ steps:
12
+ - name: search_files
13
+ engine: python
14
+ code: |
15
+ import os
16
+ import glob as globmod
17
+
18
+ query = context.get('query', '').strip()
19
+ file_paths_str = context.get('file_paths', '').strip()
20
+
21
+ if not query or not file_paths_str:
22
+ lines = [
23
+ "Usage: /file_search <query> file_paths=<path1,path2,...>",
24
+ "",
25
+ "Options:",
26
+ " file_paths - Comma-separated file paths or glob patterns (required)",
27
+ " emodel - Embedding model",
28
+ " eprovider - Embedding provider",
29
+ " vector_db_path - Path to vector database",
30
+ " recursive - Use recursive glob for patterns (default false)",
31
+ "",
32
+ "Examples:",
33
+ " /file_search how does auth work file_paths=src/*.py",
34
+ " /file_search database schema file_paths=docs/,README.md",
35
+ ]
36
+ context['output'] = "\n".join(lines)
37
+ else:
38
+ recursive = context.get('recursive', 'false').lower() == 'true'
39
+ emodel = context.get('emodel') or None
40
+ eprovider = context.get('eprovider') or None
41
+ try:
42
+ emodel = emodel or (state.embedding_model if 'state' in dir() and state else None)
43
+ eprovider = eprovider or (state.embedding_provider if 'state' in dir() and state else None)
44
+ except:
45
+ pass
46
+ vector_db_path = context.get('vector_db_path') or os.path.expanduser("~/.npcsh/npcsh_chroma.db")
47
+
48
+ try:
49
+ resolved_paths = []
50
+ for path_spec in file_paths_str.split(','):
51
+ path_spec = path_spec.strip()
52
+ if not path_spec:
53
+ continue
54
+ expanded = os.path.expanduser(path_spec)
55
+ if '*' in expanded or '?' in expanded:
56
+ if recursive:
57
+ matches = globmod.glob(expanded, recursive=True)
58
+ else:
59
+ matches = globmod.glob(expanded)
60
+ resolved_paths.extend(matches)
61
+ else:
62
+ resolved_paths.append(os.path.abspath(expanded))
63
+
64
+ file_contents = []
65
+ loaded_files = []
66
+ for path in resolved_paths:
67
+ if os.path.isfile(path):
68
+ chunks = load_file_contents(path)
69
+ basename = os.path.basename(path)
70
+ file_contents.extend([basename + ": " + chunk for chunk in chunks])
71
+ loaded_files.append(basename)
72
+ elif os.path.isdir(path):
73
+ for root, dirs, files in os.walk(path):
74
+ for f in files:
75
+ fpath = os.path.join(root, f)
76
+ chunks = load_file_contents(fpath)
77
+ file_contents.extend([f + ": " + chunk for chunk in chunks])
78
+ loaded_files.append(f)
79
+
80
+ if not file_contents:
81
+ context['output'] = "No files found or loaded from: " + file_paths_str
82
+ else:
83
+ result = execute_rag_command(
84
+ command=query,
85
+ vector_db_path=vector_db_path,
86
+ embedding_model=emodel,
87
+ embedding_provider=eprovider,
88
+ file_contents=file_contents
89
+ )
90
+ response = result.get('response', 'No RAG response.')
91
+ context['output'] = "Searched " + str(len(loaded_files)) + " files:\n\n" + response
92
+ except Exception as e:
93
+ import traceback
94
+ context['output'] = "File search error: " + str(e) + "\n" + traceback.format_exc()
@@ -0,0 +1,9 @@
1
+ jinx_name: studio.focus_pane
2
+ description: Focus/activate a specific pane in NPC Studio.
3
+ inputs:
4
+ - paneId: ""
5
+ steps:
6
+ - name: frontend_action
7
+ engine: python
8
+ code: |
9
+ context['output'] = "Action executed by frontend"
@@ -1,7 +1,7 @@
1
1
  jinx_name: help
2
2
  description: Show help for commands, NPCs, or Jinxs
3
3
  inputs:
4
- - topic: null
4
+ - topic: null
5
5
  steps:
6
6
  - name: show_help
7
7
  engine: python
@@ -1,7 +1,7 @@
1
- jinx_name: "npc-studio"
1
+ jinx_name: "incognide"
2
2
  description: "Start npc studio"
3
3
  inputs:
4
- - user_command: ""
4
+ - user_command: ""
5
5
  steps:
6
6
  - name: "launch_npc_studio"
7
7
  engine: "python"
@@ -1,11 +1,11 @@
1
1
  jinx_name: "init"
2
2
  description: "Initialize NPC project"
3
3
  inputs:
4
- - directory: "." # The directory where the NPC project should be initialized.
5
- - templates: "" # Optional templates to use for initialization.
6
- - context: "" # Optional context for project initialization.
7
- - model: "" # Optional LLM model to set as default for the project.
8
- - provider: "" # Optional LLM provider to set as default for the project.
4
+ - directory: "."
5
+ - templates: ""
6
+ - context: ""
7
+ - model: ""
8
+ - provider: ""
9
9
  steps:
10
10
  - name: "initialize_project"
11
11
  engine: "python"
@@ -1,7 +1,7 @@
1
1
  jinx_name: jinxs
2
2
  description: "Show available jinxs organized by folder. Use /jinxs <path> for details on a specific folder."
3
3
  inputs:
4
- - path: "" # Optional path to show details for (e.g., "lib/core", "bin")
4
+ - path: ""
5
5
  steps:
6
6
  - name: list_jinxs
7
7
  engine: python
@@ -6,7 +6,7 @@ description: |
6
6
  For combinations use + like: ctrl+a, ctrl+c, ctrl+v, alt+tab, ctrl+shift+t
7
7
  For regular letters/numbers, use type_text instead.
8
8
  inputs:
9
- - key: "enter"
9
+ - key: "enter"
10
10
 
11
11
  steps:
12
12
  - name: perform_key
@@ -0,0 +1,96 @@
1
+ jinx_name: kg_search
2
+ description: Search the knowledge graph for facts and concepts
3
+ inputs:
4
+ - query: ""
5
+ - type: "facts"
6
+ - concept: ""
7
+ - npc_name: ""
8
+ - team_name: ""
9
+ - db_path: ""
10
+
11
+ steps:
12
+ - name: search_kg
13
+ engine: python
14
+ code: |
15
+ import os
16
+ from npcpy.memory.knowledge_graph import kg_search_facts, kg_list_concepts, kg_get_facts_for_concept, kg_get_all_facts
17
+
18
+ query = context.get('query', '').strip()
19
+ search_type = context.get('type', 'facts').lower()
20
+ concept = context.get('concept', '').strip()
21
+
22
+ if not query and search_type == 'facts' and not concept:
23
+ lines = [
24
+ "Usage: /kg_search <query> [type=facts|concepts|all]",
25
+ "",
26
+ "Options:",
27
+ " type - Search type (facts, concepts, all). Default is facts",
28
+ " concept - Get facts for a specific concept",
29
+ " npc_name - Filter by NPC name",
30
+ " team_name - Filter by team name",
31
+ " db_path - Path to history database",
32
+ "",
33
+ "Examples:",
34
+ " /kg_search python",
35
+ " /kg_search type=concepts",
36
+ " /kg_search concept=coding",
37
+ " /kg_search type=all",
38
+ ]
39
+ context['output'] = "\n".join(lines)
40
+ else:
41
+ db_path = context.get('db_path') or os.path.expanduser("~/.npcsh/npcsh_history.db")
42
+
43
+ try:
44
+ cmd_history = CommandHistory(db_path)
45
+ engine = cmd_history.engine
46
+
47
+ team_obj = None
48
+ try:
49
+ team_obj = state.team if 'state' in dir() and state else None
50
+ except:
51
+ pass
52
+ npc_obj = npc if 'npc' in dir() else None
53
+
54
+ if concept:
55
+ facts = kg_get_facts_for_concept(engine, concept, npc=npc_obj, team=team_obj)
56
+ if not facts:
57
+ context['output'] = "No facts found for concept '" + concept + "'"
58
+ else:
59
+ lines = ["Facts for concept '" + concept + "':", ""]
60
+ for i, fact in enumerate(facts, 1):
61
+ lines.append(str(i) + ". " + str(fact))
62
+ context['output'] = "\n".join(lines)
63
+
64
+ elif search_type == 'concepts':
65
+ concepts = kg_list_concepts(engine, npc=npc_obj, team=team_obj)
66
+ if not concepts:
67
+ context['output'] = "No concepts found in knowledge graph."
68
+ else:
69
+ lines = ["Found " + str(len(concepts)) + " concepts:", ""]
70
+ for i, c in enumerate(concepts, 1):
71
+ lines.append(str(i) + ". " + str(c))
72
+ context['output'] = "\n".join(lines)
73
+
74
+ elif search_type == 'all':
75
+ facts = kg_get_all_facts(engine, npc=npc_obj, team=team_obj)
76
+ if not facts:
77
+ context['output'] = "No facts in knowledge graph."
78
+ else:
79
+ lines = ["All facts (" + str(len(facts)) + " total):", ""]
80
+ for i, fact in enumerate(facts, 1):
81
+ lines.append(str(i) + ". " + str(fact))
82
+ context['output'] = "\n".join(lines)
83
+
84
+ else:
85
+ facts = kg_search_facts(engine, query, npc=npc_obj, team=team_obj)
86
+ if not facts:
87
+ context['output'] = "No KG facts found for '" + query + "'"
88
+ else:
89
+ lines = ["Found " + str(len(facts)) + " facts:", ""]
90
+ for i, fact in enumerate(facts, 1):
91
+ lines.append(str(i) + ". " + str(fact))
92
+ context['output'] = "\n".join(lines)
93
+
94
+ except Exception as e:
95
+ import traceback
96
+ context['output'] = "KG search error: " + str(e) + "\n" + traceback.format_exc()
@@ -1,7 +1,7 @@
1
1
  jinx_name: launch_app
2
2
  description: Launch an application on the system
3
3
  inputs:
4
- - command: "" # Command to launch (e.g., "open -a Firefox" on macOS)
4
+ - command: ""
5
5
 
6
6
  steps:
7
7
  - name: perform_launch
@@ -0,0 +1,8 @@
1
+ jinx_name: studio.list_panes
2
+ description: List all open panes in NPC Studio. Returns pane IDs, types, titles, and which is active.
3
+ inputs: []
4
+ steps:
5
+ - name: frontend_action
6
+ engine: python
7
+ code: |
8
+ context['output'] = "Action executed by frontend"
@@ -0,0 +1,80 @@
1
+ jinx_name: mem_search
2
+ description: Search memories (approved, pending, or all)
3
+ inputs:
4
+ - query: ""
5
+ - status: "all"
6
+ - npc_name: ""
7
+ - team_name: ""
8
+ - max_results: "10"
9
+ - db_path: ""
10
+
11
+ steps:
12
+ - name: search_memories
13
+ engine: python
14
+ code: |
15
+ import os
16
+
17
+ query = context.get('query', '').strip()
18
+ if not query:
19
+ lines = [
20
+ "Usage: /mem_search <query> [status=all|approved|pending]",
21
+ "",
22
+ "Options:",
23
+ " status - Filter by status (all, approved, pending). Default is all",
24
+ " npc_name - Filter by NPC name",
25
+ " team_name - Filter by team name",
26
+ " max_results - Max results to return (default 10)",
27
+ " db_path - Path to history database",
28
+ ]
29
+ context['output'] = "\n".join(lines)
30
+ else:
31
+ status_filter = context.get('status', 'all').lower()
32
+ npc_name = context.get('npc_name') or (npc.name if npc else None)
33
+ team_name = context.get('team_name') or None
34
+ try:
35
+ team_name = team_name or (state.team.name if 'state' in dir() and state and state.team else None)
36
+ except:
37
+ pass
38
+ max_results = int(context.get('max_results') or 10)
39
+ db_path = context.get('db_path') or os.path.expanduser("~/.npcsh/npcsh_history.db")
40
+ current_path = os.getcwd()
41
+
42
+ try:
43
+ cmd_history = CommandHistory(db_path)
44
+
45
+ if status_filter == 'approved':
46
+ state_obj = state if 'state' in dir() else None
47
+ memories = get_relevant_memories(
48
+ command_history=cmd_history,
49
+ npc_name=npc_name or '__none__',
50
+ team_name=team_name or '__none__',
51
+ path=current_path,
52
+ query=query,
53
+ max_memories=max_results,
54
+ state=state_obj
55
+ )
56
+ else:
57
+ memories = cmd_history.search_memories(
58
+ query=query,
59
+ npc_name=npc_name,
60
+ team_name=team_name,
61
+ status=status_filter if status_filter != 'all' else None,
62
+ limit=max_results
63
+ )
64
+
65
+ if not memories:
66
+ context['output'] = "No memories found for '" + query + "' (status=" + status_filter + ")"
67
+ else:
68
+ lines = ["Found " + str(len(memories)) + " memories (status=" + status_filter + "):", ""]
69
+ for i, mem in enumerate(memories, 1):
70
+ if isinstance(mem, dict):
71
+ ts = mem.get('timestamp', 'unknown')
72
+ content = mem.get('final_memory') or mem.get('initial_memory') or mem.get('content', '')
73
+ status = mem.get('status', '')
74
+ lines.append(str(i) + ". [" + str(ts) + "] (" + status + ") " + str(content))
75
+ else:
76
+ lines.append(str(i) + ". " + str(mem))
77
+ context['output'] = "\n".join(lines)
78
+ except Exception as e:
79
+ import traceback
80
+ context['output'] = "Memory search error: " + str(e) + "\n" + traceback.format_exc()
@@ -0,0 +1,10 @@
1
+ jinx_name: studio.navigate
2
+ description: Navigate a browser pane to a specific URL.
3
+ inputs:
4
+ - paneId: "active"
5
+ - url: ""
6
+ steps:
7
+ - name: frontend_action
8
+ engine: python
9
+ code: |
10
+ context['output'] = "Action executed by frontend"
@@ -0,0 +1,10 @@
1
+ jinx_name: studio.notify
2
+ description: Show a notification toast in NPC Studio.
3
+ inputs:
4
+ - message: ""
5
+ - type: "info"
6
+ steps:
7
+ - name: frontend_action
8
+ engine: python
9
+ code: |
10
+ context['output'] = "Action executed by frontend"
@@ -1,13 +1,13 @@
1
1
  jinx_name: nql
2
2
  description: "Run NPC-SQL models with AI-powered transformations. Supports cron scheduling."
3
3
  inputs:
4
- - models_dir: "~/.npcsh/npc_team/models"
5
- - db: "~/npcsh_history.db"
6
- - model: ""
7
- - schema: ""
8
- - show: ""
9
- - cron: ""
10
- - install_cron: ""
4
+ - models_dir: "~/.npcsh/npc_team/models"
5
+ - db: "~/npcsh_history.db"
6
+ - model: ""
7
+ - schema: ""
8
+ - show: ""
9
+ - cron: ""
10
+ - install_cron: ""
11
11
 
12
12
  steps:
13
13
  - name: run_nql
@@ -3,9 +3,9 @@ description: |
3
3
  Open a browser and navigate to a URL. The browser stays open for follow-up commands.
4
4
  Use this to start browser automation.
5
5
  inputs:
6
- - url:
6
+ - url:
7
7
  description: "URL to navigate to"
8
- - browser: "firefox"
8
+ - browser: "firefox"
9
9
 
10
10
  steps:
11
11
  - name: open_browser
@@ -0,0 +1,13 @@
1
+ jinx_name: studio.open_pane
2
+ description: Open a new pane in NPC Studio. Supports editor, terminal, browser, pdf, csv, chat, image, folder, and other content types.
3
+ inputs:
4
+ - type: ""
5
+ - path: ""
6
+ - position: "right"
7
+ steps:
8
+ - name: frontend_action
9
+ engine: python
10
+ code: |
11
+ # This action is executed by the NPC Studio frontend
12
+ # The frontend intercepts studio.* tool calls and handles them directly
13
+ context['output'] = "Action executed by frontend"
@@ -1,10 +1,10 @@
1
1
  jinx_name: "ots"
2
2
  description: "Take screenshot and analyze with vision model. Usage: /ots <prompt>"
3
3
  inputs:
4
- - prompt
5
- - image_paths_args: ""
6
- - vmodel: ""
7
- - vprovider: ""
4
+ - prompt
5
+ - image_paths_args: ""
6
+ - vmodel: ""
7
+ - vprovider: ""
8
8
  steps:
9
9
  - name: "analyze_screenshot_or_image"
10
10
  engine: "python"
@@ -38,10 +38,10 @@ steps:
38
38
  print(f"📸 Screenshot captured: {screenshot_info.get('filename', os.path.basename(screenshot_info['file_path']))}")
39
39
 
40
40
  if not vision_model:
41
- vision_model = getattr(current_npc, 'model', 'gemma3:4b')
42
-
41
+ vision_model = getattr(current_npc, 'model', None) or (state.vision_model if state else 'llama3.2')
42
+
43
43
  if not vision_provider:
44
- vision_provider = getattr(current_npc, 'provider', 'ollama')
44
+ vision_provider = getattr(current_npc, 'provider', None) or (state.vision_provider if state else 'ollama')
45
45
 
46
46
  response_data = get_llm_response(
47
47
  prompt=user_prompt,
@@ -1,9 +1,9 @@
1
1
  jinx_name: paper_search
2
2
  description: Search for academic papers across multiple sources (Semantic Scholar, arXiv, local datasets)
3
3
  inputs:
4
- - query: ""
5
- - limit: 10
6
- - source: "all"
4
+ - query: ""
5
+ - limit: 10
6
+ - source: "all"
7
7
  steps:
8
8
  - name: search_papers
9
9
  engine: python
@@ -0,0 +1,9 @@
1
+ jinx_name: studio.read_pane
2
+ description: Read the contents of a pane. For editor panes returns file content, for chat panes returns messages, for browser panes returns URL/title.
3
+ inputs:
4
+ - paneId: "active"
5
+ steps:
6
+ - name: frontend_action
7
+ engine: python
8
+ code: |
9
+ context['output'] = "Action executed by frontend"
@@ -1,47 +1,44 @@
1
1
  jinx_name: "roll"
2
2
  description: "Generate a video from a text prompt."
3
3
  inputs:
4
- - prompt: "" # Required text prompt for video generation.
5
- - vgmodel: "" # Video generation model to use. Defaults to NPCSH_VIDEO_GEN_MODEL or NPC's model.
6
- - vgprovider: "" # Video generation provider to use. Defaults to NPCSH_VIDEO_GEN_PROVIDER or NPC's provider.
7
- - num_frames: 125 # Number of frames for the video.
8
- - width: 256 # Width of the video.
9
- - height: 256 # Height of the video.
10
- - output_path: "output.mp4" # Output file path for the video.
4
+ - prompt: ""
5
+ - vgmodel: ""
6
+ - vgprovider: ""
7
+ - num_frames: 125
8
+ - width: 256
9
+ - height: 256
10
+ - output_path: "output.mp4"
11
11
  steps:
12
12
  - name: "generate_video"
13
13
  engine: "python"
14
14
  code: |
15
15
  import traceback
16
16
  from npcpy.llm_funcs import gen_video
17
- # Assuming NPCSH_VIDEO_GEN_MODEL and NPCSH_VIDEO_GEN_PROVIDER are accessible
18
-
17
+
19
18
  prompt = context.get('prompt')
20
- num_frames = int(context.get('num_frames', 125)) # Ensure int type
21
- width = int(context.get('width', 256)) # Ensure int type
22
- height = int(context.get('height', 256)) # Ensure int type
19
+ num_frames = int(context.get('num_frames', 125))
20
+ width = int(context.get('width', 256))
21
+ height = int(context.get('height', 256))
23
22
  output_path = context.get('output_path')
24
23
  video_gen_model = context.get('vgmodel')
25
24
  video_gen_provider = context.get('vgprovider')
26
25
  output_messages = context.get('messages', [])
27
26
  current_npc = context.get('npc')
28
-
27
+
29
28
  if not prompt or not prompt.strip():
30
29
  context['output'] = "Usage: /roll <your prompt>"
31
30
  context['messages'] = output_messages
32
31
  exit()
33
32
 
34
- # Fallback for model/provider if not explicitly set in Jinx inputs
35
33
  if not video_gen_model and current_npc and current_npc.model:
36
34
  video_gen_model = current_npc.model
37
35
  if not video_gen_provider and current_npc and current_npc.provider:
38
36
  video_gen_provider = current_npc.provider
39
-
40
- # Final fallbacks (these would ideally come from npcsh._state config)
41
- if not video_gen_model:
42
- video_gen_model = "stable-video-diffusion" # Example default
43
- if not video_gen_provider:
44
- video_gen_provider = "diffusers" # Example default
37
+
38
+ if not video_gen_model:
39
+ video_gen_model = "stable-video-diffusion"
40
+ if not video_gen_provider:
41
+ video_gen_provider = "diffusers"
45
42
 
46
43
  try:
47
44
  result = gen_video(
@@ -53,9 +50,9 @@ steps:
53
50
  width=width,
54
51
  height=height,
55
52
  output_path=output_path,
56
- **context.get('api_kwargs', {}) # Assuming api_kwargs might be passed
53
+ **context.get('api_kwargs', {})
57
54
  )
58
-
55
+
59
56
  if isinstance(result, dict):
60
57
  context['output'] = result.get('output', 'Video generated.')
61
58
  context['messages'] = result.get('messages', output_messages)
@@ -65,4 +62,4 @@ steps:
65
62
  except Exception as e:
66
63
  traceback.print_exc()
67
64
  context['output'] = f"Error generating video: {e}"
68
- context['messages'] = output_messages
65
+ context['messages'] = output_messages
@@ -0,0 +1,10 @@
1
+ jinx_name: studio.run_terminal
2
+ description: Execute a command in a terminal pane.
3
+ inputs:
4
+ - paneId: "active"
5
+ - command: ""
6
+ steps:
7
+ - name: frontend_action
8
+ engine: python
9
+ code: |
10
+ context['output'] = "Action executed by frontend"
@@ -1,9 +1,9 @@
1
1
  jinx_name: "sample"
2
2
  description: "Send a prompt directly to the LLM."
3
3
  inputs:
4
- - prompt: "" # Required text prompt to send to the LLM.
5
- - model: "" # LLM model to use. Defaults to NPC's model.
6
- - provider: "" # LLM provider to use. Defaults to NPC's provider.
4
+ - prompt: ""
5
+ - model: ""
6
+ - provider: ""
7
7
  steps:
8
8
  - name: "send_prompt_to_llm"
9
9
  engine: "python"
@@ -28,9 +28,9 @@ steps:
28
28
  if not llm_provider and current_npc and current_npc.provider:
29
29
  llm_provider = current_npc.provider
30
30
 
31
- # Final fallbacks (these would ideally come from npcsh._state config)
32
- if not llm_model: llm_model = "gemini-1.5-pro" # Example default
33
- if not llm_provider: llm_provider = "gemini" # Example default
31
+ # Final fallbacks from state
32
+ if not llm_model: llm_model = state.chat_model if state else "llama3.2"
33
+ if not llm_provider: llm_provider = state.chat_provider if state else "ollama"
34
34
 
35
35
  try:
36
36
  result = get_llm_response(
@@ -38,7 +38,6 @@ steps:
38
38
  model=llm_model,
39
39
  provider=llm_provider,
40
40
  npc=current_npc,
41
- **{k:v for k,v in context.items() if k not in ['messages', 'prompt', 'model', 'provider']} # Pass other context
42
41
  )
43
42
 
44
43
  if isinstance(result, dict):
@@ -1,7 +1,7 @@
1
1
  jinx_name: screenshot
2
2
  description: Capture a screenshot of the current screen
3
3
  inputs:
4
- - output_path: null # Optional path to save screenshot
4
+ - output_path: null
5
5
 
6
6
  steps:
7
7
  - name: capture_screenshot