janito 1.14.3__py3-none-any.whl → 2.0.0__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 (282) hide show
  1. janito/__init__.py +6 -1
  2. janito/__main__.py +1 -1
  3. janito/agent/setup_agent.py +139 -0
  4. janito/agent/templates/profiles/{system_prompt_template_base.txt.j2 → system_prompt_template_main.txt.j2} +1 -1
  5. janito/cli/__init__.py +9 -0
  6. janito/cli/chat_mode/bindings.py +37 -0
  7. janito/cli/chat_mode/chat_entry.py +23 -0
  8. janito/cli/chat_mode/prompt_style.py +19 -0
  9. janito/cli/chat_mode/session.py +272 -0
  10. janito/{shell/prompt/completer.py → cli/chat_mode/shell/autocomplete.py} +7 -6
  11. janito/cli/chat_mode/shell/commands/__init__.py +55 -0
  12. janito/cli/chat_mode/shell/commands/base.py +9 -0
  13. janito/cli/chat_mode/shell/commands/clear.py +12 -0
  14. janito/{shell → cli/chat_mode/shell}/commands/conversation_restart.py +34 -30
  15. janito/cli/chat_mode/shell/commands/edit.py +25 -0
  16. janito/cli/chat_mode/shell/commands/help.py +16 -0
  17. janito/cli/chat_mode/shell/commands/history_view.py +93 -0
  18. janito/cli/chat_mode/shell/commands/lang.py +25 -0
  19. janito/cli/chat_mode/shell/commands/last.py +137 -0
  20. janito/cli/chat_mode/shell/commands/livelogs.py +49 -0
  21. janito/cli/chat_mode/shell/commands/multi.py +51 -0
  22. janito/cli/chat_mode/shell/commands/prompt.py +64 -0
  23. janito/cli/chat_mode/shell/commands/role.py +36 -0
  24. janito/cli/chat_mode/shell/commands/session.py +40 -0
  25. janito/{shell → cli/chat_mode/shell}/commands/session_control.py +2 -2
  26. janito/cli/chat_mode/shell/commands/termweb_log.py +92 -0
  27. janito/cli/chat_mode/shell/commands/tools.py +32 -0
  28. janito/{shell → cli/chat_mode/shell}/commands/utility.py +4 -7
  29. janito/{shell → cli/chat_mode/shell}/commands/verbose.py +5 -5
  30. janito/cli/chat_mode/shell/session/__init__.py +1 -0
  31. janito/{shell → cli/chat_mode/shell}/session/manager.py +9 -1
  32. janito/cli/chat_mode/toolbar.py +90 -0
  33. janito/cli/cli_commands/list_models.py +35 -0
  34. janito/cli/cli_commands/list_providers.py +9 -0
  35. janito/cli/cli_commands/list_tools.py +53 -0
  36. janito/cli/cli_commands/model_selection.py +50 -0
  37. janito/cli/cli_commands/model_utils.py +84 -0
  38. janito/cli/cli_commands/set_api_key.py +19 -0
  39. janito/cli/cli_commands/show_config.py +51 -0
  40. janito/cli/cli_commands/show_system_prompt.py +62 -0
  41. janito/cli/config.py +28 -0
  42. janito/cli/console.py +3 -0
  43. janito/cli/core/__init__.py +4 -0
  44. janito/cli/core/event_logger.py +59 -0
  45. janito/cli/core/getters.py +31 -0
  46. janito/cli/core/runner.py +141 -0
  47. janito/cli/core/setters.py +174 -0
  48. janito/cli/core/unsetters.py +54 -0
  49. janito/cli/main.py +8 -196
  50. janito/cli/main_cli.py +312 -0
  51. janito/cli/prompt_core.py +230 -0
  52. janito/cli/prompt_handler.py +6 -0
  53. janito/cli/rich_terminal_reporter.py +101 -0
  54. janito/cli/single_shot_mode/__init__.py +6 -0
  55. janito/cli/single_shot_mode/handler.py +137 -0
  56. janito/cli/termweb_starter.py +73 -24
  57. janito/cli/utils.py +25 -0
  58. janito/cli/verbose_output.py +196 -0
  59. janito/config.py +5 -0
  60. janito/config_manager.py +110 -0
  61. janito/conversation_history.py +30 -0
  62. janito/{agent/tools_utils/dir_walk_utils.py → dir_walk_utils.py} +3 -2
  63. janito/driver_events.py +98 -0
  64. janito/drivers/anthropic/driver.py +113 -0
  65. janito/drivers/azure_openai/driver.py +36 -0
  66. janito/drivers/driver_registry.py +33 -0
  67. janito/drivers/google_genai/driver.py +54 -0
  68. janito/drivers/google_genai/schema_generator.py +67 -0
  69. janito/drivers/mistralai/driver.py +41 -0
  70. janito/drivers/openai/driver.py +334 -0
  71. janito/event_bus/__init__.py +2 -0
  72. janito/event_bus/bus.py +68 -0
  73. janito/event_bus/event.py +15 -0
  74. janito/event_bus/handler.py +31 -0
  75. janito/event_bus/queue_bus.py +57 -0
  76. janito/exceptions.py +23 -0
  77. janito/formatting_token.py +54 -0
  78. janito/i18n/pt.py +1 -0
  79. janito/llm/__init__.py +5 -0
  80. janito/llm/agent.py +443 -0
  81. janito/llm/auth.py +62 -0
  82. janito/llm/driver.py +239 -0
  83. janito/llm/driver_config.py +34 -0
  84. janito/llm/driver_config_builder.py +34 -0
  85. janito/llm/driver_input.py +12 -0
  86. janito/llm/message_parts.py +60 -0
  87. janito/llm/model.py +38 -0
  88. janito/llm/provider.py +187 -0
  89. janito/perf_singleton.py +3 -0
  90. janito/performance_collector.py +167 -0
  91. janito/provider_config.py +98 -0
  92. janito/provider_registry.py +152 -0
  93. janito/providers/__init__.py +7 -0
  94. janito/providers/anthropic/model_info.py +22 -0
  95. janito/providers/anthropic/provider.py +65 -0
  96. janito/providers/azure_openai/model_info.py +15 -0
  97. janito/providers/azure_openai/provider.py +72 -0
  98. janito/providers/deepseek/__init__.py +1 -0
  99. janito/providers/deepseek/model_info.py +16 -0
  100. janito/providers/deepseek/provider.py +91 -0
  101. janito/providers/google/__init__.py +1 -0
  102. janito/providers/google/model_info.py +40 -0
  103. janito/providers/google/provider.py +69 -0
  104. janito/providers/mistralai/model_info.py +37 -0
  105. janito/providers/mistralai/provider.py +69 -0
  106. janito/providers/openai/__init__.py +1 -0
  107. janito/providers/openai/model_info.py +137 -0
  108. janito/providers/openai/provider.py +107 -0
  109. janito/providers/openai/schema_generator.py +63 -0
  110. janito/providers/provider_static_info.py +21 -0
  111. janito/providers/registry.py +26 -0
  112. janito/report_events.py +38 -0
  113. janito/termweb/app.py +1 -1
  114. janito/tools/__init__.py +16 -0
  115. janito/tools/adapters/__init__.py +1 -0
  116. janito/tools/adapters/local/__init__.py +54 -0
  117. janito/tools/adapters/local/adapter.py +92 -0
  118. janito/{agent/tools → tools/adapters/local}/ask_user.py +30 -13
  119. janito/tools/adapters/local/copy_file.py +84 -0
  120. janito/{agent/tools → tools/adapters/local}/create_directory.py +11 -10
  121. janito/tools/adapters/local/create_file.py +82 -0
  122. janito/tools/adapters/local/delete_text_in_file.py +136 -0
  123. janito/{agent/tools → tools/adapters/local}/fetch_url.py +18 -19
  124. janito/tools/adapters/local/find_files.py +140 -0
  125. janito/tools/adapters/local/get_file_outline/core.py +151 -0
  126. janito/{agent/tools → tools/adapters/local}/get_file_outline/python_outline.py +125 -0
  127. janito/tools/adapters/local/get_file_outline/python_outline_v2.py +156 -0
  128. janito/{agent/tools → tools/adapters/local}/get_file_outline/search_outline.py +12 -7
  129. janito/{agent/tools → tools/adapters/local}/move_file.py +13 -9
  130. janito/{agent/tools → tools/adapters/local}/open_url.py +7 -5
  131. janito/tools/adapters/local/python_code_run.py +165 -0
  132. janito/tools/adapters/local/python_command_run.py +163 -0
  133. janito/tools/adapters/local/python_file_run.py +162 -0
  134. janito/{agent/tools → tools/adapters/local}/remove_directory.py +15 -9
  135. janito/{agent/tools → tools/adapters/local}/remove_file.py +17 -14
  136. janito/{agent/tools → tools/adapters/local}/replace_text_in_file.py +27 -22
  137. janito/tools/adapters/local/run_bash_command.py +176 -0
  138. janito/tools/adapters/local/run_powershell_command.py +219 -0
  139. janito/{agent/tools → tools/adapters/local}/search_text/core.py +32 -12
  140. janito/{agent/tools → tools/adapters/local}/search_text/match_lines.py +13 -4
  141. janito/{agent/tools → tools/adapters/local}/search_text/pattern_utils.py +12 -4
  142. janito/{agent/tools → tools/adapters/local}/search_text/traverse_directory.py +15 -2
  143. janito/{agent/tools → tools/adapters/local}/validate_file_syntax/core.py +12 -11
  144. janito/{agent/tools → tools/adapters/local}/validate_file_syntax/css_validator.py +1 -1
  145. janito/{agent/tools → tools/adapters/local}/validate_file_syntax/html_validator.py +1 -1
  146. janito/{agent/tools → tools/adapters/local}/validate_file_syntax/js_validator.py +1 -1
  147. janito/{agent/tools → tools/adapters/local}/validate_file_syntax/json_validator.py +1 -1
  148. janito/{agent/tools → tools/adapters/local}/validate_file_syntax/markdown_validator.py +1 -1
  149. janito/{agent/tools → tools/adapters/local}/validate_file_syntax/ps1_validator.py +1 -1
  150. janito/{agent/tools → tools/adapters/local}/validate_file_syntax/python_validator.py +1 -1
  151. janito/{agent/tools → tools/adapters/local}/validate_file_syntax/xml_validator.py +1 -1
  152. janito/{agent/tools → tools/adapters/local}/validate_file_syntax/yaml_validator.py +1 -1
  153. janito/{agent/tools/get_lines.py → tools/adapters/local/view_file.py} +45 -27
  154. janito/tools/inspect_registry.py +17 -0
  155. janito/tools/tool_base.py +105 -0
  156. janito/tools/tool_events.py +58 -0
  157. janito/tools/tool_run_exception.py +12 -0
  158. janito/{agent → tools}/tool_use_tracker.py +2 -4
  159. janito/{agent/tools_utils/utils.py → tools/tool_utils.py} +18 -9
  160. janito/tools/tools_adapter.py +207 -0
  161. janito/tools/tools_schema.py +104 -0
  162. janito/utils.py +11 -0
  163. janito/version.py +4 -0
  164. janito-2.0.0.dist-info/METADATA +232 -0
  165. janito-2.0.0.dist-info/RECORD +180 -0
  166. janito/agent/__init__.py +0 -0
  167. janito/agent/api_exceptions.py +0 -4
  168. janito/agent/config.py +0 -147
  169. janito/agent/config_defaults.py +0 -12
  170. janito/agent/config_utils.py +0 -0
  171. janito/agent/content_handler.py +0 -0
  172. janito/agent/conversation.py +0 -238
  173. janito/agent/conversation_api.py +0 -306
  174. janito/agent/conversation_exceptions.py +0 -18
  175. janito/agent/conversation_tool_calls.py +0 -39
  176. janito/agent/conversation_ui.py +0 -17
  177. janito/agent/event.py +0 -24
  178. janito/agent/event_dispatcher.py +0 -24
  179. janito/agent/event_handler_protocol.py +0 -5
  180. janito/agent/event_system.py +0 -15
  181. janito/agent/llm_conversation_history.py +0 -82
  182. janito/agent/message_handler.py +0 -20
  183. janito/agent/message_handler_protocol.py +0 -5
  184. janito/agent/openai_client.py +0 -149
  185. janito/agent/openai_schema_generator.py +0 -187
  186. janito/agent/profile_manager.py +0 -96
  187. janito/agent/queued_message_handler.py +0 -50
  188. janito/agent/rich_live.py +0 -32
  189. janito/agent/rich_message_handler.py +0 -115
  190. janito/agent/runtime_config.py +0 -36
  191. janito/agent/test_handler_protocols.py +0 -47
  192. janito/agent/test_openai_schema_generator.py +0 -93
  193. janito/agent/tests/__init__.py +0 -1
  194. janito/agent/tool_base.py +0 -63
  195. janito/agent/tool_executor.py +0 -122
  196. janito/agent/tool_registry.py +0 -49
  197. janito/agent/tools/__init__.py +0 -47
  198. janito/agent/tools/create_file.py +0 -59
  199. janito/agent/tools/delete_text_in_file.py +0 -97
  200. janito/agent/tools/find_files.py +0 -106
  201. janito/agent/tools/get_file_outline/core.py +0 -81
  202. janito/agent/tools/present_choices.py +0 -64
  203. janito/agent/tools/python_command_runner.py +0 -201
  204. janito/agent/tools/python_file_runner.py +0 -199
  205. janito/agent/tools/python_stdin_runner.py +0 -208
  206. janito/agent/tools/replace_file.py +0 -72
  207. janito/agent/tools/run_bash_command.py +0 -218
  208. janito/agent/tools/run_powershell_command.py +0 -251
  209. janito/agent/tools_utils/__init__.py +0 -1
  210. janito/agent/tools_utils/action_type.py +0 -7
  211. janito/agent/tools_utils/test_gitignore_utils.py +0 -46
  212. janito/cli/_livereload_log_utils.py +0 -13
  213. janito/cli/_print_config.py +0 -96
  214. janito/cli/_termweb_log_utils.py +0 -17
  215. janito/cli/_utils.py +0 -9
  216. janito/cli/arg_parser.py +0 -272
  217. janito/cli/cli_main.py +0 -281
  218. janito/cli/config_commands.py +0 -211
  219. janito/cli/config_runner.py +0 -35
  220. janito/cli/formatting_runner.py +0 -12
  221. janito/cli/livereload_starter.py +0 -60
  222. janito/cli/logging_setup.py +0 -38
  223. janito/cli/one_shot.py +0 -80
  224. janito/livereload/app.py +0 -25
  225. janito/rich_utils.py +0 -59
  226. janito/shell/__init__.py +0 -0
  227. janito/shell/commands/__init__.py +0 -61
  228. janito/shell/commands/config.py +0 -22
  229. janito/shell/commands/edit.py +0 -24
  230. janito/shell/commands/history_view.py +0 -18
  231. janito/shell/commands/lang.py +0 -19
  232. janito/shell/commands/livelogs.py +0 -42
  233. janito/shell/commands/prompt.py +0 -62
  234. janito/shell/commands/termweb_log.py +0 -94
  235. janito/shell/commands/tools.py +0 -26
  236. janito/shell/commands/track.py +0 -36
  237. janito/shell/main.py +0 -326
  238. janito/shell/prompt/load_prompt.py +0 -57
  239. janito/shell/prompt/session_setup.py +0 -57
  240. janito/shell/session/config.py +0 -109
  241. janito/shell/session/history.py +0 -0
  242. janito/shell/ui/interactive.py +0 -226
  243. janito/termweb/static/editor.css +0 -158
  244. janito/termweb/static/editor.css.bak +0 -145
  245. janito/termweb/static/editor.html +0 -46
  246. janito/termweb/static/editor.html.bak +0 -46
  247. janito/termweb/static/editor.js +0 -265
  248. janito/termweb/static/editor.js.bak +0 -259
  249. janito/termweb/static/explorer.html.bak +0 -59
  250. janito/termweb/static/favicon.ico +0 -0
  251. janito/termweb/static/favicon.ico.bak +0 -0
  252. janito/termweb/static/index.html +0 -53
  253. janito/termweb/static/index.html.bak +0 -54
  254. janito/termweb/static/index.html.bak.bak +0 -175
  255. janito/termweb/static/landing.html.bak +0 -36
  256. janito/termweb/static/termicon.svg +0 -1
  257. janito/termweb/static/termweb.css +0 -214
  258. janito/termweb/static/termweb.css.bak +0 -237
  259. janito/termweb/static/termweb.js +0 -162
  260. janito/termweb/static/termweb.js.bak +0 -168
  261. janito/termweb/static/termweb.js.bak.bak +0 -157
  262. janito/termweb/static/termweb_quickopen.js +0 -135
  263. janito/termweb/static/termweb_quickopen.js.bak +0 -125
  264. janito/tests/test_rich_utils.py +0 -44
  265. janito/web/__init__.py +0 -0
  266. janito/web/__main__.py +0 -25
  267. janito/web/app.py +0 -145
  268. janito-1.14.3.dist-info/METADATA +0 -313
  269. janito-1.14.3.dist-info/RECORD +0 -162
  270. janito-1.14.3.dist-info/licenses/LICENSE +0 -21
  271. /janito/{shell → cli/chat_mode/shell}/input_history.py +0 -0
  272. /janito/{shell/commands/session.py → cli/chat_mode/shell/session/history.py} +0 -0
  273. /janito/{agent/tools_utils/formatting.py → formatting.py} +0 -0
  274. /janito/{agent/tools_utils/gitignore_utils.py → gitignore_utils.py} +0 -0
  275. /janito/{agent/platform_discovery.py → platform_discovery.py} +0 -0
  276. /janito/{agent/tools → tools/adapters/local}/get_file_outline/__init__.py +0 -0
  277. /janito/{agent/tools → tools/adapters/local}/get_file_outline/markdown_outline.py +0 -0
  278. /janito/{agent/tools → tools/adapters/local}/search_text/__init__.py +0 -0
  279. /janito/{agent/tools → tools/adapters/local}/validate_file_syntax/__init__.py +0 -0
  280. {janito-1.14.3.dist-info → janito-2.0.0.dist-info}/WHEEL +0 -0
  281. {janito-1.14.3.dist-info → janito-2.0.0.dist-info}/entry_points.txt +0 -0
  282. {janito-1.14.3.dist-info → janito-2.0.0.dist-info}/top_level.txt +0 -0
