npcsh 1.1.20__py3-none-any.whl → 1.1.21__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 (166) hide show
  1. npcsh/_state.py +5 -71
  2. npcsh/diff_viewer.py +3 -3
  3. npcsh/npc_team/jinxs/lib/core/compress.jinx +373 -85
  4. npcsh/npc_team/jinxs/lib/core/search/db_search.jinx +17 -6
  5. npcsh/npc_team/jinxs/lib/core/search/file_search.jinx +17 -6
  6. npcsh/npc_team/jinxs/lib/core/search/kg_search.jinx +19 -8
  7. npcsh/npc_team/jinxs/lib/core/search/web_search.jinx +52 -14
  8. npcsh/npc_team/jinxs/{bin → lib/utils}/benchmark.jinx +2 -2
  9. npcsh/npc_team/jinxs/{bin → lib/utils}/jinxs.jinx +12 -12
  10. npcsh/npc_team/jinxs/{bin → lib/utils}/models.jinx +7 -7
  11. npcsh/npc_team/jinxs/{bin → lib/utils}/setup.jinx +6 -6
  12. npcsh/npc_team/jinxs/modes/alicanto.jinx +1573 -296
  13. npcsh/npc_team/jinxs/modes/arxiv.jinx +5 -5
  14. npcsh/npc_team/jinxs/modes/config_tui.jinx +300 -0
  15. npcsh/npc_team/jinxs/modes/corca.jinx +3 -3
  16. npcsh/npc_team/jinxs/modes/git.jinx +795 -0
  17. {npcsh-1.1.20.data/data/npcsh/npc_team → npcsh/npc_team/jinxs/modes}/kg.jinx +13 -13
  18. npcsh/npc_team/jinxs/modes/memories.jinx +414 -0
  19. npcsh/npc_team/jinxs/{bin → modes}/nql.jinx +10 -21
  20. npcsh/npc_team/jinxs/modes/papers.jinx +578 -0
  21. npcsh/npc_team/jinxs/modes/plonk.jinx +490 -304
  22. npcsh/npc_team/jinxs/modes/reattach.jinx +3 -3
  23. npcsh/npc_team/jinxs/modes/spool.jinx +3 -3
  24. npcsh/npc_team/jinxs/{bin → modes}/team.jinx +12 -12
  25. npcsh/npc_team/jinxs/modes/vixynt.jinx +388 -0
  26. npcsh/npc_team/jinxs/modes/wander.jinx +454 -181
  27. npcsh/npc_team/jinxs/modes/yap.jinx +10 -3
  28. npcsh/npcsh.py +112 -47
  29. npcsh/routes.py +4 -1
  30. npcsh/salmon_simulation.py +0 -0
  31. npcsh-1.1.21.data/data/npcsh/npc_team/alicanto.jinx +1633 -0
  32. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/arxiv.jinx +5 -5
  33. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/benchmark.jinx +2 -2
  34. npcsh-1.1.21.data/data/npcsh/npc_team/compress.jinx +428 -0
  35. npcsh-1.1.21.data/data/npcsh/npc_team/config_tui.jinx +300 -0
  36. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/corca.jinx +3 -3
  37. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/db_search.jinx +17 -6
  38. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/file_search.jinx +17 -6
  39. npcsh-1.1.21.data/data/npcsh/npc_team/git.jinx +795 -0
  40. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/jinxs.jinx +12 -12
  41. {npcsh/npc_team/jinxs/bin → npcsh-1.1.21.data/data/npcsh/npc_team}/kg.jinx +13 -13
  42. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/kg_search.jinx +19 -8
  43. npcsh-1.1.21.data/data/npcsh/npc_team/memories.jinx +414 -0
  44. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/models.jinx +7 -7
  45. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/nql.jinx +10 -21
  46. npcsh-1.1.21.data/data/npcsh/npc_team/papers.jinx +578 -0
  47. npcsh-1.1.21.data/data/npcsh/npc_team/plonk.jinx +565 -0
  48. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/reattach.jinx +3 -3
  49. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/setup.jinx +6 -6
  50. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/spool.jinx +3 -3
  51. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/team.jinx +12 -12
  52. npcsh-1.1.21.data/data/npcsh/npc_team/vixynt.jinx +388 -0
  53. npcsh-1.1.21.data/data/npcsh/npc_team/wander.jinx +728 -0
  54. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/web_search.jinx +52 -14
  55. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/yap.jinx +10 -3
  56. {npcsh-1.1.20.dist-info → npcsh-1.1.21.dist-info}/METADATA +2 -2
  57. {npcsh-1.1.20.dist-info → npcsh-1.1.21.dist-info}/RECORD +145 -150
  58. npcsh-1.1.21.dist-info/entry_points.txt +11 -0
  59. npcsh/npc_team/jinxs/bin/config_tui.jinx +0 -300
  60. npcsh/npc_team/jinxs/bin/memories.jinx +0 -317
  61. npcsh/npc_team/jinxs/bin/vixynt.jinx +0 -122
  62. npcsh/npc_team/jinxs/lib/core/search/mem_review.jinx +0 -73
  63. npcsh/npc_team/jinxs/lib/core/search/mem_search.jinx +0 -388
  64. npcsh/npc_team/jinxs/lib/research/paper_search.jinx +0 -412
  65. npcsh/npc_team/jinxs/lib/research/semantic_scholar.jinx +0 -386
  66. npcsh/npc_team/plonkjr.npc +0 -23
  67. npcsh-1.1.20.data/data/npcsh/npc_team/alicanto.jinx +0 -356
  68. npcsh-1.1.20.data/data/npcsh/npc_team/compress.jinx +0 -140
  69. npcsh-1.1.20.data/data/npcsh/npc_team/config_tui.jinx +0 -300
  70. npcsh-1.1.20.data/data/npcsh/npc_team/mem_review.jinx +0 -73
  71. npcsh-1.1.20.data/data/npcsh/npc_team/mem_search.jinx +0 -388
  72. npcsh-1.1.20.data/data/npcsh/npc_team/memories.jinx +0 -317
  73. npcsh-1.1.20.data/data/npcsh/npc_team/paper_search.jinx +0 -412
  74. npcsh-1.1.20.data/data/npcsh/npc_team/plonk.jinx +0 -379
  75. npcsh-1.1.20.data/data/npcsh/npc_team/plonkjr.npc +0 -23
  76. npcsh-1.1.20.data/data/npcsh/npc_team/semantic_scholar.jinx +0 -386
  77. npcsh-1.1.20.data/data/npcsh/npc_team/vixynt.jinx +0 -122
  78. npcsh-1.1.20.data/data/npcsh/npc_team/wander.jinx +0 -455
  79. npcsh-1.1.20.dist-info/entry_points.txt +0 -25
  80. /npcsh/npc_team/jinxs/lib/{orchestration → core}/convene.jinx +0 -0
  81. /npcsh/npc_team/jinxs/lib/{orchestration → core}/delegate.jinx +0 -0
  82. /npcsh/npc_team/jinxs/{bin → lib/core}/sample.jinx +0 -0
  83. /npcsh/npc_team/jinxs/{bin → lib/utils}/sync.jinx +0 -0
  84. /npcsh/npc_team/jinxs/{bin → modes}/roll.jinx +0 -0
  85. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/add_tab.jinx +0 -0
  86. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/alicanto.npc +0 -0
  87. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/alicanto.png +0 -0
  88. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/browser_action.jinx +0 -0
  89. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/browser_screenshot.jinx +0 -0
  90. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/build.jinx +0 -0
  91. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/chat.jinx +0 -0
  92. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/click.jinx +0 -0
  93. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/close_browser.jinx +0 -0
  94. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/close_pane.jinx +0 -0
  95. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/close_tab.jinx +0 -0
  96. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/cmd.jinx +0 -0
  97. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/compile.jinx +0 -0
  98. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/confirm.jinx +0 -0
  99. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/convene.jinx +0 -0
  100. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/corca.npc +0 -0
  101. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/corca.png +0 -0
  102. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/corca_example.png +0 -0
  103. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/delegate.jinx +0 -0
  104. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/edit_file.jinx +0 -0
  105. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/focus_pane.jinx +0 -0
  106. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/frederic.npc +0 -0
  107. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/frederic4.png +0 -0
  108. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/guac.jinx +0 -0
  109. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/guac.npc +0 -0
  110. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/guac.png +0 -0
  111. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/help.jinx +0 -0
  112. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/incognide.jinx +0 -0
  113. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/init.jinx +0 -0
  114. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/kadiefa.npc +0 -0
  115. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/kadiefa.png +0 -0
  116. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/key_press.jinx +0 -0
  117. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/launch_app.jinx +0 -0
  118. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/list_panes.jinx +0 -0
  119. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/load_file.jinx +0 -0
  120. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/navigate.jinx +0 -0
  121. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/notify.jinx +0 -0
  122. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/npcsh.ctx +0 -0
  123. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/npcsh_sibiji.png +0 -0
  124. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/open_browser.jinx +0 -0
  125. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/open_pane.jinx +0 -0
  126. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/ots.jinx +0 -0
  127. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/paste.jinx +0 -0
  128. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/plonk.npc +0 -0
  129. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/plonk.png +0 -0
  130. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/plonkjr.png +0 -0
  131. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/pti.jinx +0 -0
  132. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/python.jinx +0 -0
  133. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/read_pane.jinx +0 -0
  134. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/roll.jinx +0 -0
  135. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/run_terminal.jinx +0 -0
  136. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/sample.jinx +0 -0
  137. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/screenshot.jinx +0 -0
  138. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/search.jinx +0 -0
  139. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/send_message.jinx +0 -0
  140. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/serve.jinx +0 -0
  141. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/set.jinx +0 -0
  142. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/sh.jinx +0 -0
  143. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/shh.jinx +0 -0
  144. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/sibiji.npc +0 -0
  145. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/sibiji.png +0 -0
  146. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/sleep.jinx +0 -0
  147. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/split_pane.jinx +0 -0
  148. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/spool.png +0 -0
  149. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/sql.jinx +0 -0
  150. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/switch.jinx +0 -0
  151. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/switch_npc.jinx +0 -0
  152. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/switch_tab.jinx +0 -0
  153. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/switches.jinx +0 -0
  154. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/sync.jinx +0 -0
  155. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/teamviz.jinx +0 -0
  156. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/trigger.jinx +0 -0
  157. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/type_text.jinx +0 -0
  158. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/usage.jinx +0 -0
  159. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/verbose.jinx +0 -0
  160. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/wait.jinx +0 -0
  161. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/write_file.jinx +0 -0
  162. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/yap.png +0 -0
  163. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/zen_mode.jinx +0 -0
  164. {npcsh-1.1.20.dist-info → npcsh-1.1.21.dist-info}/WHEEL +0 -0
  165. {npcsh-1.1.20.dist-info → npcsh-1.1.21.dist-info}/licenses/LICENSE +0 -0
  166. {npcsh-1.1.20.dist-info → npcsh-1.1.21.dist-info}/top_level.txt +0 -0
