pythinker-code 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.
- pythinker_code/CHANGELOG.md +16 -0
- pythinker_code/__init__.py +0 -0
- pythinker_code/__main__.py +92 -0
- pythinker_code/acp/AGENTS.md +93 -0
- pythinker_code/acp/__init__.py +13 -0
- pythinker_code/acp/convert.py +128 -0
- pythinker_code/acp/host.py +298 -0
- pythinker_code/acp/mcp.py +46 -0
- pythinker_code/acp/server.py +497 -0
- pythinker_code/acp/session.py +496 -0
- pythinker_code/acp/tools.py +167 -0
- pythinker_code/acp/types.py +13 -0
- pythinker_code/acp/version.py +45 -0
- pythinker_code/agents/default/agent.yaml +36 -0
- pythinker_code/agents/default/coder.yaml +25 -0
- pythinker_code/agents/default/explore.yaml +46 -0
- pythinker_code/agents/default/plan.yaml +30 -0
- pythinker_code/agents/default/system.md +164 -0
- pythinker_code/agents/okabe/agent.yaml +22 -0
- pythinker_code/agentspec.py +163 -0
- pythinker_code/app.py +820 -0
- pythinker_code/approval_runtime/__init__.py +29 -0
- pythinker_code/approval_runtime/models.py +42 -0
- pythinker_code/approval_runtime/runtime.py +235 -0
- pythinker_code/auth/__init__.py +25 -0
- pythinker_code/auth/anthropic_direct.py +207 -0
- pythinker_code/auth/deepseek.py +192 -0
- pythinker_code/auth/lm_studio.py +418 -0
- pythinker_code/auth/minimax.py +203 -0
- pythinker_code/auth/oauth.py +1122 -0
- pythinker_code/auth/ollama.py +293 -0
- pythinker_code/auth/openai.py +771 -0
- pythinker_code/auth/opencode_go.py +203 -0
- pythinker_code/auth/openrouter.py +225 -0
- pythinker_code/auth/platforms.py +466 -0
- pythinker_code/background/__init__.py +36 -0
- pythinker_code/background/agent_runner.py +231 -0
- pythinker_code/background/ids.py +19 -0
- pythinker_code/background/manager.py +650 -0
- pythinker_code/background/models.py +105 -0
- pythinker_code/background/store.py +237 -0
- pythinker_code/background/summary.py +66 -0
- pythinker_code/background/worker.py +209 -0
- pythinker_code/cli/__init__.py +1326 -0
- pythinker_code/cli/__main__.py +19 -0
- pythinker_code/cli/_lazy_group.py +238 -0
- pythinker_code/cli/export.py +322 -0
- pythinker_code/cli/info.py +62 -0
- pythinker_code/cli/mcp.py +349 -0
- pythinker_code/cli/plugin.py +351 -0
- pythinker_code/cli/toad.py +74 -0
- pythinker_code/cli/vis.py +38 -0
- pythinker_code/cli/web.py +80 -0
- pythinker_code/config.py +453 -0
- pythinker_code/constant.py +33 -0
- pythinker_code/exception.py +43 -0
- pythinker_code/hooks/__init__.py +4 -0
- pythinker_code/hooks/config.py +34 -0
- pythinker_code/hooks/engine.py +371 -0
- pythinker_code/hooks/events.py +190 -0
- pythinker_code/hooks/runner.py +89 -0
- pythinker_code/llm.py +412 -0
- pythinker_code/metadata.py +79 -0
- pythinker_code/notifications/__init__.py +33 -0
- pythinker_code/notifications/llm.py +77 -0
- pythinker_code/notifications/manager.py +145 -0
- pythinker_code/notifications/models.py +50 -0
- pythinker_code/notifications/notifier.py +41 -0
- pythinker_code/notifications/store.py +118 -0
- pythinker_code/notifications/wire.py +21 -0
- pythinker_code/plugin/__init__.py +124 -0
- pythinker_code/plugin/manager.py +153 -0
- pythinker_code/plugin/tool.py +173 -0
- pythinker_code/prompts/__init__.py +6 -0
- pythinker_code/prompts/compact.md +73 -0
- pythinker_code/prompts/init.md +21 -0
- pythinker_code/py.typed +0 -0
- pythinker_code/session.py +319 -0
- pythinker_code/session_fork.py +325 -0
- pythinker_code/session_state.py +132 -0
- pythinker_code/share.py +14 -0
- pythinker_code/skill/__init__.py +727 -0
- pythinker_code/skill/flow/__init__.py +99 -0
- pythinker_code/skill/flow/d2.py +482 -0
- pythinker_code/skill/flow/mermaid.py +266 -0
- pythinker_code/skills/pythinker-code-help/SKILL.md +54 -0
- pythinker_code/skills/skill-creator/SKILL.md +367 -0
- pythinker_code/soul/__init__.py +304 -0
- pythinker_code/soul/agent.py +520 -0
- pythinker_code/soul/approval.py +267 -0
- pythinker_code/soul/btw.py +214 -0
- pythinker_code/soul/compaction.py +189 -0
- pythinker_code/soul/context.py +339 -0
- pythinker_code/soul/denwarenji.py +39 -0
- pythinker_code/soul/dynamic_injection.py +84 -0
- pythinker_code/soul/dynamic_injections/__init__.py +0 -0
- pythinker_code/soul/dynamic_injections/auto_mode.py +72 -0
- pythinker_code/soul/dynamic_injections/plan_mode.py +239 -0
- pythinker_code/soul/message.py +92 -0
- pythinker_code/soul/pythinkersoul.py +1613 -0
- pythinker_code/soul/slash.py +340 -0
- pythinker_code/soul/toolset.py +788 -0
- pythinker_code/subagents/__init__.py +21 -0
- pythinker_code/subagents/builder.py +42 -0
- pythinker_code/subagents/core.py +86 -0
- pythinker_code/subagents/git_context.py +172 -0
- pythinker_code/subagents/models.py +54 -0
- pythinker_code/subagents/output.py +71 -0
- pythinker_code/subagents/registry.py +28 -0
- pythinker_code/subagents/runner.py +428 -0
- pythinker_code/subagents/store.py +196 -0
- pythinker_code/telemetry/__init__.py +211 -0
- pythinker_code/telemetry/config.py +54 -0
- pythinker_code/telemetry/crash.py +157 -0
- pythinker_code/telemetry/metrics.py +208 -0
- pythinker_code/telemetry/otel.py +240 -0
- pythinker_code/telemetry/sentry.py +167 -0
- pythinker_code/telemetry/sink.py +189 -0
- pythinker_code/tools/AGENTS.md +6 -0
- pythinker_code/tools/__init__.py +105 -0
- pythinker_code/tools/agent/__init__.py +277 -0
- pythinker_code/tools/agent/description.md +41 -0
- pythinker_code/tools/ask_user/__init__.py +159 -0
- pythinker_code/tools/ask_user/description.md +19 -0
- pythinker_code/tools/background/__init__.py +318 -0
- pythinker_code/tools/background/list.md +10 -0
- pythinker_code/tools/background/output.md +11 -0
- pythinker_code/tools/background/stop.md +8 -0
- pythinker_code/tools/display.py +46 -0
- pythinker_code/tools/dmail/__init__.py +38 -0
- pythinker_code/tools/dmail/dmail.md +17 -0
- pythinker_code/tools/file/__init__.py +30 -0
- pythinker_code/tools/file/glob.md +17 -0
- pythinker_code/tools/file/glob.py +160 -0
- pythinker_code/tools/file/grep.md +6 -0
- pythinker_code/tools/file/grep_local.py +589 -0
- pythinker_code/tools/file/plan_mode.py +45 -0
- pythinker_code/tools/file/read.md +16 -0
- pythinker_code/tools/file/read.py +300 -0
- pythinker_code/tools/file/read_media.md +24 -0
- pythinker_code/tools/file/read_media.py +217 -0
- pythinker_code/tools/file/replace.md +7 -0
- pythinker_code/tools/file/replace.py +195 -0
- pythinker_code/tools/file/utils.py +257 -0
- pythinker_code/tools/file/write.md +5 -0
- pythinker_code/tools/file/write.py +177 -0
- pythinker_code/tools/plan/__init__.py +327 -0
- pythinker_code/tools/plan/description.md +29 -0
- pythinker_code/tools/plan/enter.py +190 -0
- pythinker_code/tools/plan/enter_description.md +35 -0
- pythinker_code/tools/plan/heroes.py +277 -0
- pythinker_code/tools/shell/__init__.py +253 -0
- pythinker_code/tools/shell/bash.md +35 -0
- pythinker_code/tools/shell/powershell.md +30 -0
- pythinker_code/tools/test.py +55 -0
- pythinker_code/tools/think/__init__.py +21 -0
- pythinker_code/tools/think/think.md +1 -0
- pythinker_code/tools/todo/__init__.py +168 -0
- pythinker_code/tools/todo/set_todo_list.md +23 -0
- pythinker_code/tools/utils.py +199 -0
- pythinker_code/tools/web/__init__.py +4 -0
- pythinker_code/tools/web/fetch.md +1 -0
- pythinker_code/tools/web/fetch.py +189 -0
- pythinker_code/tools/web/search.md +1 -0
- pythinker_code/tools/web/search.py +163 -0
- pythinker_code/ui/__init__.py +0 -0
- pythinker_code/ui/acp/__init__.py +99 -0
- pythinker_code/ui/print/__init__.py +474 -0
- pythinker_code/ui/print/visualize.py +185 -0
- pythinker_code/ui/shell/__init__.py +1696 -0
- pythinker_code/ui/shell/console.py +109 -0
- pythinker_code/ui/shell/debug.py +190 -0
- pythinker_code/ui/shell/echo.py +17 -0
- pythinker_code/ui/shell/export_import.py +117 -0
- pythinker_code/ui/shell/keyboard.py +300 -0
- pythinker_code/ui/shell/mcp_status.py +113 -0
- pythinker_code/ui/shell/model_picker.py +318 -0
- pythinker_code/ui/shell/oauth.py +272 -0
- pythinker_code/ui/shell/placeholders.py +531 -0
- pythinker_code/ui/shell/prompt.py +2278 -0
- pythinker_code/ui/shell/replay.py +215 -0
- pythinker_code/ui/shell/session_picker.py +227 -0
- pythinker_code/ui/shell/setup.py +212 -0
- pythinker_code/ui/shell/slash.py +898 -0
- pythinker_code/ui/shell/startup.py +32 -0
- pythinker_code/ui/shell/task_browser.py +486 -0
- pythinker_code/ui/shell/update.py +350 -0
- pythinker_code/ui/shell/usage.py +291 -0
- pythinker_code/ui/shell/usage_adapters/__init__.py +50 -0
- pythinker_code/ui/shell/usage_adapters/anthropic_admin.py +233 -0
- pythinker_code/ui/shell/usage_adapters/base.py +72 -0
- pythinker_code/ui/shell/usage_adapters/deepseek.py +137 -0
- pythinker_code/ui/shell/usage_adapters/minimax.py +236 -0
- pythinker_code/ui/shell/usage_adapters/openai_admin.py +225 -0
- pythinker_code/ui/shell/usage_adapters/openai_chatgpt.py +241 -0
- pythinker_code/ui/shell/usage_adapters/opencode_go.py +232 -0
- pythinker_code/ui/shell/usage_adapters/openrouter.py +105 -0
- pythinker_code/ui/shell/usage_adapters/pythinker.py +189 -0
- pythinker_code/ui/shell/usage_adapters/pythinker_ai.py +50 -0
- pythinker_code/ui/shell/usage_render.py +150 -0
- pythinker_code/ui/shell/visualize/__init__.py +165 -0
- pythinker_code/ui/shell/visualize/_approval_panel.py +505 -0
- pythinker_code/ui/shell/visualize/_blocks.py +629 -0
- pythinker_code/ui/shell/visualize/_btw_panel.py +224 -0
- pythinker_code/ui/shell/visualize/_input_router.py +48 -0
- pythinker_code/ui/shell/visualize/_interactive.py +523 -0
- pythinker_code/ui/shell/visualize/_live_view.py +826 -0
- pythinker_code/ui/shell/visualize/_question_panel.py +586 -0
- pythinker_code/ui/theme.py +241 -0
- pythinker_code/usage_ratelimit_cache.py +175 -0
- pythinker_code/utils/__init__.py +0 -0
- pythinker_code/utils/aiohttp.py +24 -0
- pythinker_code/utils/aioqueue.py +72 -0
- pythinker_code/utils/broadcast.py +37 -0
- pythinker_code/utils/changelog.py +108 -0
- pythinker_code/utils/clipboard.py +246 -0
- pythinker_code/utils/datetime.py +64 -0
- pythinker_code/utils/diff.py +135 -0
- pythinker_code/utils/editor.py +91 -0
- pythinker_code/utils/environment.py +73 -0
- pythinker_code/utils/envvar.py +22 -0
- pythinker_code/utils/export.py +696 -0
- pythinker_code/utils/file_filter.py +375 -0
- pythinker_code/utils/frontmatter.py +70 -0
- pythinker_code/utils/io.py +27 -0
- pythinker_code/utils/logging.py +146 -0
- pythinker_code/utils/media_tags.py +29 -0
- pythinker_code/utils/message.py +24 -0
- pythinker_code/utils/path.py +199 -0
- pythinker_code/utils/proctitle.py +33 -0
- pythinker_code/utils/proxy.py +31 -0
- pythinker_code/utils/pyinstaller.py +45 -0
- pythinker_code/utils/rich/__init__.py +33 -0
- pythinker_code/utils/rich/columns.py +99 -0
- pythinker_code/utils/rich/diff_render.py +481 -0
- pythinker_code/utils/rich/markdown.py +900 -0
- pythinker_code/utils/rich/markdown_sample.md +108 -0
- pythinker_code/utils/rich/markdown_sample_short.md +2 -0
- pythinker_code/utils/rich/syntax.py +114 -0
- pythinker_code/utils/sensitive.py +54 -0
- pythinker_code/utils/server.py +121 -0
- pythinker_code/utils/signals.py +43 -0
- pythinker_code/utils/slashcmd.py +124 -0
- pythinker_code/utils/string.py +41 -0
- pythinker_code/utils/subprocess_env.py +73 -0
- pythinker_code/utils/term.py +168 -0
- pythinker_code/utils/typing.py +20 -0
- pythinker_code/vis/__init__.py +0 -0
- pythinker_code/vis/api/__init__.py +5 -0
- pythinker_code/vis/api/sessions.py +687 -0
- pythinker_code/vis/api/statistics.py +209 -0
- pythinker_code/vis/api/system.py +19 -0
- pythinker_code/vis/app.py +175 -0
- pythinker_code/vis/static/assets/highlighted-body-B3W2YXNL-D2MTYyJz.js +1 -0
- pythinker_code/vis/static/assets/index-CezafTt_.js +185 -0
- pythinker_code/vis/static/assets/index-DSRInNnm.css +1 -0
- pythinker_code/vis/static/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
- pythinker_code/vis/static/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
- pythinker_code/vis/static/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
- pythinker_code/vis/static/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
- pythinker_code/vis/static/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
- pythinker_code/vis/static/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
- pythinker_code/vis/static/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
- pythinker_code/vis/static/index.html +17 -0
- pythinker_code/web/__init__.py +5 -0
- pythinker_code/web/api/__init__.py +15 -0
- pythinker_code/web/api/config.py +208 -0
- pythinker_code/web/api/open_in.py +199 -0
- pythinker_code/web/api/sessions.py +1225 -0
- pythinker_code/web/app.py +451 -0
- pythinker_code/web/auth.py +191 -0
- pythinker_code/web/models.py +98 -0
- pythinker_code/web/runner/__init__.py +5 -0
- pythinker_code/web/runner/messages.py +57 -0
- pythinker_code/web/runner/process.py +754 -0
- pythinker_code/web/runner/worker.py +97 -0
- pythinker_code/web/static/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- pythinker_code/web/static/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- pythinker_code/web/static/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- pythinker_code/web/static/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- pythinker_code/web/static/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- pythinker_code/web/static/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- pythinker_code/web/static/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- pythinker_code/web/static/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- pythinker_code/web/static/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- pythinker_code/web/static/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- pythinker_code/web/static/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- pythinker_code/web/static/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- pythinker_code/web/static/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- pythinker_code/web/static/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- pythinker_code/web/static/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- pythinker_code/web/static/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- pythinker_code/web/static/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- pythinker_code/web/static/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- pythinker_code/web/static/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- pythinker_code/web/static/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- pythinker_code/web/static/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- pythinker_code/web/static/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- pythinker_code/web/static/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- pythinker_code/web/static/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- pythinker_code/web/static/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- pythinker_code/web/static/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- pythinker_code/web/static/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- pythinker_code/web/static/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- pythinker_code/web/static/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- pythinker_code/web/static/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- pythinker_code/web/static/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- pythinker_code/web/static/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- pythinker_code/web/static/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- pythinker_code/web/static/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- pythinker_code/web/static/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- pythinker_code/web/static/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- pythinker_code/web/static/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- pythinker_code/web/static/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- pythinker_code/web/static/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- pythinker_code/web/static/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- pythinker_code/web/static/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- pythinker_code/web/static/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- pythinker_code/web/static/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- pythinker_code/web/static/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- pythinker_code/web/static/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- pythinker_code/web/static/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- pythinker_code/web/static/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- pythinker_code/web/static/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- pythinker_code/web/static/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- pythinker_code/web/static/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- pythinker_code/web/static/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- pythinker_code/web/static/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- pythinker_code/web/static/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- pythinker_code/web/static/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- pythinker_code/web/static/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- pythinker_code/web/static/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- pythinker_code/web/static/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- pythinker_code/web/static/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- pythinker_code/web/static/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- pythinker_code/web/static/assets/_baseUniq--dyU3g5v.js +1 -0
- pythinker_code/web/static/assets/abap-BdImnpbu.js +1 -0
- pythinker_code/web/static/assets/actionscript-3-CfeIJUat.js +1 -0
- pythinker_code/web/static/assets/ada-bCR0ucgS.js +1 -0
- pythinker_code/web/static/assets/andromeeda-C-Jbm3Hp.js +1 -0
- pythinker_code/web/static/assets/angular-html-CU67Zn6k.js +1 -0
- pythinker_code/web/static/assets/angular-ts-BwZT4LLn.js +1 -0
- pythinker_code/web/static/assets/apache-Pmp26Uib.js +1 -0
- pythinker_code/web/static/assets/apex-D8_7TLub.js +1 -0
- pythinker_code/web/static/assets/apl-dKokRX4l.js +1 -0
- pythinker_code/web/static/assets/applescript-Co6uUVPk.js +1 -0
- pythinker_code/web/static/assets/ara-BRHolxvo.js +1 -0
- pythinker_code/web/static/assets/arc-DkMjLpYa.js +1 -0
- pythinker_code/web/static/assets/architectureDiagram-VXUJARFQ-CHWVaGo9.js +36 -0
- pythinker_code/web/static/assets/asciidoc-Dv7Oe6Be.js +1 -0
- pythinker_code/web/static/assets/asm-D_Q5rh1f.js +1 -0
- pythinker_code/web/static/assets/astro-CbQHKStN.js +1 -0
- pythinker_code/web/static/assets/aurora-x-D-2ljcwZ.js +1 -0
- pythinker_code/web/static/assets/awk-DMzUqQB5.js +1 -0
- pythinker_code/web/static/assets/ayu-dark-CmMr59Fi.js +1 -0
- pythinker_code/web/static/assets/ballerina-BFfxhgS-.js +1 -0
- pythinker_code/web/static/assets/bat-BkioyH1T.js +1 -0
- pythinker_code/web/static/assets/beancount-k_qm7-4y.js +1 -0
- pythinker_code/web/static/assets/berry-uYugtg8r.js +1 -0
- pythinker_code/web/static/assets/bibtex-CHM0blh-.js +1 -0
- pythinker_code/web/static/assets/bicep-Bmn6On1c.js +1 -0
- pythinker_code/web/static/assets/blade-D4QpJJKB.js +1 -0
- pythinker_code/web/static/assets/blockDiagram-VD42YOAC-DzdKe497.js +122 -0
- pythinker_code/web/static/assets/bsl-BO_Y6i37.js +1 -0
- pythinker_code/web/static/assets/c-BIGW1oBm.js +1 -0
- pythinker_code/web/static/assets/c3-VCDPK7BO.js +1 -0
- pythinker_code/web/static/assets/c4Diagram-YG6GDRKO-D84Blotg.js +10 -0
- pythinker_code/web/static/assets/cadence-Bv_4Rxtq.js +1 -0
- pythinker_code/web/static/assets/cairo-KRGpt6FW.js +1 -0
- pythinker_code/web/static/assets/catppuccin-frappe-DFWUc33u.js +1 -0
- pythinker_code/web/static/assets/catppuccin-latte-C9dUb6Cb.js +1 -0
- pythinker_code/web/static/assets/catppuccin-macchiato-DQyhUUbL.js +1 -0
- pythinker_code/web/static/assets/catppuccin-mocha-D87Tk5Gz.js +1 -0
- pythinker_code/web/static/assets/channel-CllSjjdl.js +1 -0
- pythinker_code/web/static/assets/chunk-4BX2VUAB-C9w8wleE.js +1 -0
- pythinker_code/web/static/assets/chunk-55IACEB6-YlYJ8HnF.js +1 -0
- pythinker_code/web/static/assets/chunk-B4BG7PRW-Bwtz_AHU.js +165 -0
- pythinker_code/web/static/assets/chunk-DI55MBZ5-BbEHkl8h.js +220 -0
- pythinker_code/web/static/assets/chunk-FMBD7UC4-BKPbvjLC.js +15 -0
- pythinker_code/web/static/assets/chunk-QN33PNHL-D73dQvKf.js +1 -0
- pythinker_code/web/static/assets/chunk-QZHKN3VN-zGiLKes_.js +1 -0
- pythinker_code/web/static/assets/chunk-TZMSLE5B-LHJCi2fy.js +1 -0
- pythinker_code/web/static/assets/clarity-D53aC0YG.js +1 -0
- pythinker_code/web/static/assets/classDiagram-2ON5EDUG-vX27iZwa.js +1 -0
- pythinker_code/web/static/assets/classDiagram-v2-WZHVMYZB-vX27iZwa.js +1 -0
- pythinker_code/web/static/assets/clojure-P80f7IUj.js +1 -0
- pythinker_code/web/static/assets/clone-DYBkaPm2.js +1 -0
- pythinker_code/web/static/assets/cmake-D1j8_8rp.js +1 -0
- pythinker_code/web/static/assets/cobol-nwyudZeR.js +1 -0
- pythinker_code/web/static/assets/code-block-IT6T5CEO-NtKViZGl.js +2 -0
- pythinker_code/web/static/assets/codeowners-Bp6g37R7.js +1 -0
- pythinker_code/web/static/assets/codeql-DsOJ9woJ.js +1 -0
- pythinker_code/web/static/assets/coffee-Ch7k5sss.js +1 -0
- pythinker_code/web/static/assets/common-lisp-Cg-RD9OK.js +1 -0
- pythinker_code/web/static/assets/coq-DkFqJrB1.js +1 -0
- pythinker_code/web/static/assets/cose-bilkent-S5V4N54A-DialjZpd.js +1 -0
- pythinker_code/web/static/assets/cpp-CofmeUqb.js +1 -0
- pythinker_code/web/static/assets/crystal-tKQVLTB8.js +1 -0
- pythinker_code/web/static/assets/csharp-K5feNrxe.js +1 -0
- pythinker_code/web/static/assets/css-DPfMkruS.js +1 -0
- pythinker_code/web/static/assets/csv-fuZLfV_i.js +1 -0
- pythinker_code/web/static/assets/cue-D82EKSYY.js +1 -0
- pythinker_code/web/static/assets/cypher-COkxafJQ.js +1 -0
- pythinker_code/web/static/assets/cytoscape.esm-C_Fzpdck.js +321 -0
- pythinker_code/web/static/assets/d-85-TOEBH.js +1 -0
- pythinker_code/web/static/assets/dagre-6UL2VRFP-DfuvkZZ7.js +4 -0
- pythinker_code/web/static/assets/dark-plus-C3mMm8J8.js +1 -0
- pythinker_code/web/static/assets/dart-CF10PKvl.js +1 -0
- pythinker_code/web/static/assets/dax-CEL-wOlO.js +1 -0
- pythinker_code/web/static/assets/defaultLocale-DX6XiGOO.js +1 -0
- pythinker_code/web/static/assets/desktop-BmXAJ9_W.js +1 -0
- pythinker_code/web/static/assets/diagram-PSM6KHXK-DLGctX3v.js +24 -0
- pythinker_code/web/static/assets/diagram-QEK2KX5R-DnxN6S0F.js +43 -0
- pythinker_code/web/static/assets/diagram-S2PKOQOG-Caq_Set9.js +24 -0
- pythinker_code/web/static/assets/diff-D97Zzqfu.js +1 -0
- pythinker_code/web/static/assets/docker-BcOcwvcX.js +1 -0
- pythinker_code/web/static/assets/dotenv-Da5cRb03.js +1 -0
- pythinker_code/web/static/assets/dracula-BzJJZx-M.js +1 -0
- pythinker_code/web/static/assets/dracula-soft-BXkSAIEj.js +1 -0
- pythinker_code/web/static/assets/dream-maker-BtqSS_iP.js +1 -0
- pythinker_code/web/static/assets/edge-BkV0erSs.js +1 -0
- pythinker_code/web/static/assets/elixir-CDX3lj18.js +1 -0
- pythinker_code/web/static/assets/elm-DbKCFpqz.js +1 -0
- pythinker_code/web/static/assets/emacs-lisp-C9XAeP06.js +1 -0
- pythinker_code/web/static/assets/erDiagram-Q2GNP2WA-BgTfALoK.js +60 -0
- pythinker_code/web/static/assets/erb-BOJIQeun.js +1 -0
- pythinker_code/web/static/assets/erlang-DsQrWhSR.js +1 -0
- pythinker_code/web/static/assets/everforest-dark-BgDCqdQA.js +1 -0
- pythinker_code/web/static/assets/everforest-light-C8M2exoo.js +1 -0
- pythinker_code/web/static/assets/fennel-BYunw83y.js +1 -0
- pythinker_code/web/static/assets/fish-BvzEVeQv.js +1 -0
- pythinker_code/web/static/assets/flowDiagram-NV44I4VS-QjW_fnGi.js +162 -0
- pythinker_code/web/static/assets/fluent-C4IJs8-o.js +1 -0
- pythinker_code/web/static/assets/fortran-fixed-form-CkoXwp7k.js +1 -0
- pythinker_code/web/static/assets/fortran-free-form-BxgE0vQu.js +1 -0
- pythinker_code/web/static/assets/fsharp-CXgrBDvD.js +1 -0
- pythinker_code/web/static/assets/ganttDiagram-JELNMOA3-fqi8JFof.js +267 -0
- pythinker_code/web/static/assets/gdresource-B7Tvp0Sc.js +1 -0
- pythinker_code/web/static/assets/gdscript-DTMYz4Jt.js +1 -0
- pythinker_code/web/static/assets/gdshader-DkwncUOv.js +1 -0
- pythinker_code/web/static/assets/genie-D0YGMca9.js +1 -0
- pythinker_code/web/static/assets/gherkin-DyxjwDmM.js +1 -0
- pythinker_code/web/static/assets/git-commit-F4YmCXRG.js +1 -0
- pythinker_code/web/static/assets/git-rebase-r7XF79zn.js +1 -0
- pythinker_code/web/static/assets/gitGraphDiagram-NY62KEGX-i7o6VQ8x.js +65 -0
- pythinker_code/web/static/assets/github-dark-DHJKELXO.js +1 -0
- pythinker_code/web/static/assets/github-dark-default-Cuk6v7N8.js +1 -0
- pythinker_code/web/static/assets/github-dark-dimmed-DH5Ifo-i.js +1 -0
- pythinker_code/web/static/assets/github-dark-high-contrast-E3gJ1_iC.js +1 -0
- pythinker_code/web/static/assets/github-light-DAi9KRSo.js +1 -0
- pythinker_code/web/static/assets/github-light-default-D7oLnXFd.js +1 -0
- pythinker_code/web/static/assets/github-light-high-contrast-BfjtVDDH.js +1 -0
- pythinker_code/web/static/assets/gleam-BspZqrRM.js +1 -0
- pythinker_code/web/static/assets/glimmer-js-Rg0-pVw9.js +1 -0
- pythinker_code/web/static/assets/glimmer-ts-U6CK756n.js +1 -0
- pythinker_code/web/static/assets/glsl-DplSGwfg.js +1 -0
- pythinker_code/web/static/assets/gn-n2N0HUVH.js +1 -0
- pythinker_code/web/static/assets/gnuplot-DdkO51Og.js +1 -0
- pythinker_code/web/static/assets/go-Dn2_MT6a.js +1 -0
- pythinker_code/web/static/assets/graph-C0vZK2pT.js +1 -0
- pythinker_code/web/static/assets/graphql-ChdNCCLP.js +1 -0
- pythinker_code/web/static/assets/groovy-gcz8RCvz.js +1 -0
- pythinker_code/web/static/assets/gruvbox-dark-hard-CFHQjOhq.js +1 -0
- pythinker_code/web/static/assets/gruvbox-dark-medium-GsRaNv29.js +1 -0
- pythinker_code/web/static/assets/gruvbox-dark-soft-CVdnzihN.js +1 -0
- pythinker_code/web/static/assets/gruvbox-light-hard-CH1njM8p.js +1 -0
- pythinker_code/web/static/assets/gruvbox-light-medium-DRw_LuNl.js +1 -0
- pythinker_code/web/static/assets/gruvbox-light-soft-hJgmCMqR.js +1 -0
- pythinker_code/web/static/assets/hack-CaT9iCJl.js +1 -0
- pythinker_code/web/static/assets/haml-B8DHNrY2.js +1 -0
- pythinker_code/web/static/assets/handlebars-BL8al0AC.js +1 -0
- pythinker_code/web/static/assets/haskell-Df6bDoY_.js +1 -0
- pythinker_code/web/static/assets/haxe-CzTSHFRz.js +1 -0
- pythinker_code/web/static/assets/hcl-BWvSN4gD.js +1 -0
- pythinker_code/web/static/assets/hjson-D5-asLiD.js +1 -0
- pythinker_code/web/static/assets/hlsl-D3lLCCz7.js +1 -0
- pythinker_code/web/static/assets/houston-DnULxvSX.js +1 -0
- pythinker_code/web/static/assets/html-GMplVEZG.js +1 -0
- pythinker_code/web/static/assets/html-derivative-BFtXZ54Q.js +1 -0
- pythinker_code/web/static/assets/http-jrhK8wxY.js +1 -0
- pythinker_code/web/static/assets/hurl-irOxFIW8.js +1 -0
- pythinker_code/web/static/assets/hxml-Bvhsp5Yf.js +1 -0
- pythinker_code/web/static/assets/hy-DFXneXwc.js +1 -0
- pythinker_code/web/static/assets/imba-DGztddWO.js +1 -0
- pythinker_code/web/static/assets/index-BYCCk6-K.js +153 -0
- pythinker_code/web/static/assets/index-BpoLgcEt.js +1 -0
- pythinker_code/web/static/assets/index-Cpy4G3uJ.js +2 -0
- pythinker_code/web/static/assets/index-CzV_vCfu.css +1 -0
- pythinker_code/web/static/assets/index-DI2oedCt.js +19 -0
- pythinker_code/web/static/assets/index-DdIkp80K.js +5 -0
- pythinker_code/web/static/assets/infoDiagram-WHAUD3N6-BMPpeZSM.js +2 -0
- pythinker_code/web/static/assets/ini-BEwlwnbL.js +1 -0
- pythinker_code/web/static/assets/init-Gi6I4Gst.js +1 -0
- pythinker_code/web/static/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
- pythinker_code/web/static/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
- pythinker_code/web/static/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
- pythinker_code/web/static/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
- pythinker_code/web/static/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
- pythinker_code/web/static/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
- pythinker_code/web/static/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
- pythinker_code/web/static/assets/java-CylS5w8V.js +1 -0
- pythinker_code/web/static/assets/javascript-wDzz0qaB.js +1 -0
- pythinker_code/web/static/assets/jinja-4LBKfQ-Z.js +1 -0
- pythinker_code/web/static/assets/jison-wvAkD_A8.js +1 -0
- pythinker_code/web/static/assets/journeyDiagram-XKPGCS4Q-DAM7gngo.js +139 -0
- pythinker_code/web/static/assets/json-Cp-IABpG.js +1 -0
- pythinker_code/web/static/assets/json5-C9tS-k6U.js +1 -0
- pythinker_code/web/static/assets/jsonc-Des-eS-w.js +1 -0
- pythinker_code/web/static/assets/jsonl-DcaNXYhu.js +1 -0
- pythinker_code/web/static/assets/jsonnet-DFQXde-d.js +1 -0
- pythinker_code/web/static/assets/jssm-C2t-YnRu.js +1 -0
- pythinker_code/web/static/assets/jsx-g9-lgVsj.js +1 -0
- pythinker_code/web/static/assets/julia-CxzCAyBv.js +1 -0
- pythinker_code/web/static/assets/kanagawa-dragon-CkXjmgJE.js +1 -0
- pythinker_code/web/static/assets/kanagawa-lotus-CfQXZHmo.js +1 -0
- pythinker_code/web/static/assets/kanagawa-wave-DWedfzmr.js +1 -0
- pythinker_code/web/static/assets/kanban-definition-3W4ZIXB7-ChpBpV0k.js +89 -0
- pythinker_code/web/static/assets/katex-D2lIc1rk.css +1 -0
- pythinker_code/web/static/assets/kdl-DV7GczEv.js +1 -0
- pythinker_code/web/static/assets/kotlin-BdnUsdx6.js +1 -0
- pythinker_code/web/static/assets/kusto-DZf3V79B.js +1 -0
- pythinker_code/web/static/assets/laserwave-DUszq2jm.js +1 -0
- pythinker_code/web/static/assets/latex-B4uzh10-.js +1 -0
- pythinker_code/web/static/assets/layout-C3Jp1gKO.js +1 -0
- pythinker_code/web/static/assets/lean-BZvkOJ9d.js +1 -0
- pythinker_code/web/static/assets/less-B1dDrJ26.js +1 -0
- pythinker_code/web/static/assets/light-plus-B7mTdjB0.js +1 -0
- pythinker_code/web/static/assets/linear-BGHtL1N4.js +1 -0
- pythinker_code/web/static/assets/liquid-DYVedYrR.js +1 -0
- pythinker_code/web/static/assets/llvm-BtvRca6l.js +1 -0
- pythinker_code/web/static/assets/log-2UxHyX5q.js +1 -0
- pythinker_code/web/static/assets/logo-BtOb2qkB.js +1 -0
- pythinker_code/web/static/assets/lua-BbnMAYS6.js +1 -0
- pythinker_code/web/static/assets/luau-C-HG3fhB.js +1 -0
- pythinker_code/web/static/assets/make-CHLpvVh8.js +1 -0
- pythinker_code/web/static/assets/markdown-Cvjx9yec.js +1 -0
- pythinker_code/web/static/assets/marko-DZsq8hO1.js +1 -0
- pythinker_code/web/static/assets/material-theme-D5KoaKCx.js +1 -0
- pythinker_code/web/static/assets/material-theme-darker-BfHTSMKl.js +1 -0
- pythinker_code/web/static/assets/material-theme-lighter-B0m2ddpp.js +1 -0
- pythinker_code/web/static/assets/material-theme-ocean-CyktbL80.js +1 -0
- pythinker_code/web/static/assets/material-theme-palenight-Csfq5Kiy.js +1 -0
- pythinker_code/web/static/assets/matlab-D7o27uSR.js +1 -0
- pythinker_code/web/static/assets/mdc-DUICxH0z.js +1 -0
- pythinker_code/web/static/assets/mdx-Cmh6b_Ma.js +1 -0
- pythinker_code/web/static/assets/mermaid-VLURNSYL-B2P5VJ9v.css +1 -0
- pythinker_code/web/static/assets/mermaid-VLURNSYL-C_HW6koB.js +465 -0
- pythinker_code/web/static/assets/mermaid-mWjccvbQ.js +1 -0
- pythinker_code/web/static/assets/mermaid.core-CnT4VrPC.js +191 -0
- pythinker_code/web/static/assets/min-Dn5VRVmX.js +1 -0
- pythinker_code/web/static/assets/min-dark-CafNBF8u.js +1 -0
- pythinker_code/web/static/assets/min-light-CTRr51gU.js +1 -0
- pythinker_code/web/static/assets/mindmap-definition-VGOIOE7T-x8EwhfIt.js +68 -0
- pythinker_code/web/static/assets/mipsasm-CKIfxQSi.js +1 -0
- pythinker_code/web/static/assets/mojo-B93PlW-d.js +1 -0
- pythinker_code/web/static/assets/monokai-D4h5O-jR.js +1 -0
- pythinker_code/web/static/assets/moonbit-Ba13S78F.js +1 -0
- pythinker_code/web/static/assets/move-Bu9oaDYs.js +1 -0
- pythinker_code/web/static/assets/narrat-DRg8JJMk.js +1 -0
- pythinker_code/web/static/assets/nextflow-BrzmwbiE.js +1 -0
- pythinker_code/web/static/assets/nginx-DknmC5AR.js +1 -0
- pythinker_code/web/static/assets/night-owl-C39BiMTA.js +1 -0
- pythinker_code/web/static/assets/nim-CVrawwO9.js +1 -0
- pythinker_code/web/static/assets/nix-CwoSXNpI.js +1 -0
- pythinker_code/web/static/assets/nord-Ddv68eIx.js +1 -0
- pythinker_code/web/static/assets/nushell-C-sUppwS.js +1 -0
- pythinker_code/web/static/assets/objective-c-DXmwc3jG.js +1 -0
- pythinker_code/web/static/assets/objective-cpp-CLxacb5B.js +1 -0
- pythinker_code/web/static/assets/ocaml-C0hk2d4L.js +1 -0
- pythinker_code/web/static/assets/one-dark-pro-DVMEJ2y_.js +1 -0
- pythinker_code/web/static/assets/one-light-PoHY5YXO.js +1 -0
- pythinker_code/web/static/assets/openscad-C4EeE6gA.js +1 -0
- pythinker_code/web/static/assets/ordinal-Cboi1Yqb.js +1 -0
- pythinker_code/web/static/assets/pascal-D93ZcfNL.js +1 -0
- pythinker_code/web/static/assets/perl-C0TMdlhV.js +1 -0
- pythinker_code/web/static/assets/php-CDn_0X-4.js +1 -0
- pythinker_code/web/static/assets/pieDiagram-ADFJNKIX-DgxBKGz2.js +30 -0
- pythinker_code/web/static/assets/pkl-u5AG7uiY.js +1 -0
- pythinker_code/web/static/assets/plastic-3e1v2bzS.js +1 -0
- pythinker_code/web/static/assets/plsql-ChMvpjG-.js +1 -0
- pythinker_code/web/static/assets/po-BTJTHyun.js +1 -0
- pythinker_code/web/static/assets/poimandres-CS3Unz2-.js +1 -0
- pythinker_code/web/static/assets/polar-C0HS_06l.js +1 -0
- pythinker_code/web/static/assets/postcss-CXtECtnM.js +1 -0
- pythinker_code/web/static/assets/powerquery-CEu0bR-o.js +1 -0
- pythinker_code/web/static/assets/powershell-Dpen1YoG.js +1 -0
- pythinker_code/web/static/assets/prisma-Dd19v3D-.js +1 -0
- pythinker_code/web/static/assets/prolog-CbFg5uaA.js +1 -0
- pythinker_code/web/static/assets/proto-C7zT0LnQ.js +1 -0
- pythinker_code/web/static/assets/pug-CGlum2m_.js +1 -0
- pythinker_code/web/static/assets/puppet-BMWR74SV.js +1 -0
- pythinker_code/web/static/assets/purescript-CklMAg4u.js +1 -0
- pythinker_code/web/static/assets/python-B6aJPvgy.js +1 -0
- pythinker_code/web/static/assets/qml-3beO22l8.js +1 -0
- pythinker_code/web/static/assets/qmldir-C8lEn-DE.js +1 -0
- pythinker_code/web/static/assets/qss-IeuSbFQv.js +1 -0
- pythinker_code/web/static/assets/quadrantDiagram-AYHSOK5B-DSpe_dqk.js +7 -0
- pythinker_code/web/static/assets/r-Dspwwk_N.js +1 -0
- pythinker_code/web/static/assets/racket-BqYA7rlc.js +1 -0
- pythinker_code/web/static/assets/raku-DXvB9xmW.js +1 -0
- pythinker_code/web/static/assets/razor-C1TweQQi.js +1 -0
- pythinker_code/web/static/assets/red-bN70gL4F.js +1 -0
- pythinker_code/web/static/assets/reg-C-SQnVFl.js +1 -0
- pythinker_code/web/static/assets/regexp-CDVJQ6XC.js +1 -0
- pythinker_code/web/static/assets/rel-C3B-1QV4.js +1 -0
- pythinker_code/web/static/assets/requirementDiagram-UZGBJVZJ-8o9hozL-.js +64 -0
- pythinker_code/web/static/assets/riscv-BM1_JUlF.js +1 -0
- pythinker_code/web/static/assets/rose-pine-dawn-DHQR4-dF.js +1 -0
- pythinker_code/web/static/assets/rose-pine-moon-D4_iv3hh.js +1 -0
- pythinker_code/web/static/assets/rose-pine-qdsjHGoJ.js +1 -0
- pythinker_code/web/static/assets/rosmsg-BJDFO7_C.js +1 -0
- pythinker_code/web/static/assets/rst-B0xPkSld.js +1 -0
- pythinker_code/web/static/assets/ruby-BvKwtOVI.js +1 -0
- pythinker_code/web/static/assets/rust-B1yitclQ.js +1 -0
- pythinker_code/web/static/assets/sankeyDiagram-TZEHDZUN-BLOSUixH.js +10 -0
- pythinker_code/web/static/assets/sas-cz2c8ADy.js +1 -0
- pythinker_code/web/static/assets/sass-Cj5Yp3dK.js +1 -0
- pythinker_code/web/static/assets/scala-C151Ov-r.js +1 -0
- pythinker_code/web/static/assets/scheme-C98Dy4si.js +1 -0
- pythinker_code/web/static/assets/scss-OYdSNvt2.js +1 -0
- pythinker_code/web/static/assets/sdbl-DVxCFoDh.js +1 -0
- pythinker_code/web/static/assets/sequenceDiagram-WL72ISMW-6F2G8JTU.js +145 -0
- pythinker_code/web/static/assets/shaderlab-Dg9Lc6iA.js +1 -0
- pythinker_code/web/static/assets/shellscript-Yzrsuije.js +1 -0
- pythinker_code/web/static/assets/shellsession-BADoaaVG.js +1 -0
- pythinker_code/web/static/assets/slack-dark-BthQWCQV.js +1 -0
- pythinker_code/web/static/assets/slack-ochin-DqwNpetd.js +1 -0
- pythinker_code/web/static/assets/smalltalk-BERRCDM3.js +1 -0
- pythinker_code/web/static/assets/snazzy-light-Bw305WKR.js +1 -0
- pythinker_code/web/static/assets/solarized-dark-DXbdFlpD.js +1 -0
- pythinker_code/web/static/assets/solarized-light-L9t79GZl.js +1 -0
- pythinker_code/web/static/assets/solidity-rGO070M0.js +1 -0
- pythinker_code/web/static/assets/soy-Brmx7dQM.js +1 -0
- pythinker_code/web/static/assets/sparql-rVzFXLq3.js +1 -0
- pythinker_code/web/static/assets/splunk-BtCnVYZw.js +1 -0
- pythinker_code/web/static/assets/sql-BLtJtn59.js +1 -0
- pythinker_code/web/static/assets/ssh-config-_ykCGR6B.js +1 -0
- pythinker_code/web/static/assets/stata-BH5u7GGu.js +1 -0
- pythinker_code/web/static/assets/stateDiagram-FKZM4ZOC-DP8xP0iJ.js +1 -0
- pythinker_code/web/static/assets/stateDiagram-v2-4FDKWEC3-1l6-EZNX.js +1 -0
- pythinker_code/web/static/assets/stylus-BEDo0Tqx.js +1 -0
- pythinker_code/web/static/assets/svelte-zxCyuUbr.js +1 -0
- pythinker_code/web/static/assets/swift-Dg5xB15N.js +1 -0
- pythinker_code/web/static/assets/synthwave-84-CbfX1IO0.js +1 -0
- pythinker_code/web/static/assets/system-verilog-CnnmHF94.js +1 -0
- pythinker_code/web/static/assets/systemd-4A_iFExJ.js +1 -0
- pythinker_code/web/static/assets/talonscript-CkByrt1z.js +1 -0
- pythinker_code/web/static/assets/tasl-QIJgUcNo.js +1 -0
- pythinker_code/web/static/assets/tcl-dwOrl1Do.js +1 -0
- pythinker_code/web/static/assets/templ-W15q3VgB.js +1 -0
- pythinker_code/web/static/assets/terraform-BETggiCN.js +1 -0
- pythinker_code/web/static/assets/tex-CvyZ59Mk.js +1 -0
- pythinker_code/web/static/assets/timeline-definition-IT6M3QCI-DMgruDfK.js +61 -0
- pythinker_code/web/static/assets/tokyo-night-hegEt444.js +1 -0
- pythinker_code/web/static/assets/toml-vGWfd6FD.js +1 -0
- pythinker_code/web/static/assets/treemap-KMMF4GRG-Bo9ZkrAK.js +128 -0
- pythinker_code/web/static/assets/ts-tags-zn1MmPIZ.js +1 -0
- pythinker_code/web/static/assets/tsv-B_m7g4N7.js +1 -0
- pythinker_code/web/static/assets/tsx-COt5Ahok.js +1 -0
- pythinker_code/web/static/assets/turtle-BsS91CYL.js +1 -0
- pythinker_code/web/static/assets/twig-CO9l9SDP.js +1 -0
- pythinker_code/web/static/assets/typescript-BPQ3VLAy.js +1 -0
- pythinker_code/web/static/assets/typespec-BGHnOYBU.js +1 -0
- pythinker_code/web/static/assets/typst-DHCkPAjA.js +1 -0
- pythinker_code/web/static/assets/v-BcVCzyr7.js +1 -0
- pythinker_code/web/static/assets/vala-CsfeWuGM.js +1 -0
- pythinker_code/web/static/assets/vb-D17OF-Vu.js +1 -0
- pythinker_code/web/static/assets/verilog-BQ8w6xss.js +1 -0
- pythinker_code/web/static/assets/vesper-DU1UobuO.js +1 -0
- pythinker_code/web/static/assets/vhdl-CeAyd5Ju.js +1 -0
- pythinker_code/web/static/assets/viml-CJc9bBzg.js +1 -0
- pythinker_code/web/static/assets/vitesse-black-Bkuqu6BP.js +1 -0
- pythinker_code/web/static/assets/vitesse-dark-D0r3Knsf.js +1 -0
- pythinker_code/web/static/assets/vitesse-light-CVO1_9PV.js +1 -0
- pythinker_code/web/static/assets/vue-DN_0RTcg.js +1 -0
- pythinker_code/web/static/assets/vue-html-AaS7Mt5G.js +1 -0
- pythinker_code/web/static/assets/vue-vine-CQOfvN7w.js +1 -0
- pythinker_code/web/static/assets/vyper-CDx5xZoG.js +1 -0
- pythinker_code/web/static/assets/wasm-CG6Dc4jp.js +1 -0
- pythinker_code/web/static/assets/wasm-MzD3tlZU.js +1 -0
- pythinker_code/web/static/assets/wenyan-BV7otONQ.js +1 -0
- pythinker_code/web/static/assets/wgsl-Dx-B1_4e.js +1 -0
- pythinker_code/web/static/assets/wikitext-BhOHFoWU.js +1 -0
- pythinker_code/web/static/assets/wit-5i3qLPDT.js +1 -0
- pythinker_code/web/static/assets/wolfram-lXgVvXCa.js +1 -0
- pythinker_code/web/static/assets/xml-sdJ4AIDG.js +1 -0
- pythinker_code/web/static/assets/xsl-CtQFsRM5.js +1 -0
- pythinker_code/web/static/assets/xychartDiagram-PRI3JC2R-GeF2johi.js +7 -0
- pythinker_code/web/static/assets/yaml-Buea-lGh.js +1 -0
- pythinker_code/web/static/assets/zenscript-DVFEvuxE.js +1 -0
- pythinker_code/web/static/assets/zig-VOosw3JB.js +1 -0
- pythinker_code/web/static/brand/apple-touch-icon.png +0 -0
- pythinker_code/web/static/brand/arctecture.webp +0 -0
- pythinker_code/web/static/brand/bimi-logo.svg +46 -0
- pythinker_code/web/static/brand/favicon.ico +0 -0
- pythinker_code/web/static/brand/fonts/dm-sans-latin-ext.woff2 +0 -0
- pythinker_code/web/static/brand/fonts/dm-sans-latin.woff2 +0 -0
- pythinker_code/web/static/brand/fonts/instrument-sans-latin-ext.woff2 +0 -0
- pythinker_code/web/static/brand/fonts/instrument-sans-latin.woff2 +0 -0
- pythinker_code/web/static/brand/fonts/instrument-serif-latin-ext.woff2 +0 -0
- pythinker_code/web/static/brand/fonts/instrument-serif-latin.woff2 +0 -0
- pythinker_code/web/static/brand/fonts/libre-baskerville-italic-latin-ext.woff2 +0 -0
- pythinker_code/web/static/brand/fonts/libre-baskerville-italic-latin.woff2 +0 -0
- pythinker_code/web/static/brand/fonts/libre-baskerville-latin-ext.woff2 +0 -0
- pythinker_code/web/static/brand/fonts/libre-baskerville-latin.woff2 +0 -0
- pythinker_code/web/static/brand/fonts/roboto-latin-ext.woff2 +0 -0
- pythinker_code/web/static/brand/fonts/roboto-latin.woff2 +0 -0
- pythinker_code/web/static/brand/icon-192.png +0 -0
- pythinker_code/web/static/brand/icon-512.png +0 -0
- pythinker_code/web/static/brand/icon.svg +1 -0
- pythinker_code/web/static/brand/logo.png +0 -0
- pythinker_code/web/static/brand/pythinker_animated.svg +79 -0
- pythinker_code/web/static/brand/robots.txt +4 -0
- pythinker_code/web/static/index.html +15 -0
- pythinker_code/web/static/logo.png +0 -0
- pythinker_code/web/store/__init__.py +1 -0
- pythinker_code/web/store/sessions.py +432 -0
- pythinker_code/wire/__init__.py +148 -0
- pythinker_code/wire/file.py +151 -0
- pythinker_code/wire/jsonrpc.py +263 -0
- pythinker_code/wire/protocol.py +2 -0
- pythinker_code/wire/root_hub.py +27 -0
- pythinker_code/wire/serde.py +26 -0
- pythinker_code/wire/server.py +1069 -0
- pythinker_code/wire/types.py +698 -0
- pythinker_code-2.0.0.dist-info/METADATA +660 -0
- pythinker_code-2.0.0.dist-info/RECORD +731 -0
- pythinker_code-2.0.0.dist-info/WHEEL +4 -0
- pythinker_code-2.0.0.dist-info/entry_points.txt +4 -0
- pythinker_code-2.0.0.dist-info/licenses/LICENSE +202 -0
- pythinker_code-2.0.0.dist-info/licenses/NOTICE +14 -0
|
@@ -0,0 +1,523 @@
|
|
|
1
|
+
"""Interactive prompt view for the bottom dynamic area.
|
|
2
|
+
|
|
3
|
+
``_PromptLiveView`` extends ``_LiveView`` with prompt_toolkit integration:
|
|
4
|
+
input routing (queue/steer/btw), modal management, and key handling.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
# pyright: reportPrivateUsage=false, reportUnusedClass=false
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import asyncio
|
|
12
|
+
from collections.abc import Awaitable, Callable
|
|
13
|
+
from contextlib import suppress
|
|
14
|
+
|
|
15
|
+
from prompt_toolkit.application.run_in_terminal import run_in_terminal
|
|
16
|
+
from prompt_toolkit.buffer import Buffer
|
|
17
|
+
from prompt_toolkit.document import Document
|
|
18
|
+
from prompt_toolkit.formatted_text import ANSI
|
|
19
|
+
from prompt_toolkit.key_binding import KeyPressEvent
|
|
20
|
+
from rich.console import Group, RenderableType
|
|
21
|
+
from rich.text import Text
|
|
22
|
+
|
|
23
|
+
from pythinker_code.ui.shell.console import console, render_to_ansi
|
|
24
|
+
from pythinker_code.ui.shell.echo import render_user_echo_text
|
|
25
|
+
from pythinker_code.ui.shell.keyboard import KeyEvent
|
|
26
|
+
from pythinker_code.ui.shell.prompt import (
|
|
27
|
+
CustomPromptSession,
|
|
28
|
+
UserInput,
|
|
29
|
+
)
|
|
30
|
+
from pythinker_code.ui.shell.visualize._btw_panel import _BtwModalDelegate
|
|
31
|
+
from pythinker_code.ui.shell.visualize._input_router import InputAction, classify_input
|
|
32
|
+
from pythinker_code.ui.shell.visualize._live_view import _LiveView
|
|
33
|
+
from pythinker_code.ui.shell.visualize._question_panel import (
|
|
34
|
+
QuestionPromptDelegate,
|
|
35
|
+
QuestionRequestPanel,
|
|
36
|
+
)
|
|
37
|
+
from pythinker_code.utils.aioqueue import QueueShutDown
|
|
38
|
+
from pythinker_code.wire import WireUISide
|
|
39
|
+
from pythinker_code.wire.types import (
|
|
40
|
+
BtwBegin,
|
|
41
|
+
BtwEnd,
|
|
42
|
+
ContentPart,
|
|
43
|
+
StatusUpdate,
|
|
44
|
+
SteerInput,
|
|
45
|
+
StepInterrupted,
|
|
46
|
+
TurnEnd,
|
|
47
|
+
WireMessage,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
BtwRunner = Callable[[str, Callable[[str], None] | None], Awaitable[tuple[str | None, str | None]]]
|
|
51
|
+
"""async (question, on_text_chunk) -> (response, error). Used for direct btw execution."""
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class _PromptLiveView(_LiveView):
|
|
55
|
+
"""Interactive prompt view: renders agent output above the input buffer.
|
|
56
|
+
|
|
57
|
+
Supports two modes for user input during streaming:
|
|
58
|
+
- **Queue (Enter)**: message is held and sent as a new turn after the
|
|
59
|
+
current turn completes. Queued messages are shown above the input and
|
|
60
|
+
can be recalled with ↑.
|
|
61
|
+
- **Steer (Ctrl+S)**: message is injected immediately into the running
|
|
62
|
+
turn's context. Shown permanently in the conversation flow.
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
modal_priority = 0
|
|
66
|
+
|
|
67
|
+
def __init__(
|
|
68
|
+
self,
|
|
69
|
+
initial_status: StatusUpdate,
|
|
70
|
+
*,
|
|
71
|
+
prompt_session: CustomPromptSession,
|
|
72
|
+
steer: Callable[[str | list[ContentPart]], None],
|
|
73
|
+
btw_runner: BtwRunner | None = None,
|
|
74
|
+
cancel_event: asyncio.Event | None = None,
|
|
75
|
+
show_thinking_stream: bool = False,
|
|
76
|
+
) -> None:
|
|
77
|
+
super().__init__(initial_status, cancel_event, show_thinking_stream=show_thinking_stream)
|
|
78
|
+
self._prompt_session = prompt_session
|
|
79
|
+
self._steer = steer
|
|
80
|
+
self._btw_runner = btw_runner
|
|
81
|
+
self._pending_local_steer_count: int = 0
|
|
82
|
+
self._turn_ended = False
|
|
83
|
+
self._question_modal: QuestionPromptDelegate | None = None
|
|
84
|
+
# -- Queue: messages waiting to be sent after the turn ends ----------
|
|
85
|
+
self._queued_messages: list[UserInput] = []
|
|
86
|
+
# -- BTW modal (replaces prompt line when active) --------------------
|
|
87
|
+
self._btw_modal: _BtwModalDelegate | None = None
|
|
88
|
+
self._btw_dismiss_event: asyncio.Event | None = None
|
|
89
|
+
self._btw_refresh_task: asyncio.Task[None] | None = None
|
|
90
|
+
self._btw_run_task: asyncio.Task[None] | None = None
|
|
91
|
+
|
|
92
|
+
# -- Helpers -------------------------------------------------------------
|
|
93
|
+
|
|
94
|
+
@property
|
|
95
|
+
def _btw_active(self) -> bool:
|
|
96
|
+
return self._btw_modal is not None
|
|
97
|
+
|
|
98
|
+
def _dismiss_btw(self) -> None:
|
|
99
|
+
if self._btw_modal is not None:
|
|
100
|
+
self._prompt_session.detach_modal(self._btw_modal)
|
|
101
|
+
self._btw_modal = None
|
|
102
|
+
if self._btw_run_task is not None:
|
|
103
|
+
self._btw_run_task.cancel()
|
|
104
|
+
self._btw_run_task = None
|
|
105
|
+
if self._btw_refresh_task is not None:
|
|
106
|
+
self._btw_refresh_task.cancel()
|
|
107
|
+
self._btw_refresh_task = None
|
|
108
|
+
# Wake the visualize_loop if it's waiting for user dismiss
|
|
109
|
+
if self._btw_dismiss_event is not None:
|
|
110
|
+
self._btw_dismiss_event.set()
|
|
111
|
+
self._btw_dismiss_event = None
|
|
112
|
+
self._prompt_session.invalidate()
|
|
113
|
+
|
|
114
|
+
def _start_btw(self, question: str) -> None:
|
|
115
|
+
"""Set up the btw modal and start the LLM task."""
|
|
116
|
+
import time
|
|
117
|
+
|
|
118
|
+
# Attach modal FIRST (hides input buffer), then clear buffer.
|
|
119
|
+
# This avoids a render frame between clear and attach where the
|
|
120
|
+
# user would see an empty input flash.
|
|
121
|
+
modal = _BtwModalDelegate(on_dismiss=self._dismiss_btw)
|
|
122
|
+
modal._question = question # pyright: ignore[reportPrivateUsage]
|
|
123
|
+
modal.set_start_time(time.monotonic())
|
|
124
|
+
self._btw_modal = modal
|
|
125
|
+
self._prompt_session.attach_modal(modal)
|
|
126
|
+
# Now safe to clear — buffer is hidden by modal
|
|
127
|
+
buf = self._prompt_session._session.default_buffer # pyright: ignore[reportPrivateUsage]
|
|
128
|
+
if buf.text:
|
|
129
|
+
buf.set_document(Document(), bypass_readonly=True)
|
|
130
|
+
self._btw_refresh_task = asyncio.create_task(self._btw_refresh_loop())
|
|
131
|
+
self._btw_run_task = asyncio.create_task(self._run_btw(question))
|
|
132
|
+
|
|
133
|
+
async def _run_btw(self, question: str) -> None:
|
|
134
|
+
"""Execute /btw directly via btw_runner (no wire)."""
|
|
135
|
+
assert self._btw_runner is not None
|
|
136
|
+
try:
|
|
137
|
+
|
|
138
|
+
def _on_chunk(chunk: str) -> None:
|
|
139
|
+
if self._btw_modal is not None:
|
|
140
|
+
self._btw_modal.append_text(chunk)
|
|
141
|
+
|
|
142
|
+
response, error = await self._btw_runner(question, _on_chunk)
|
|
143
|
+
if self._btw_modal is not None:
|
|
144
|
+
self._btw_modal.set_result(response, error)
|
|
145
|
+
except asyncio.CancelledError:
|
|
146
|
+
pass # dismiss cancelled us — expected
|
|
147
|
+
except Exception as e:
|
|
148
|
+
if self._btw_modal is not None:
|
|
149
|
+
self._btw_modal.set_result(None, str(e))
|
|
150
|
+
finally:
|
|
151
|
+
self._btw_run_task = None # self-clear so _dismiss_btw won't cancel a done task
|
|
152
|
+
if self._btw_refresh_task is not None:
|
|
153
|
+
self._btw_refresh_task.cancel()
|
|
154
|
+
self._btw_refresh_task = None
|
|
155
|
+
self._prompt_session.invalidate()
|
|
156
|
+
|
|
157
|
+
async def _btw_refresh_loop(self) -> None:
|
|
158
|
+
"""Periodically invalidate prompt so the spinner animates."""
|
|
159
|
+
try:
|
|
160
|
+
while True:
|
|
161
|
+
await asyncio.sleep(0.08)
|
|
162
|
+
self._prompt_session.invalidate()
|
|
163
|
+
except asyncio.CancelledError:
|
|
164
|
+
pass
|
|
165
|
+
|
|
166
|
+
# -- Public API: queued messages for the shell to drain ------------------
|
|
167
|
+
|
|
168
|
+
def drain_queued_messages(self) -> list[UserInput]:
|
|
169
|
+
"""Return and clear all queued messages (called by shell after turn)."""
|
|
170
|
+
msgs = list(self._queued_messages)
|
|
171
|
+
self._queued_messages.clear()
|
|
172
|
+
return msgs
|
|
173
|
+
|
|
174
|
+
async def wait_for_btw_dismiss(self) -> None:
|
|
175
|
+
"""Wait for btw LLM completion + user dismiss, then clean up.
|
|
176
|
+
|
|
177
|
+
Called by the shell AFTER visualize_loop returns (which must exit
|
|
178
|
+
within run_soul's 0.5s ui_task timeout). The modal is still
|
|
179
|
+
attached to prompt_session, so prompt_toolkit continues to render
|
|
180
|
+
and handle key events.
|
|
181
|
+
"""
|
|
182
|
+
if self._btw_modal is None:
|
|
183
|
+
return
|
|
184
|
+
# If LLM is still running, wait for it (user can Escape to cancel)
|
|
185
|
+
if self._btw_run_task is not None and not self._btw_run_task.done():
|
|
186
|
+
with suppress(asyncio.CancelledError):
|
|
187
|
+
await self._btw_run_task
|
|
188
|
+
# Wait for user dismiss (Escape/Enter/Space)
|
|
189
|
+
if self._btw_modal is not None: # pyright: ignore[reportUnnecessaryComparison]
|
|
190
|
+
self._btw_dismiss_event = asyncio.Event()
|
|
191
|
+
await self._btw_dismiss_event.wait()
|
|
192
|
+
# Clean up: detach modal, cancel remaining tasks
|
|
193
|
+
self._dismiss_btw()
|
|
194
|
+
|
|
195
|
+
# -- Visualize loop ------------------------------------------------------
|
|
196
|
+
|
|
197
|
+
async def visualize_loop(self, wire: WireUISide):
|
|
198
|
+
# Declare outside try so finally can always cancel them.
|
|
199
|
+
wire_task: asyncio.Task[WireMessage] | None = None
|
|
200
|
+
external_task: asyncio.Task[WireMessage] | None = None
|
|
201
|
+
try:
|
|
202
|
+
wire_task = asyncio.create_task(wire.receive())
|
|
203
|
+
external_task = asyncio.create_task(self._external_messages.get())
|
|
204
|
+
while True:
|
|
205
|
+
try:
|
|
206
|
+
done, _ = await asyncio.wait(
|
|
207
|
+
[wire_task, external_task],
|
|
208
|
+
return_when=asyncio.FIRST_COMPLETED,
|
|
209
|
+
)
|
|
210
|
+
if wire_task in done:
|
|
211
|
+
msg = wire_task.result()
|
|
212
|
+
wire_task = asyncio.create_task(wire.receive())
|
|
213
|
+
else:
|
|
214
|
+
msg = external_task.result()
|
|
215
|
+
external_task = asyncio.create_task(self._external_messages.get())
|
|
216
|
+
except QueueShutDown:
|
|
217
|
+
msg, external_task = await self._drain_external_message_after_wire_shutdown(
|
|
218
|
+
external_task
|
|
219
|
+
)
|
|
220
|
+
if msg is not None:
|
|
221
|
+
self.dispatch_wire_message(msg)
|
|
222
|
+
self._flush_prompt_refresh()
|
|
223
|
+
continue
|
|
224
|
+
self.cleanup(is_interrupt=False)
|
|
225
|
+
self._flush_prompt_refresh()
|
|
226
|
+
break
|
|
227
|
+
|
|
228
|
+
if isinstance(msg, StepInterrupted):
|
|
229
|
+
self.cleanup(is_interrupt=True)
|
|
230
|
+
self._flush_prompt_refresh()
|
|
231
|
+
break
|
|
232
|
+
|
|
233
|
+
if isinstance(msg, TurnEnd):
|
|
234
|
+
self._active_turn_depth = max(0, self._active_turn_depth - 1)
|
|
235
|
+
self._turn_ended = self._active_turn_depth == 0
|
|
236
|
+
self._flush_prompt_refresh()
|
|
237
|
+
continue
|
|
238
|
+
|
|
239
|
+
self.dispatch_wire_message(msg)
|
|
240
|
+
self._flush_prompt_refresh()
|
|
241
|
+
|
|
242
|
+
# NOTE: btw dismiss waiting is handled by the shell layer
|
|
243
|
+
# (run_soul_command → wait_for_btw_dismiss) AFTER visualize_loop
|
|
244
|
+
# returns, because run_soul gives ui_task only a 0.5s timeout.
|
|
245
|
+
finally:
|
|
246
|
+
self._external_messages.shutdown(immediate=True)
|
|
247
|
+
for task in (wire_task, external_task):
|
|
248
|
+
if task is None:
|
|
249
|
+
continue
|
|
250
|
+
task.cancel()
|
|
251
|
+
with suppress(asyncio.CancelledError, QueueShutDown):
|
|
252
|
+
await task
|
|
253
|
+
self._pending_local_steer_count = 0
|
|
254
|
+
# Do NOT dismiss btw here — the shell will call
|
|
255
|
+
# wait_for_btw_dismiss() after visualize_loop returns.
|
|
256
|
+
# Only cancel the refresh task (spinner animation stops,
|
|
257
|
+
# but modal stays attached for rendering + key handling).
|
|
258
|
+
if self._btw_refresh_task is not None:
|
|
259
|
+
self._btw_refresh_task.cancel()
|
|
260
|
+
self._btw_refresh_task = None
|
|
261
|
+
self._turn_ended = False
|
|
262
|
+
if self._question_modal is not None:
|
|
263
|
+
self._prompt_session.detach_modal(self._question_modal)
|
|
264
|
+
self._question_modal = None
|
|
265
|
+
self._prompt_session.invalidate()
|
|
266
|
+
|
|
267
|
+
# -- Input handling ------------------------------------------------------
|
|
268
|
+
|
|
269
|
+
def handle_local_input(self, user_input: UserInput) -> None:
|
|
270
|
+
"""Route user input through the unified classifier."""
|
|
271
|
+
if not user_input or self._turn_ended:
|
|
272
|
+
return
|
|
273
|
+
action = classify_input(user_input.resolved_command, is_streaming=True)
|
|
274
|
+
match action.kind:
|
|
275
|
+
case InputAction.BTW:
|
|
276
|
+
if self._btw_runner is not None and not self._btw_active:
|
|
277
|
+
self._start_btw(action.args)
|
|
278
|
+
case InputAction.QUEUE:
|
|
279
|
+
# Block shell-only commands from being queued — they would
|
|
280
|
+
# be misrouted through run_soul() instead of the shell dispatcher.
|
|
281
|
+
from pythinker_code.utils.slashcmd import parse_slash_command_call
|
|
282
|
+
|
|
283
|
+
if cmd := parse_slash_command_call(user_input.resolved_command.strip()):
|
|
284
|
+
from pythinker_code.ui.shell.slash import registry as shell_registry
|
|
285
|
+
|
|
286
|
+
if shell_registry.find_command(cmd.name) is not None:
|
|
287
|
+
from pythinker_code.ui.shell.prompt import toast
|
|
288
|
+
|
|
289
|
+
toast(
|
|
290
|
+
f"/{cmd.name} is not available during streaming",
|
|
291
|
+
topic="input-ignored",
|
|
292
|
+
duration=3.0,
|
|
293
|
+
)
|
|
294
|
+
return
|
|
295
|
+
self._queued_messages.append(user_input)
|
|
296
|
+
from pythinker_code.telemetry import track
|
|
297
|
+
|
|
298
|
+
track("input_queue")
|
|
299
|
+
# Invalidate directly — _flush_prompt_refresh() is gated by
|
|
300
|
+
# _need_recompose which may be False between wire events.
|
|
301
|
+
self._prompt_session.invalidate()
|
|
302
|
+
case InputAction.IGNORED:
|
|
303
|
+
from pythinker_code.ui.shell.prompt import toast
|
|
304
|
+
|
|
305
|
+
toast(action.args, topic="input-ignored", duration=3.0)
|
|
306
|
+
case _:
|
|
307
|
+
pass # SEND and unknown actions are no-ops during streaming
|
|
308
|
+
|
|
309
|
+
def handle_immediate_steer(self, user_input: UserInput) -> None:
|
|
310
|
+
"""Ctrl+S: inject immediately into the running turn's context."""
|
|
311
|
+
if not user_input or self._turn_ended:
|
|
312
|
+
return
|
|
313
|
+
# Intercept /btw and IGNORED (e.g. /btw without args) on Ctrl+S
|
|
314
|
+
action = classify_input(user_input.resolved_command, is_streaming=True)
|
|
315
|
+
if action.kind == InputAction.BTW:
|
|
316
|
+
if self._btw_runner is not None and not self._btw_active:
|
|
317
|
+
self._start_btw(action.args)
|
|
318
|
+
return
|
|
319
|
+
if action.kind == InputAction.IGNORED:
|
|
320
|
+
from pythinker_code.ui.shell.prompt import toast
|
|
321
|
+
|
|
322
|
+
toast(action.args, topic="input-ignored", duration=3.0)
|
|
323
|
+
return
|
|
324
|
+
# Block shell-only commands — same check as the Enter/queue path
|
|
325
|
+
from pythinker_code.utils.slashcmd import parse_slash_command_call
|
|
326
|
+
|
|
327
|
+
if cmd := parse_slash_command_call(user_input.resolved_command.strip()):
|
|
328
|
+
from pythinker_code.ui.shell.slash import registry as shell_registry
|
|
329
|
+
|
|
330
|
+
if shell_registry.find_command(cmd.name) is not None:
|
|
331
|
+
from pythinker_code.ui.shell.prompt import toast
|
|
332
|
+
|
|
333
|
+
toast(
|
|
334
|
+
f"/{cmd.name} is not available during streaming",
|
|
335
|
+
topic="input-ignored",
|
|
336
|
+
duration=3.0,
|
|
337
|
+
)
|
|
338
|
+
return
|
|
339
|
+
# Print permanently in conversation flow (shows placeholder for pasted text)
|
|
340
|
+
console.print(render_user_echo_text(user_input.command))
|
|
341
|
+
from pythinker_code.telemetry import track
|
|
342
|
+
|
|
343
|
+
track("input_steer")
|
|
344
|
+
# Track that we originated this steer locally (FIFO counter for dedup)
|
|
345
|
+
self._pending_local_steer_count += 1
|
|
346
|
+
self._steer(user_input.content)
|
|
347
|
+
self._flush_prompt_refresh()
|
|
348
|
+
|
|
349
|
+
# -- Wire event dispatch -------------------------------------------------
|
|
350
|
+
|
|
351
|
+
def dispatch_wire_message(self, msg: WireMessage) -> None:
|
|
352
|
+
# Dedup locally-originated steers: we know how many we sent,
|
|
353
|
+
# so consume the matching SteerInput events without content comparison.
|
|
354
|
+
# This avoids text vs media mismatch issues.
|
|
355
|
+
if isinstance(msg, SteerInput) and self._pending_local_steer_count > 0:
|
|
356
|
+
self._pending_local_steer_count -= 1
|
|
357
|
+
return
|
|
358
|
+
# Suppress parent's BtwBegin/BtwEnd spinner — btw is handled via modal
|
|
359
|
+
if isinstance(msg, (BtwBegin, BtwEnd)):
|
|
360
|
+
self._btw_spinner = None
|
|
361
|
+
return
|
|
362
|
+
super().dispatch_wire_message(msg)
|
|
363
|
+
|
|
364
|
+
# -- Running prompt rendering --------------------------------------------
|
|
365
|
+
|
|
366
|
+
def render_agent_status(self, columns: int) -> ANSI:
|
|
367
|
+
"""Render agent streaming output — always visible regardless of modal.
|
|
368
|
+
|
|
369
|
+
Uses ``compose_agent_output()`` (not ``compose()``) to avoid rendering
|
|
370
|
+
approval/question panels here. Those panels are rendered by their
|
|
371
|
+
respective modal delegates in Layer 2.
|
|
372
|
+
"""
|
|
373
|
+
if self._turn_ended:
|
|
374
|
+
return ANSI("")
|
|
375
|
+
blocks = self.compose_agent_output()
|
|
376
|
+
if not blocks:
|
|
377
|
+
return ANSI("")
|
|
378
|
+
body = render_to_ansi(Group(*blocks), columns=columns).rstrip("\n")
|
|
379
|
+
return ANSI(body if body else "")
|
|
380
|
+
|
|
381
|
+
def render_running_prompt_body(self, columns: int) -> ANSI:
|
|
382
|
+
"""Render the interactive part — queued messages."""
|
|
383
|
+
if not self._queued_messages:
|
|
384
|
+
return ANSI("")
|
|
385
|
+
|
|
386
|
+
blocks: list[RenderableType] = []
|
|
387
|
+
for qi in self._queued_messages:
|
|
388
|
+
blocks.append(Text(f"❯ {qi.command}", style="dim cyan"))
|
|
389
|
+
blocks.append(Text("↑ to edit · ctrl-s to send immediately", style="dim"))
|
|
390
|
+
|
|
391
|
+
body = render_to_ansi(Group(*blocks), columns=columns).rstrip("\n")
|
|
392
|
+
return ANSI(body if body else "")
|
|
393
|
+
|
|
394
|
+
def running_prompt_placeholder(self) -> str | None:
|
|
395
|
+
if self._current_approval_request_panel is not None:
|
|
396
|
+
return "Use ↑/↓ or 1/2/3, then press Enter to respond to the approval request."
|
|
397
|
+
return None
|
|
398
|
+
|
|
399
|
+
def running_prompt_hides_input_buffer(self) -> bool:
|
|
400
|
+
return False
|
|
401
|
+
|
|
402
|
+
def running_prompt_allows_text_input(self) -> bool:
|
|
403
|
+
if self._current_approval_request_panel is not None:
|
|
404
|
+
return False
|
|
405
|
+
if self._current_question_panel is not None:
|
|
406
|
+
return False
|
|
407
|
+
return not self._turn_ended
|
|
408
|
+
|
|
409
|
+
def running_prompt_accepts_submission(self) -> bool:
|
|
410
|
+
if self._current_approval_request_panel is not None:
|
|
411
|
+
return True
|
|
412
|
+
if self._current_question_panel is not None:
|
|
413
|
+
return True
|
|
414
|
+
return not self._turn_ended
|
|
415
|
+
|
|
416
|
+
# -- Key handling --------------------------------------------------------
|
|
417
|
+
|
|
418
|
+
def should_handle_running_prompt_key(self, key: str) -> bool:
|
|
419
|
+
if key == "c-e":
|
|
420
|
+
return self.has_expandable_panel()
|
|
421
|
+
if self._current_approval_request_panel is not None:
|
|
422
|
+
return key in {"up", "down", "enter", "1", "2", "3", "4"}
|
|
423
|
+
if self._turn_ended:
|
|
424
|
+
return False
|
|
425
|
+
if key == "escape":
|
|
426
|
+
return self._cancel_event is not None
|
|
427
|
+
# ↑ on empty buffer: recall last queued message.
|
|
428
|
+
# Only intercept when buffer is empty — otherwise let prompt_toolkit
|
|
429
|
+
# handle ↑ for cursor movement / history navigation.
|
|
430
|
+
if key == "up" and self._queued_messages:
|
|
431
|
+
buf = self._prompt_session._session.default_buffer # pyright: ignore[reportPrivateUsage]
|
|
432
|
+
return not buf.text.strip()
|
|
433
|
+
# Ctrl+S: immediate steer
|
|
434
|
+
return key == "c-s"
|
|
435
|
+
|
|
436
|
+
def handle_running_prompt_key(self, key: str, event: KeyPressEvent) -> None:
|
|
437
|
+
if key == "c-e":
|
|
438
|
+
event.app.create_background_task(self._show_panel_in_pager())
|
|
439
|
+
return
|
|
440
|
+
|
|
441
|
+
# ↑ on empty buffer: pop last queued message back to input for editing.
|
|
442
|
+
# should_handle already verified buffer is empty.
|
|
443
|
+
if key == "up" and self._queued_messages:
|
|
444
|
+
buf = event.current_buffer
|
|
445
|
+
recalled = self._queued_messages.pop()
|
|
446
|
+
buf.document = Document(recalled.command, len(recalled.command))
|
|
447
|
+
self._prompt_session.invalidate()
|
|
448
|
+
return
|
|
449
|
+
|
|
450
|
+
# Ctrl+S: immediate steer
|
|
451
|
+
# 1) If input has text → steer it
|
|
452
|
+
# 2) Else if queue has messages → pop first (oldest) and steer it
|
|
453
|
+
if key == "c-s":
|
|
454
|
+
buf = event.current_buffer
|
|
455
|
+
text = buf.text.strip()
|
|
456
|
+
if text:
|
|
457
|
+
steer_input = self._prompt_session._build_user_input(text) # pyright: ignore[reportPrivateUsage]
|
|
458
|
+
self._clear_buffer(buf)
|
|
459
|
+
self.handle_immediate_steer(steer_input)
|
|
460
|
+
elif self._queued_messages:
|
|
461
|
+
queued = self._queued_messages.pop(0) # FIFO: oldest first
|
|
462
|
+
self.handle_immediate_steer(queued)
|
|
463
|
+
self._flush_prompt_refresh()
|
|
464
|
+
return
|
|
465
|
+
|
|
466
|
+
mapped = {
|
|
467
|
+
"up": KeyEvent.UP,
|
|
468
|
+
"down": KeyEvent.DOWN,
|
|
469
|
+
"enter": KeyEvent.ENTER,
|
|
470
|
+
"escape": KeyEvent.ESCAPE,
|
|
471
|
+
"1": KeyEvent.NUM_1,
|
|
472
|
+
"2": KeyEvent.NUM_2,
|
|
473
|
+
"3": KeyEvent.NUM_3,
|
|
474
|
+
"4": KeyEvent.NUM_4,
|
|
475
|
+
}.get(key)
|
|
476
|
+
if mapped is None:
|
|
477
|
+
return
|
|
478
|
+
if self._current_approval_request_panel is not None:
|
|
479
|
+
self._clear_buffer(event.current_buffer)
|
|
480
|
+
self.dispatch_keyboard_event(mapped)
|
|
481
|
+
self._flush_prompt_refresh()
|
|
482
|
+
|
|
483
|
+
async def _show_panel_in_pager(self) -> None:
|
|
484
|
+
await run_in_terminal(self._show_expandable_panel_content)
|
|
485
|
+
self._prompt_session.invalidate()
|
|
486
|
+
|
|
487
|
+
@staticmethod
|
|
488
|
+
def _clear_buffer(buffer: Buffer) -> None:
|
|
489
|
+
if buffer.text:
|
|
490
|
+
buffer.document = Document(text="", cursor_position=0)
|
|
491
|
+
|
|
492
|
+
def _flush_prompt_refresh(self) -> None:
|
|
493
|
+
if self._need_recompose:
|
|
494
|
+
self._prompt_session.invalidate()
|
|
495
|
+
self._need_recompose = False
|
|
496
|
+
|
|
497
|
+
def cleanup(self, is_interrupt: bool) -> None:
|
|
498
|
+
super().cleanup(is_interrupt)
|
|
499
|
+
|
|
500
|
+
def _on_question_panel_state_changed(self) -> None:
|
|
501
|
+
panel = self._current_question_panel
|
|
502
|
+
if panel is None:
|
|
503
|
+
if self._question_modal is not None:
|
|
504
|
+
self._prompt_session.detach_modal(self._question_modal)
|
|
505
|
+
self._question_modal = None
|
|
506
|
+
return
|
|
507
|
+
if self._question_modal is None:
|
|
508
|
+
self._question_modal = QuestionPromptDelegate(
|
|
509
|
+
panel,
|
|
510
|
+
on_advance=self._advance_question,
|
|
511
|
+
on_invalidate=self._flush_prompt_refresh,
|
|
512
|
+
buffer_text_provider=lambda: self._prompt_session._session.default_buffer.text, # pyright: ignore[reportPrivateUsage]
|
|
513
|
+
text_expander=self._prompt_session._get_placeholder_manager().serialize_for_history, # pyright: ignore[reportPrivateUsage]
|
|
514
|
+
)
|
|
515
|
+
self._prompt_session.attach_modal(self._question_modal)
|
|
516
|
+
else:
|
|
517
|
+
self._question_modal.set_panel(panel)
|
|
518
|
+
self._prompt_session.invalidate()
|
|
519
|
+
|
|
520
|
+
def _advance_question(self) -> QuestionRequestPanel | None:
|
|
521
|
+
"""Advance to the next question in the queue, returning the new panel or None."""
|
|
522
|
+
self.show_next_question_request()
|
|
523
|
+
return self._current_question_panel
|