@@ -1,46 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <link rel="icon" type="image/svg+xml" href="/static/termicon.svg">
5
- <link rel="shortcut icon" type="image/x-icon" href="/static/favicon.ico">
6
- <meta charset="UTF-8">
7
- <title>Janito Light Editor</title>
8
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/codemirror.min.css">
9
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/theme/dracula.min.css">
10
- <link rel="stylesheet" href="/static/termweb.css">
11
- <link rel="stylesheet" href="/static/editor.css">
12
- </head>
13
- <body>
14
- <div class="header">
15
- <div class="header-title">Janito Light Editor</div>
16
- <span id="filename-display" class="filename-display"></span>
17
- <div style="flex:1 1 auto;"></div>
18
- <button class="theme-switcher" id="theme-switcher" title="Alternator tema">
19
- <span id="theme-icon" aria-label="Switch theme" style="pointer-events:none;">🌙</span>
20
- </button>
21
- </div>
22
- <div class="main">
23
- <div class="editor-pane">
24
- <textarea id="code" name="code"></textarea>
25
- <div id="save-popup" style="display:none;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);z-index:9999;background:#2196f3;color:#fff;padding:14px 28px;border-radius:8px;box-shadow:0 4px 16px #1976d288;border:2px solid #1976d2;font-size:1.1em;">Saved!</div>
26
- </div>
27
- </div>
28
- <div class="footer">
29
- <button class="save-btn" id="save-btn">Save</button>
30
-
31
- </div>
32
- <div id="save-popup" style="display:none;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);z-index:9999;background:#2196f3;color:#fff;padding:14px 28px;border-radius:8px;box-shadow:0 4px 16px #1976d288;border:2px solid #1976d2;font-size:1.1em;">Saved!</div>
33
- <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/codemirror.min.js"></script>
34
- <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/mode/python/python.min.js"></script>
35
- <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/mode/django/django.min.js"></script>
36
- <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/theme/dracula.min.js"></script>
37
- <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/addon/selection/active-line.min.js"></script>
38
- <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/addon/search/search.min.js"></script>
39
- <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/addon/search/searchcursor.min.js"></script>
40
- <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/addon/dialog/dialog.min.js"></script>
41
- <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/addon/mode/overlay.min.js"></script>
42
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/addon/dialog/dialog.min.css">
43
-
44
- <script src="/static/editor.js"></script>
45
- </body>
46
- </html>
@@ -1,46 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <link rel="icon" type="image/svg+xml" href="/static/termicon.svg">
5
- <link rel="shortcut icon" type="image/x-icon" href="/static/favicon.ico">
6
- <meta charset="UTF-8">
7
- <title>Janito Light Editor</title>
8
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/codemirror.min.css">
9
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/theme/dracula.min.css">
10
- <link rel="stylesheet" href="/static/termweb.css">
11
- <link rel="stylesheet" href="/static/editor.css">
12
- </head>
13
- <body>
14
- <div class="header">
15
- <div class="header-title">Janito Light Editor</div>
16
- <span id="filename-display" class="filename-display"></span>
17
- <div style="flex:1 1 auto;"></div>
18
- <button class="theme-switcher" id="theme-switcher" title="Alternator tema">
19
- <span id="theme-icon" aria-label="Switch theme" style="pointer-events:none;">🌙</span>
20
- </button>
21
- </div>
22
- <div class="main">
23
- <div class="editor-pane">
24
- <textarea id="code" name="code"></textarea>
25
- <div id="save-popup" style="display:none;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);z-index:9999;background:#323b4c;color:#fff;padding:14px 28px;border-radius:8px;box-shadow:0 2px 12px #0007;font-size:1.1em;">Saved!</div>
26
- </div>
27
- </div>
28
- <div class="footer">
29
- <button class="save-btn" id="save-btn">Save</button>
30
-
31
- </div>
32
- <div id="save-popup" style="display:none;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);z-index:9999;background:#323b4c;color:#fff;padding:14px 28px;border-radius:8px;box-shadow:0 2px 12px #0007;font-size:1.1em;">Saved!</div>
33
- <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/codemirror.min.js"></script>
34
- <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/mode/python/python.min.js"></script>
35
- <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/mode/django/django.min.js"></script>
36
- <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/theme/dracula.min.js"></script>
37
- <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/addon/selection/active-line.min.js"></script>
38
- <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/addon/search/search.min.js"></script>
39
- <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/addon/search/searchcursor.min.js"></script>
40
- <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/addon/dialog/dialog.min.js"></script>
41
- <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/addon/mode/overlay.min.js"></script>
42
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/addon/dialog/dialog.min.css">
43
-
44
- <script src="/static/editor.js"></script>
45
- </body>
46
- </html>
@@ -1,265 +0,0 @@
1
- // --- Load file content via AJAX if ?path=... is present ---
2
- function getQueryParam(name) {
3
- const url = new URL(window.location.href);
4
- return url.searchParams.get(name);
5
- }
6
- const filePath = getQueryParam('path');
7
-
8
- // Updates the theme icon based on the current theme
9
- function updateThemeIcon() {
10
- var icon = document.getElementById('theme-icon');
11
- if (!icon) return;
12
- if (document.body.classList.contains('light-theme')) {
13
- icon.textContent = '☀️'; // Sun for light mode
14
- icon.title = 'Switch to dark mode';
15
- } else {
16
- icon.textContent = '🌙'; // Moon for dark mode
17
- icon.title = 'Switch to light mode';
18
- }
19
- }
20
-
21
- document.addEventListener('DOMContentLoaded', function() {
22
- // Display filename in header if present
23
- if (filePath) {
24
- const filename = filePath.split(/[\\\/]/).pop();
25
- const filenameDisplay = document.getElementById('filename-display');
26
- if (filenameDisplay) {
27
- filenameDisplay.textContent = '— ' + filePath;
28
- filenameDisplay.title = filePath;
29
- }
30
- }
31
-
32
- let initialContent = "";
33
- if (filePath) {
34
- fetch(`/api/explorer/${encodeURIComponent(filePath)}`)
35
- .then(resp => resp.json())
36
- .then(data => {
37
- if (data.type === 'file') {
38
- initialContent = data.content;
39
- if (window.editorInstance) {
40
- window.editorInstance.setValue(initialContent);
41
- }
42
- } else if (data.error) {
43
- initialContent = '# Error: ' + data.error;
44
- if (window.editorInstance) {
45
- window.editorInstance.setValue(initialContent);
46
- }
47
- }
48
- })
49
- .catch(err => {
50
- initialContent = '# Error ao carregar arquivo: ' + err;
51
- if (window.editorInstance) {
52
- window.editorInstance.setValue(initialContent);
53
- }
54
- });
55
- }
56
-
57
- // --- Detect file extension and set CodeMirror mode ---
58
- function detectMode(filename) {
59
- if (!filename) return 'python';
60
- const ext = filename.split('.').pop().toLowerCase();
61
- const map = {
62
- 'py': 'python',
63
- 'js': 'javascript',
64
- 'json': 'javascript',
65
- 'md': 'markdown',
66
- 'html': {name: 'htmlmixed', scriptingModeSpec: 'django'},
67
- 'htm': {name: 'htmlmixed', scriptingModeSpec: 'django'},
68
- 'jinja': 'django',
69
- 'j2': 'django',
70
- 'jinja2': 'django',
71
- 'css': 'css',
72
- 'sh': 'shell',
73
- 'bash': 'shell',
74
- 'yml': 'yaml',
75
- 'yaml': 'yaml',
76
- };
77
- return map[ext] || 'python';
78
- }
79
- var initialMode = detectMode(filePath);
80
- var editorInstance = CodeMirror.fromTextArea(document.getElementById('code'), {
81
- lineNumbers: true,
82
- mode: initialMode,
83
- theme: 'dracula',
84
- indentUnit: 4,
85
- tabSize: 4,
86
- styleActiveLine: true,
87
- });
88
- // If file loaded later, update mode
89
- if (filePath) {
90
- const mode = detectMode(filePath);
91
- editorInstance.setOption('mode', mode);
92
- }
93
- window.editorInstance = editorInstance;
94
-
95
-
96
- // Add Ctrl-F handler for find
97
- editorInstance.addKeyMap({
98
- 'Ctrl-F': function(cm) {
99
- cm.execCommand('find');
100
- },
101
- 'Cmd-F': function(cm) {
102
- cm.execCommand('find');
103
- },
104
- 'Ctrl-S': function(cm) {
105
- document.getElementById('save-btn').click();
106
- // Prevent default browser save dialog
107
- return false;
108
- },
109
- 'Cmd-S': function(cm) {
110
- document.getElementById('save-btn').click();
111
- return false;
112
- },
113
- 'Alt-W': function(cm) {
114
- const current = cm.getOption('lineWrapping');
115
- cm.setOption('lineWrapping', !current);
116
- }
117
- });
118
- // --- Custom floating find navigation panel ---
119
- function createFindPanel() {
120
- let panel = document.getElementById('find-nav-panel');
121
- if (!panel) {
122
- panel = document.createElement('div');
123
- panel.id = 'find-nav-panel';
124
- panel.style.position = 'absolute';
125
- panel.style.top = '70px';
126
- panel.style.right = '30px';
127
- panel.style.zIndex = 200;
128
- panel.style.background = 'rgba(40,42,54,0.98)';
129
- panel.style.color = '#fff';
130
- panel.style.borderRadius = '6px';
131
- panel.style.boxShadow = '0 2px 8px #0008';
132
- panel.style.padding = '4px 10px 4px 8px';
133
- panel.style.display = 'flex';
134
- panel.style.alignItems = 'center';
135
- panel.style.gap = '8px';
136
- panel.style.fontSize = '1em';
137
- panel.style.userSelect = 'none';
138
- panel.innerHTML = `
139
- <button id="find-prev-btn" title="Previous match" style="background:none;border:none;color:#fff;font-size:1.2em;cursor:pointer;">⏮️</button>
140
- <span id="find-match-info">1/1</span>
141
- <button id="find-next-btn" title="Next match" style="background:none;border:none;color:#fff;font-size:1.2em;cursor:pointer;">⏭️</button>
142
- `;
143
- document.body.appendChild(panel);
144
- }
145
- return panel;
146
- }
147
- function removeFindPanel() {
148
- let panel = document.getElementById('find-nav-panel');
149
- if (panel) panel.remove();
150
- }
151
- // Hook into CodeMirror search dialog
152
- let lastSearchState = null;
153
- function updateFindPanel(cm) {
154
- let state = cm.state.search;
155
- if (!state || !state.query) {
156
- removeFindPanel();
157
- return;
158
- }
159
- let matches = 0, current = 0;
160
- if (state.overlay && state.overlay.matches) {
161
- matches = state.overlay.matches.length;
162
- current = state.overlay.matches.findIndex(m => m.from && cm.getCursor().line === m.from.line && cm.getCursor().ch >= m.from.ch && cm.getCursor().ch <= m.to.ch) + 1;
163
- }
164
- // fallback: count marked text
165
- if (!matches) {
166
- let marks = cm.getAllMarks();
167
- let found = marks.filter(m => m.className && m.className.includes('cm-searching'));
168
- matches = found.length;
169
- let cur = cm.getCursor();
170
- current = found.findIndex(m => {
171
- let pos = m.find();
172
- return pos && pos.from.line === cur.line && cur.ch >= pos.from.ch && cur.ch <= pos.to.ch;
173
- }) + 1;
174
- }
175
- if (!matches) matches = 1;
176
- if (!current) current = 1;
177
- createFindPanel();
178
- document.getElementById('find-match-info').textContent = `${current}/${matches}`;
179
- }
180
- editorInstance.on('cursorActivity', function(cm) {
181
- updateFindPanel(cm);
182
- });
183
- editorInstance.on('search', function(cm) {
184
- updateFindPanel(cm);
185
- });
186
- // Listen for dialog open/close
187
- let observer = new MutationObserver(function() {
188
- let dialogs = document.querySelectorAll('.CodeMirror-dialog');
189
- if (dialogs.length) {
190
- setTimeout(() => updateFindPanel(editorInstance), 100);
191
- } else {
192
- removeFindPanel();
193
- }
194
- });
195
- observer.observe(document.body, { childList: true, subtree: true });
196
- // Button handlers
197
- document.body.addEventListener('click', function(e) {
198
- if (e.target && e.target.id === 'find-next-btn') {
199
- editorInstance.execCommand('findNext');
200
- } else if (e.target && e.target.id === 'find-prev-btn') {
201
- editorInstance.execCommand('findPrev');
202
- }
203
- });
204
- // --- END custom find panel ---
205
- // Dynamically calculate available height
206
- function resizeEditor() {
207
- var header = document.querySelector('.header');
208
- var headerHeight = header ? header.offsetHeight : 0;
209
- var availableHeight = window.innerHeight - headerHeight;
210
- editorInstance.setSize('100%', availableHeight + 'px');
211
- }
212
- window.addEventListener('resize', resizeEditor);
213
- setTimeout(resizeEditor, 0);
214
- editorInstance.setValue(initialContent);
215
- updateThemeIcon();
216
-
217
- // Set initial state
218
- document.body.classList.remove('light-theme');
219
- editorInstance.setOption('theme', 'dracula');
220
- updateThemeIcon();
221
-
222
- // Theme switch button logic
223
- var themeSwitcher = document.getElementById('theme-switcher');
224
- if (themeSwitcher) {
225
- themeSwitcher.addEventListener('click', function() {
226
- var isLight = document.body.classList.toggle('light-theme');
227
- if (isLight) {
228
- editorInstance.setOption('theme', 'default');
229
- } else {
230
- editorInstance.setOption('theme', 'dracula');
231
- }
232
- updateThemeIcon();
233
- });
234
- }
235
- // Botão de Gravar
236
- var saveBtn = document.getElementById('save-btn');
237
- saveBtn.addEventListener('click', function() {
238
- if (!filePath) {
239
- alert('Nenhum arquivo aberto para gravar.');
240
- return;
241
- }
242
- const content = editorInstance.getValue();
243
- fetch(`/api/explorer/${encodeURIComponent(filePath)}`, {
244
- method: 'POST',
245
- headers: {
246
- 'Content-Type': 'application/json',
247
- },
248
- body: JSON.stringify({ content }),
249
- })
250
- .then(resp => resp.json())
251
- .then(data => {
252
- if (data.success) {
253
- // Show popup
254
- var popup = document.getElementById('save-popup');
255
- popup.style.display = 'block';
256
- setTimeout(() => { popup.style.display = 'none'; }, 1500);
257
- } else {
258
- alert('Error saving: ' + (data.error || 'desconhecido'));
259
- }
260
- })
261
- .catch(err => {
262
- alert('Error saving: ' + err);
263
- });
264
- });
265
- });
@@ -1,259 +0,0 @@
1
- // --- Load file content via AJAX if ?path=... is present ---
2
- function getQueryParam(name) {
3
- const url = new URL(window.location.href);
4
- return url.searchParams.get(name);
5
- }
6
- const filePath = getQueryParam('path');
7
-
8
- // Updates the theme icon based on the current theme
9
- function updateThemeIcon() {
10
- var icon = document.getElementById('theme-icon');
11
- if (!icon) return;
12
- if (document.body.classList.contains('light-theme')) {
13
- icon.textContent = '☀️'; // Sun for light mode
14
- icon.title = 'Switch to dark mode';
15
- } else {
16
- icon.textContent = '🌙'; // Moon for dark mode
17
- icon.title = 'Switch to light mode';
18
- }
19
- }
20
-
21
- document.addEventListener('DOMContentLoaded', function() {
22
- // Display filename in header if present
23
- if (filePath) {
24
- const filename = filePath.split(/[\\\/]/).pop();
25
- const filenameDisplay = document.getElementById('filename-display');
26
- if (filenameDisplay) {
27
- filenameDisplay.textContent = '— ' + filePath;
28
- filenameDisplay.title = filePath;
29
- }
30
- }
31
-
32
- let initialContent = "";
33
- if (filePath) {
34
- fetch(`/api/explorer/${encodeURIComponent(filePath)}`)
35
- .then(resp => resp.json())
36
- .then(data => {
37
- if (data.type === 'file') {
38
- initialContent = data.content;
39
- if (window.editorInstance) {
40
- window.editorInstance.setValue(initialContent);
41
- }
42
- } else if (data.error) {
43
- initialContent = '# Error: ' + data.error;
44
- if (window.editorInstance) {
45
- window.editorInstance.setValue(initialContent);
46
- }
47
- }
48
- })
49
- .catch(err => {
50
- initialContent = '# Error ao carregar arquivo: ' + err;
51
- if (window.editorInstance) {
52
- window.editorInstance.setValue(initialContent);
53
- }
54
- });
55
- }
56
-
57
- // --- Detect file extension and set CodeMirror mode ---
58
- function detectMode(filename) {
59
- if (!filename) return 'python';
60
- const ext = filename.split('.').pop().toLowerCase();
61
- const map = {
62
- 'py': 'python',
63
- 'js': 'javascript',
64
- 'json': 'javascript',
65
- 'md': 'markdown',
66
- 'html': {name: 'htmlmixed', scriptingModeSpec: 'django'},
67
- 'htm': {name: 'htmlmixed', scriptingModeSpec: 'django'},
68
- 'jinja': 'django',
69
- 'j2': 'django',
70
- 'jinja2': 'django',
71
- 'css': 'css',
72
- 'sh': 'shell',
73
- 'bash': 'shell',
74
- 'yml': 'yaml',
75
- 'yaml': 'yaml',
76
- };
77
- return map[ext] || 'python';
78
- }
79
- var initialMode = detectMode(filePath);
80
- var editorInstance = CodeMirror.fromTextArea(document.getElementById('code'), {
81
- lineNumbers: true,
82
- mode: initialMode,
83
- theme: 'dracula',
84
- indentUnit: 4,
85
- tabSize: 4,
86
- styleActiveLine: true,
87
- });
88
- // If file loaded later, update mode
89
- if (filePath) {
90
- const mode = detectMode(filePath);
91
- editorInstance.setOption('mode', mode);
92
- }
93
- window.editorInstance = editorInstance;
94
- // Add Ctrl-F handler for find
95
- editorInstance.addKeyMap({
96
- 'Ctrl-F': function(cm) {
97
- cm.execCommand('find');
98
- },
99
- 'Cmd-F': function(cm) {
100
- cm.execCommand('find');
101
- },
102
- 'Ctrl-S': function(cm) {
103
- document.getElementById('save-btn').click();
104
- // Prevent default browser save dialog
105
- return false;
106
- },
107
- 'Cmd-S': function(cm) {
108
- document.getElementById('save-btn').click();
109
- return false;
110
- }
111
- });
112
- // --- Custom floating find navigation panel ---
113
- function createFindPanel() {
114
- let panel = document.getElementById('find-nav-panel');
115
- if (!panel) {
116
- panel = document.createElement('div');
117
- panel.id = 'find-nav-panel';
118
- panel.style.position = 'absolute';
119
- panel.style.top = '70px';
120
- panel.style.right = '30px';
121
- panel.style.zIndex = 200;
122
- panel.style.background = 'rgba(40,42,54,0.98)';
123
- panel.style.color = '#fff';
124
- panel.style.borderRadius = '6px';
125
- panel.style.boxShadow = '0 2px 8px #0008';
126
- panel.style.padding = '4px 10px 4px 8px';
127
- panel.style.display = 'flex';
128
- panel.style.alignItems = 'center';
129
- panel.style.gap = '8px';
130
- panel.style.fontSize = '1em';
131
- panel.style.userSelect = 'none';
132
- panel.innerHTML = `
133
- <button id="find-prev-btn" title="Previous match" style="background:none;border:none;color:#fff;font-size:1.2em;cursor:pointer;">⏮️</button>
134
- <span id="find-match-info">1/1</span>
135
- <button id="find-next-btn" title="Next match" style="background:none;border:none;color:#fff;font-size:1.2em;cursor:pointer;">⏭️</button>
136
- `;
137
- document.body.appendChild(panel);
138
- }
139
- return panel;
140
- }
141
- function removeFindPanel() {
142
- let panel = document.getElementById('find-nav-panel');
143
- if (panel) panel.remove();
144
- }
145
- // Hook into CodeMirror search dialog
146
- let lastSearchState = null;
147
- function updateFindPanel(cm) {
148
- let state = cm.state.search;
149
- if (!state || !state.query) {
150
- removeFindPanel();
151
- return;
152
- }
153
- let matches = 0, current = 0;
154
- if (state.overlay && state.overlay.matches) {
155
- matches = state.overlay.matches.length;
156
- current = state.overlay.matches.findIndex(m => m.from && cm.getCursor().line === m.from.line && cm.getCursor().ch >= m.from.ch && cm.getCursor().ch <= m.to.ch) + 1;
157
- }
158
- // fallback: count marked text
159
- if (!matches) {
160
- let marks = cm.getAllMarks();
161
- let found = marks.filter(m => m.className && m.className.includes('cm-searching'));
162
- matches = found.length;
163
- let cur = cm.getCursor();
164
- current = found.findIndex(m => {
165
- let pos = m.find();
166
- return pos && pos.from.line === cur.line && cur.ch >= pos.from.ch && cur.ch <= pos.to.ch;
167
- }) + 1;
168
- }
169
- if (!matches) matches = 1;
170
- if (!current) current = 1;
171
- createFindPanel();
172
- document.getElementById('find-match-info').textContent = `${current}/${matches}`;
173
- }
174
- editorInstance.on('cursorActivity', function(cm) {
175
- updateFindPanel(cm);
176
- });
177
- editorInstance.on('search', function(cm) {
178
- updateFindPanel(cm);
179
- });
180
- // Listen for dialog open/close
181
- let observer = new MutationObserver(function() {
182
- let dialogs = document.querySelectorAll('.CodeMirror-dialog');
183
- if (dialogs.length) {
184
- setTimeout(() => updateFindPanel(editorInstance), 100);
185
- } else {
186
- removeFindPanel();
187
- }
188
- });
189
- observer.observe(document.body, { childList: true, subtree: true });
190
- // Button handlers
191
- document.body.addEventListener('click', function(e) {
192
- if (e.target && e.target.id === 'find-next-btn') {
193
- editorInstance.execCommand('findNext');
194
- } else if (e.target && e.target.id === 'find-prev-btn') {
195
- editorInstance.execCommand('findPrev');
196
- }
197
- });
198
- // --- END custom find panel ---
199
- // Dynamically calculate available height
200
- function resizeEditor() {
201
- var header = document.querySelector('.header');
202
- var headerHeight = header ? header.offsetHeight : 0;
203
- var availableHeight = window.innerHeight - headerHeight;
204
- editorInstance.setSize('100%', availableHeight + 'px');
205
- }
206
- window.addEventListener('resize', resizeEditor);
207
- setTimeout(resizeEditor, 0);
208
- editorInstance.setValue(initialContent);
209
- updateThemeIcon();
210
-
211
- // Set initial state
212
- document.body.classList.remove('light-theme');
213
- editorInstance.setOption('theme', 'dracula');
214
- updateThemeIcon();
215
-
216
- // Theme switch button logic
217
- var themeSwitcher = document.getElementById('theme-switcher');
218
- if (themeSwitcher) {
219
- themeSwitcher.addEventListener('click', function() {
220
- var isLight = document.body.classList.toggle('light-theme');
221
- if (isLight) {
222
- editorInstance.setOption('theme', 'default');
223
- } else {
224
- editorInstance.setOption('theme', 'dracula');
225
- }
226
- updateThemeIcon();
227
- });
228
- }
229
- // Botão de Gravar
230
- var saveBtn = document.getElementById('save-btn');
231
- saveBtn.addEventListener('click', function() {
232
- if (!filePath) {
233
- alert('Nenhum arquivo aberto para gravar.');
234
- return;
235
- }
236
- const content = editorInstance.getValue();
237
- fetch(`/api/explorer/${encodeURIComponent(filePath)}`, {
238
- method: 'POST',
239
- headers: {
240
- 'Content-Type': 'application/json',
241
- },
242
- body: JSON.stringify({ content }),
243
- })
244
- .then(resp => resp.json())
245
- .then(data => {
246
- if (data.success) {
247
- // Show popup
248
- var popup = document.getElementById('save-popup');
249
- popup.style.display = 'block';
250
- setTimeout(() => { popup.style.display = 'none'; }, 1500);
251
- } else {
252
- alert('Error saving: ' + (data.error || 'desconhecido'));
253
- }
254
- })
255
- .catch(err => {
256
- alert('Error saving: ' + err);
257
- });
258
- });
259
- });
@@ -1,59 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <link rel="icon" type="image/svg+xml" href="/static/termicon.svg">
5
- <link rel="shortcut icon" type="image/x-icon" href="/static/favicon.ico">
6
- <meta charset="UTF-8">
7
- <title>TermWeb File Explorer &mdash; janito.dev</title>
8
- <link rel="stylesheet" href="/static/termweb.css">
9
- </head>
10
- <body>
11
- <div class="header">
12
- TermWeb File Explorer
13
- <button class="theme-switcher" id="theme-switcher">Switch to Light Theme</button>
14
- </div>
15
- <div class="toolbar" id="explorer-toolbar">
16
- <button id="view-list" class="view-toggle active" title="List View">&#9776;</button>
17
- <button id="view-icons" class="view-toggle" title="Icon View">&#9632;</button>
18
- </div>
19
- <div class="main" id="explorer-main">
20
- <!-- Directory/File browser will be injected here -->
21
- </div>
22
- <div class="footer">
23
- <div class="subtitle">
24
- Powered by <a href="https://janito.dev" target="_blank">janito.dev</a> &mdash; AI-powered coding agent
25
- </div>
26
- <ul>
27
- <li>🌐 <a href="https://janito.dev" target="_blank">janito.dev</a></li>
28
- <li>📚 <a href="https://docs.janito.dev" target="_blank">Documentation</a></li>
29
- <li>💻 <a href="https://github.com/joaompinto/janito" target="_blank">GitHub</a></li>
30
- </ul>
31
- <span style="font-size:0.9em;opacity:0.7;">_generated by janito.dev_</span>
32
- </div>
33
- <script src="/static/termweb.js"></script>
34
- <script>
35
- // Theme switcher logic
36
- function setTheme(dark) {
37
- if (dark) {
38
- document.body.classList.add('dark-theme');
39
- document.body.classList.remove('light-theme');
40
- localStorage.setItem('theme', 'dark');
41
- document.getElementById('theme-switcher').textContent = 'Switch to Light Theme';
42
- } else {
43
- document.body.classList.remove('dark-theme');
44
- document.body.classList.add('light-theme');
45
- localStorage.setItem('theme', 'light');
46
- document.getElementById('theme-switcher').textContent = 'Switch to Dark Theme';
47
- }
48
- }
49
- document.addEventListener('DOMContentLoaded', function() {
50
- // Initial theme
51
- var theme = localStorage.getItem('theme') || 'dark';
52
- setTheme(theme === 'dark');
53
- document.getElementById('theme-switcher').onclick = function() {
54
- setTheme(document.body.classList.contains('light-theme'));
55
- };
56
- });
57
- </script>
58
- </body>
59
- </html>