@@ -1,379 +0,0 @@
1
- jinx_name: plonk
2
- description: Vision-based GUI automation - use vision model to interact with screen elements
3
- inputs:
4
- - task: null
5
- - vmodel: null
6
- - vprovider: null
7
- - max_iterations: 10
8
- - debug: true
9
- - browse: false
10
-
11
- steps:
12
- - name: plonk_execute
13
- engine: python
14
- code: |
15
- import os
16
- import sys
17
- import tty
18
- import termios
19
- import time
20
- import platform
21
- from termcolor import colored
22
-
23
- from npcpy.llm_funcs import get_llm_response
24
- from npcpy.data.image import capture_screenshot
25
- from npcpy.work.desktop import perform_action
26
-
27
- npc = context.get('npc')
28
- team = context.get('team')
29
- messages = context.get('messages', [])
30
-
31
- # Resolve npc if it's a string (npc name) rather than NPC object
32
- if isinstance(npc, str) and team:
33
- npc = team.get(npc) if hasattr(team, 'get') else None
34
- elif isinstance(npc, str):
35
- npc = None
36
-
37
- # ========== TUI Helper Functions ==========
38
- def get_terminal_size():
39
- try:
40
- size = os.get_terminal_size()
41
- return size.columns, size.lines
42
- except:
43
- return 80, 24
44
-
45
- def plonk_tui_browser(summary, click_history):
46
- """Interactive TUI browser for plonk action history"""
47
- if not summary and not click_history:
48
- print(colored("No actions recorded.", "yellow"))
49
- return
50
-
51
- width, height = get_terminal_size()
52
- selected = 0
53
- scroll = 0
54
- list_height = height - 5
55
- mode = 'summary' # summary or history
56
-
57
- fd = sys.stdin.fileno()
58
- old_settings = termios.tcgetattr(fd)
59
-
60
- try:
61
- tty.setcbreak(fd)
62
- sys.stdout.write('\033[?25l')
63
- sys.stdout.write('\033[2J\033[H')
64
-
65
- while True:
66
- width, height = get_terminal_size()
67
- list_height = height - 5
68
-
69
- items = summary if mode == 'summary' else click_history
70
-
71
- if not items:
72
- items = [{'action': 'none', 'reason': 'No actions'}]
73
-
74
- if selected >= len(items):
75
- selected = max(0, len(items) - 1)
76
-
77
- if selected < scroll:
78
- scroll = selected
79
- elif selected >= scroll + list_height:
80
- scroll = selected - list_height + 1
81
-
82
- sys.stdout.write('\033[H')
83
-
84
- # Tab bar
85
- summary_tab = '\033[44;37;1m Summary \033[0m' if mode == 'summary' else '\033[90m Summary \033[0m'
86
- history_tab = '\033[44;37;1m History \033[0m' if mode == 'history' else '\033[90m History \033[0m'
87
- header = f" PLONK ACTION BROWSER {summary_tab} {history_tab} "
88
- sys.stdout.write(f'\033[44;37;1m{" PLONK ACTION BROWSER".ljust(width)}\033[0m\n')
89
-
90
- if mode == 'summary':
91
- col_header = f' {"STEP":<6} {"ACTION":<12} {"COORDS":<15} {"REASON":<40}'
92
- else:
93
- col_header = f' {"#":<4} {"ACTION":<10} {"X":<6} {"Y":<6} {"DETAILS":<40}'
94
- sys.stdout.write(f'\033[90m{col_header[:width]}\033[0m\n')
95
-
96
- for i in range(list_height):
97
- idx = scroll + i
98
- sys.stdout.write(f'\033[{3+i};1H\033[K')
99
- if idx >= len(items):
100
- continue
101
-
102
- item = items[idx]
103
-
104
- if mode == 'summary':
105
- step = item.get('iteration', idx + 1)
106
- action = item.get('action', '?')[:12]
107
- coords = item.get('last_click_coords', 'N/A')[:15]
108
- reason = item.get('reason', item.get('error', ''))[:40]
109
- line = f" {step:<6} {action:<12} {coords:<15} {reason}"
110
- else:
111
- action = item.get('action', '?')[:10]
112
- x = str(item.get('x', '-'))[:6]
113
- y = str(item.get('y', '-'))[:6]
114
- details = item.get('reason', item.get('text', item.get('key', item.get('command', ''))))[:40]
115
- line = f" {idx+1:<4} {action:<10} {x:<6} {y:<6} {details}"
116
-
117
- line = line[:width-1]
118
-
119
- # Color by action type
120
- action_type = item.get('action', '')
121
- if action_type == 'done':
122
- color = '\033[32m' # green
123
- elif action_type == 'fail':
124
- color = '\033[31m' # red
125
- elif action_type == 'click':
126
- color = '\033[33m' # yellow
127
- elif action_type == 'type':
128
- color = '\033[36m' # cyan
129
- else:
130
- color = ''
131
-
132
- if idx == selected:
133
- sys.stdout.write(f'\033[7;1m>{line.ljust(width-2)}\033[0m')
134
- elif color:
135
- sys.stdout.write(f'{color}{line}\033[0m')
136
- else:
137
- sys.stdout.write(f' {line}')
138
-
139
- # Status bar
140
- sys.stdout.write(f'\033[{height-2};1H\033[K\033[90m{"─" * width}\033[0m')
141
- stats = f"Actions: {len(summary)} | Clicks: {len([h for h in click_history if h.get('action') == 'click'])}"
142
- sys.stdout.write(f'\033[{height-1};1H\033[K {stats}'.ljust(width)[:width])
143
- sys.stdout.write(f'\033[{height};1H\033[K\033[44;37m j/k:Nav Tab:Toggle Enter:Details q:Quit [{selected+1}/{len(items)}] \033[0m')
144
-
145
- sys.stdout.flush()
146
-
147
- c = sys.stdin.read(1)
148
-
149
- if c == '\x1b':
150
- c2 = sys.stdin.read(1)
151
- if c2 == '[':
152
- c3 = sys.stdin.read(1)
153
- if c3 == 'A' and selected > 0:
154
- selected -= 1
155
- elif c3 == 'B' and selected < len(items) - 1:
156
- selected += 1
157
- else:
158
- return
159
- continue
160
-
161
- if c == 'q' or c == '\x03':
162
- return
163
- elif c == 'k' and selected > 0:
164
- selected -= 1
165
- elif c == 'j' and selected < len(items) - 1:
166
- selected += 1
167
- elif c == '\t': # Tab to toggle
168
- mode = 'history' if mode == 'summary' else 'summary'
169
- selected = 0
170
- scroll = 0
171
- elif c in ('\r', '\n'):
172
- # Show full details
173
- item = items[selected]
174
- details = "\n".join(f"{k}: {v}" for k, v in item.items())
175
- print(f'\033[2J\033[H{details}\n\nPress any key to continue...')
176
- sys.stdout.flush()
177
- sys.stdin.read(1)
178
- sys.stdout.write('\033[2J\033[H')
179
-
180
- finally:
181
- termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
182
- sys.stdout.write('\033[?25h')
183
- sys.stdout.write('\033[2J\033[H')
184
- sys.stdout.flush()
185
-
186
- task = context.get('task')
187
- vision_model = context.get('vmodel') or (npc.model if npc and hasattr(npc, 'model') else 'gpt-4o')
188
- vision_provider = context.get('vprovider') or (npc.provider if npc and hasattr(npc, 'provider') else 'openai')
189
- max_iterations = int(context.get('max_iterations', 10))
190
- debug = context.get('debug', True)
191
-
192
- if not task:
193
- context['output'] = """Usage: /plonk <task description>
194
-
195
- Options:
196
- --vmodel MODEL Vision model to use (default: gpt-4o)
197
- --vprovider PROV Vision provider (default: openai)
198
- --max-iterations N Max steps (default: 10)
199
-
200
- Example: /plonk Open Firefox and navigate to google.com"""
201
- context['messages'] = messages
202
- exit()
203
-
204
- print(f"""
205
- ██████╗ ██╗ ██████╗ ███╗ ██╗██╗ ██╗
206
- ██╔══██╗██║ ██╔═══██╗████╗ ██║██║ ██╔╝
207
- ██████╔╝██║ ██║ ██║██╔██╗ ██║█████╔╝
208
- ██╔═══╝ ██║ ██║ ██║██║╚██╗██║██╔═██╗
209
- ██║ ███████╗╚██████╔╝██║ ╚████║██║ ██╗
210
- ╚═╝ ╚══════╝ ╚═════╝ ╚═╝ ╚═══╝╚═╝ ╚═╝
211
-
212
- Vision GUI Automation
213
- Task: {task}
214
- Model: {vision_model} | Max iterations: {max_iterations}
215
- """)
216
-
217
- # System-specific examples
218
- system = platform.system()
219
- if system == "Windows":
220
- app_examples = "start firefox, notepad, calc"
221
- elif system == "Darwin":
222
- app_examples = "open -a Firefox, open -a TextEdit"
223
- else:
224
- app_examples = "firefox &, gedit &, gnome-calculator &"
225
-
226
- # Action types
227
- ACTION_SCHEMA = {
228
- "type": "object",
229
- "properties": {
230
- "action": {
231
- "type": "string",
232
- "enum": ["click", "type", "key", "launch", "wait", "done", "fail"],
233
- "description": "Action to perform"
234
- },
235
- "x": {"type": "number", "description": "X coordinate (0-100 percentage)"},
236
- "y": {"type": "number", "description": "Y coordinate (0-100 percentage)"},
237
- "text": {"type": "string", "description": "Text to type or key to press"},
238
- "command": {"type": "string", "description": "Command to launch"},
239
- "duration": {"type": "number", "description": "Wait duration in seconds"},
240
- "reason": {"type": "string", "description": "Explanation of action"}
241
- },
242
- "required": ["action", "reason"]
243
- }
244
-
245
- click_history = []
246
- summary = []
247
-
248
- for iteration in range(max_iterations):
249
- print(colored(f"\n--- Iteration {iteration + 1}/{max_iterations} ---", "cyan"))
250
-
251
- # Capture screenshot
252
- ss = capture_screenshot()
253
- if not ss or 'file_path' not in ss:
254
- print(colored("Failed to capture screenshot", "red"))
255
- break
256
-
257
- screenshot_path = ss['file_path']
258
- if debug:
259
- print(colored(f"Screenshot: {screenshot_path}", "gray"))
260
-
261
- # Build context from history
262
- history_context = ""
263
- if click_history:
264
- history_context = f"\nPrevious actions ({len(click_history)}):\n"
265
- for i, click in enumerate(click_history[-5:], 1):
266
- history_context += f" {i}. {click.get('action', 'unknown')} at ({click.get('x', '?')}, {click.get('y', '?')}) - {click.get('reason', '')}\n"
267
-
268
- prompt = f"""You are a GUI automation assistant. Analyze this screenshot and determine the next action to complete the task.
269
-
270
- TASK: {task}
271
-
272
- {history_context}
273
-
274
- Available actions:
275
- - click: Click at x,y coordinates (0-100 percentage of screen)
276
- - type: Type text
277
- - key: Press key (enter, tab, escape, etc.)
278
- - launch: Launch application ({app_examples})
279
- - wait: Wait for duration seconds
280
- - done: Task completed successfully
281
- - fail: Task cannot be completed
282
-
283
- Respond with JSON: {{"action": "...", "x": N, "y": N, "text": "...", "command": "...", "duration": N, "reason": "..."}}"""
284
-
285
- try:
286
- resp = get_llm_response(
287
- prompt,
288
- model=vision_model,
289
- provider=vision_provider,
290
- images=[screenshot_path],
291
- format="json",
292
- npc=npc
293
- )
294
-
295
- action_response = resp.get('response', {})
296
- if isinstance(action_response, str):
297
- import json
298
- try:
299
- action_response = json.loads(action_response)
300
- except:
301
- print(colored(f"Invalid JSON response: {action_response[:100]}", "red"))
302
- continue
303
-
304
- action = action_response.get('action', 'fail')
305
- reason = action_response.get('reason', 'No reason provided')
306
-
307
- print(colored(f"Action: {action} - {reason}", "yellow"))
308
-
309
- if action == 'done':
310
- print(colored("Task completed successfully!", "green"))
311
- summary.append({"iteration": iteration + 1, "action": "done", "reason": reason})
312
- break
313
-
314
- if action == 'fail':
315
- print(colored(f"Task failed: {reason}", "red"))
316
- summary.append({"iteration": iteration + 1, "action": "fail", "reason": reason})
317
- break
318
-
319
- # Execute action
320
- if action == 'click':
321
- x, y = action_response.get('x', 50), action_response.get('y', 50)
322
- perform_action('click', x=x, y=y)
323
- click_history.append({"action": "click", "x": x, "y": y, "reason": reason})
324
- print(colored(f"Clicked at ({x}, {y})", "green"))
325
-
326
- elif action == 'type':
327
- text = action_response.get('text', '')
328
- perform_action('type', text=text)
329
- click_history.append({"action": "type", "text": text[:20], "reason": reason})
330
- print(colored(f"Typed: {text[:30]}...", "green"))
331
-
332
- elif action == 'key':
333
- key = action_response.get('text', 'enter')
334
- perform_action('key', key=key)
335
- click_history.append({"action": "key", "key": key, "reason": reason})
336
- print(colored(f"Pressed key: {key}", "green"))
337
-
338
- elif action == 'launch':
339
- cmd = action_response.get('command', '')
340
- perform_action('launch', command=cmd)
341
- click_history.append({"action": "launch", "command": cmd, "reason": reason})
342
- print(colored(f"Launched: {cmd}", "green"))
343
- time.sleep(2) # Wait for app to open
344
-
345
- elif action == 'wait':
346
- duration = action_response.get('duration', 1)
347
- time.sleep(duration)
348
- click_history.append({"action": "wait", "duration": duration, "reason": reason})
349
- print(colored(f"Waited {duration}s", "green"))
350
-
351
- summary.append({
352
- "iteration": iteration + 1,
353
- "action": action,
354
- "last_click_coords": f"({click_history[-1].get('x', 'N/A')}, {click_history[-1].get('y', 'N/A')})" if click_history else "N/A",
355
- "reason": reason
356
- })
357
-
358
- time.sleep(0.5) # Brief pause between actions
359
-
360
- except Exception as e:
361
- print(colored(f"Error in iteration {iteration + 1}: {e}", "red"))
362
- summary.append({"iteration": iteration + 1, "error": str(e)})
363
-
364
- # Generate summary
365
- print("\n" + "="*50)
366
- print(colored("PLONK SESSION SUMMARY", "cyan", attrs=['bold']))
367
- print("="*50)
368
- for s in summary:
369
- print(f" Step {s.get('iteration', '?')}: {s.get('action', 'unknown')} - {s.get('reason', s.get('error', ''))[:60]}")
370
-
371
- context['output'] = f"Plonk completed with {len(summary)} actions"
372
- context['messages'] = messages
373
- context['plonk_summary'] = summary
374
- context['click_history'] = click_history
375
-
376
- # Launch interactive browser automatically
377
- if summary:
378
- print(colored("\nLaunching action browser...", "cyan"))
379
- plonk_tui_browser(summary, click_history)
@@ -1,23 +0,0 @@
1
- name: plonkjr
2
- ascii_art: |
3
- 🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲
4
- ██████ ██ ██████ ███ ██ ██ ██ 🪵 ██ ██████
5
- ██ ██ ██ ██ ██ ████ ██ ██ ██ ██ ██ ██
6
- ██████ ██ ██ ██ ██ ██ ██ █████ 🌲 ██ ██████
7
- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
8
- ██ ███████ ██████ ██ ████ ██ ██ █████ ██ ██
9
- 🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲
10
- colors:
11
- top: "34,139,34"
12
- bottom: "139,69,19"
13
- primary_directive: |
14
- You are plonkjr, the junior automation assistant. You handle basic computer use tasks:
15
- taking screenshots, clicking, typing, and pressing keys. You're simpler than plonk -
16
- you focus on executing the core actions without complex vision-based planning.
17
- Just do what's asked: screenshot, click, type, key press.
18
- jinxs:
19
- - lib/computer_use/screenshot
20
- - lib/computer_use/click
21
- - lib/computer_use/type_text
22
- - lib/computer_use/key_press
23
- - lib/core/sh