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,108 @@
|
|
|
1
|
+
# Markdown Sample Document
|
|
2
|
+
|
|
3
|
+
This is a comprehensive sample document showcasing various Markdown elements.
|
|
4
|
+
|
|
5
|
+
## Level 2 Heading
|
|
6
|
+
|
|
7
|
+
### Level 3 Heading
|
|
8
|
+
|
|
9
|
+
Here's some regular text with **bold text**, *italic text*, and `inline code`.
|
|
10
|
+
|
|
11
|
+
## Lists
|
|
12
|
+
|
|
13
|
+
### Unordered List
|
|
14
|
+
|
|
15
|
+
- First item
|
|
16
|
+
- Second item
|
|
17
|
+
- Nested item 1
|
|
18
|
+
- Nested item 2
|
|
19
|
+
- Third item
|
|
20
|
+
|
|
21
|
+
### Ordered List
|
|
22
|
+
|
|
23
|
+
1. First step
|
|
24
|
+
2. Second step
|
|
25
|
+
1. Sub-step A
|
|
26
|
+
2. Sub-step B
|
|
27
|
+
3. Third step
|
|
28
|
+
|
|
29
|
+
### Mixed List
|
|
30
|
+
|
|
31
|
+
1. First item
|
|
32
|
+
- Sub-item with bullet
|
|
33
|
+
- Another sub-item
|
|
34
|
+
2. Second item
|
|
35
|
+
1. Numbered sub-item
|
|
36
|
+
2. Another numbered sub-item
|
|
37
|
+
|
|
38
|
+
## Links and References
|
|
39
|
+
|
|
40
|
+
Here's a [link to GitHub](https://github.com) and another [relative link](../README.md).
|
|
41
|
+
|
|
42
|
+
## Code Blocks
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
def hello_world():
|
|
46
|
+
"""A simple function to demonstrate code blocks."""
|
|
47
|
+
print("Hello, World!")
|
|
48
|
+
return 42
|
|
49
|
+
|
|
50
|
+
# Call the function
|
|
51
|
+
result = hello_world()
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# Bash example
|
|
56
|
+
echo "This is a bash script"
|
|
57
|
+
ls -la /tmp
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Blockquotes
|
|
61
|
+
|
|
62
|
+
> This is a blockquote.
|
|
63
|
+
> It can span multiple lines.
|
|
64
|
+
>
|
|
65
|
+
> > And it can be nested too!
|
|
66
|
+
|
|
67
|
+
## Tables
|
|
68
|
+
|
|
69
|
+
| Column 1 | Column 2 | Column 3 |
|
|
70
|
+
|----------|----------|----------|
|
|
71
|
+
| Cell 1 | Cell 2 | Cell 3 |
|
|
72
|
+
| Left | Center | Right |
|
|
73
|
+
| Foo | Bar | Baz |
|
|
74
|
+
|
|
75
|
+
## Horizontal Rules
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
Here's some text after a horizontal rule.
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Inline Formatting
|
|
84
|
+
|
|
85
|
+
You can combine **bold and *italic*** text, or use `code` within paragraphs.
|
|
86
|
+
|
|
87
|
+
**Important**: Always test your `code` snippets before deployment.
|
|
88
|
+
|
|
89
|
+
## Advanced Features
|
|
90
|
+
|
|
91
|
+
### Task Lists
|
|
92
|
+
|
|
93
|
+
- [x] Completed task
|
|
94
|
+
- [ ] Pending task
|
|
95
|
+
- [ ] Another pending task
|
|
96
|
+
|
|
97
|
+
### Definition Lists
|
|
98
|
+
|
|
99
|
+
Term 1
|
|
100
|
+
: Definition of term 1
|
|
101
|
+
|
|
102
|
+
Term 2
|
|
103
|
+
: Definition of term 2
|
|
104
|
+
: Another definition for term 2
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
*This document demonstrates comprehensive Markdown formatting capabilities.*
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from pygments.token import (
|
|
6
|
+
Comment,
|
|
7
|
+
Generic,
|
|
8
|
+
Keyword,
|
|
9
|
+
Name,
|
|
10
|
+
Number,
|
|
11
|
+
Operator,
|
|
12
|
+
Punctuation,
|
|
13
|
+
String,
|
|
14
|
+
)
|
|
15
|
+
from pygments.token import (
|
|
16
|
+
Literal as PygmentsLiteral,
|
|
17
|
+
)
|
|
18
|
+
from pygments.token import (
|
|
19
|
+
Text as PygmentsText,
|
|
20
|
+
)
|
|
21
|
+
from pygments.token import (
|
|
22
|
+
Token as PygmentsToken,
|
|
23
|
+
)
|
|
24
|
+
from rich.style import Style
|
|
25
|
+
from rich.syntax import ANSISyntaxTheme, Syntax, SyntaxTheme
|
|
26
|
+
|
|
27
|
+
PYTHINKER_ANSI_THEME_NAME = "pythinker-ansi"
|
|
28
|
+
PYTHINKER_ANSI_THEME = ANSISyntaxTheme(
|
|
29
|
+
{
|
|
30
|
+
PygmentsToken: Style(color="default"),
|
|
31
|
+
PygmentsText: Style(color="default"),
|
|
32
|
+
Comment: Style(color="bright_black", italic=True),
|
|
33
|
+
Keyword: Style(color="magenta"),
|
|
34
|
+
Keyword.Constant: Style(color="cyan"),
|
|
35
|
+
Keyword.Declaration: Style(color="magenta"),
|
|
36
|
+
Keyword.Namespace: Style(color="magenta"),
|
|
37
|
+
Keyword.Pseudo: Style(color="magenta"),
|
|
38
|
+
Keyword.Reserved: Style(color="magenta"),
|
|
39
|
+
Keyword.Type: Style(color="magenta"),
|
|
40
|
+
Name: Style(color="default"),
|
|
41
|
+
Name.Attribute: Style(color="cyan"),
|
|
42
|
+
Name.Builtin: Style(color="bright_yellow"),
|
|
43
|
+
Name.Builtin.Pseudo: Style(color="cyan"),
|
|
44
|
+
Name.Builtin.Type: Style(color="bright_yellow", bold=True),
|
|
45
|
+
Name.Class: Style(color="bright_yellow", bold=True),
|
|
46
|
+
Name.Constant: Style(color="cyan"),
|
|
47
|
+
Name.Decorator: Style(color="bright_cyan"),
|
|
48
|
+
Name.Entity: Style(color="bright_yellow"),
|
|
49
|
+
Name.Exception: Style(color="bright_yellow", bold=True),
|
|
50
|
+
Name.Function: Style(color="bright_cyan"),
|
|
51
|
+
Name.Label: Style(color="cyan"),
|
|
52
|
+
Name.Namespace: Style(color="magenta"),
|
|
53
|
+
Name.Other: Style(color="bright_cyan"),
|
|
54
|
+
Name.Property: Style(color="cyan"),
|
|
55
|
+
Name.Tag: Style(color="bright_green"),
|
|
56
|
+
Name.Variable: Style(color="bright_yellow"),
|
|
57
|
+
PygmentsLiteral: Style(color="bright_blue"),
|
|
58
|
+
PygmentsLiteral.Date: Style(color="bright_blue"),
|
|
59
|
+
String: Style(color="bright_blue"),
|
|
60
|
+
String.Doc: Style(color="bright_blue", italic=True),
|
|
61
|
+
String.Interpol: Style(color="bright_blue"),
|
|
62
|
+
String.Affix: Style(color="cyan"),
|
|
63
|
+
Number: Style(color="cyan"),
|
|
64
|
+
Operator: Style(color="default"),
|
|
65
|
+
Operator.Word: Style(color="magenta"),
|
|
66
|
+
Punctuation: Style(color="default"),
|
|
67
|
+
Generic.Deleted: Style(color="red"),
|
|
68
|
+
Generic.Emph: Style(italic=True),
|
|
69
|
+
Generic.Error: Style(color="bright_red", bold=True),
|
|
70
|
+
Generic.Heading: Style(color="cyan", bold=True),
|
|
71
|
+
Generic.Inserted: Style(color="green"),
|
|
72
|
+
Generic.Output: Style(color="bright_black"),
|
|
73
|
+
Generic.Prompt: Style(color="bright_cyan"),
|
|
74
|
+
Generic.Strong: Style(bold=True),
|
|
75
|
+
Generic.Subheading: Style(color="cyan"),
|
|
76
|
+
Generic.Traceback: Style(color="bright_red", bold=True),
|
|
77
|
+
}
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def resolve_code_theme(theme: str | SyntaxTheme) -> str | SyntaxTheme:
|
|
82
|
+
if isinstance(theme, str) and theme.lower() == PYTHINKER_ANSI_THEME_NAME:
|
|
83
|
+
return PYTHINKER_ANSI_THEME
|
|
84
|
+
return theme
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class PythinkerSyntax(Syntax):
|
|
88
|
+
def __init__(self, code: str, lexer: str, **kwargs: Any) -> None:
|
|
89
|
+
if "theme" not in kwargs or kwargs["theme"] is None:
|
|
90
|
+
kwargs["theme"] = PYTHINKER_ANSI_THEME
|
|
91
|
+
super().__init__(code, lexer, **kwargs)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
if __name__ == "__main__":
|
|
95
|
+
from rich.console import Console
|
|
96
|
+
from rich.text import Text
|
|
97
|
+
|
|
98
|
+
console = Console()
|
|
99
|
+
|
|
100
|
+
examples = [
|
|
101
|
+
("diff", "diff", "@@ -1,2 +1,2 @@\n-line one\n+line uno\n"),
|
|
102
|
+
(
|
|
103
|
+
"python",
|
|
104
|
+
"python",
|
|
105
|
+
'def greet(name: str) -> str:\n return f"Hi, {name}!"\n',
|
|
106
|
+
),
|
|
107
|
+
("bash", "bash", "set -euo pipefail\nprintf '%s\\n' \"hello\"\n"),
|
|
108
|
+
]
|
|
109
|
+
|
|
110
|
+
for idx, (title, lexer, code) in enumerate(examples):
|
|
111
|
+
if idx:
|
|
112
|
+
console.print()
|
|
113
|
+
console.print(Text(f"[{title}]", style="bold"))
|
|
114
|
+
console.print(PythinkerSyntax(code, lexer))
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import fnmatch
|
|
4
|
+
from pathlib import PurePath
|
|
5
|
+
|
|
6
|
+
# High-confidence sensitive file patterns.
|
|
7
|
+
# Only patterns with very low false-positive risk are included.
|
|
8
|
+
SENSITIVE_PATTERNS: list[str] = [
|
|
9
|
+
# Environment variable / secrets
|
|
10
|
+
".env",
|
|
11
|
+
".env.*",
|
|
12
|
+
# SSH private keys
|
|
13
|
+
"id_rsa",
|
|
14
|
+
"id_ed25519",
|
|
15
|
+
"id_ecdsa",
|
|
16
|
+
# Cloud credentials (path-based, also bare name for stripped-path scenarios)
|
|
17
|
+
".aws/credentials",
|
|
18
|
+
".gcp/credentials",
|
|
19
|
+
"credentials",
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
# Template/example files that match .env.* but are not sensitive.
|
|
23
|
+
SENSITIVE_EXEMPTIONS: set[str] = {
|
|
24
|
+
".env.example",
|
|
25
|
+
".env.sample",
|
|
26
|
+
".env.template",
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def is_sensitive_file(path: str) -> bool:
|
|
31
|
+
"""Check if a file path matches any sensitive file pattern."""
|
|
32
|
+
name = PurePath(path).name
|
|
33
|
+
if name in SENSITIVE_EXEMPTIONS:
|
|
34
|
+
return False
|
|
35
|
+
for pattern in SENSITIVE_PATTERNS:
|
|
36
|
+
if "/" in pattern:
|
|
37
|
+
if path.endswith(pattern) or ("/" + pattern) in path:
|
|
38
|
+
return True
|
|
39
|
+
else:
|
|
40
|
+
if fnmatch.fnmatch(name, pattern):
|
|
41
|
+
return True
|
|
42
|
+
return False
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def sensitive_file_warning(paths: list[str]) -> str:
|
|
46
|
+
"""Generate a warning message for sensitive files that were skipped."""
|
|
47
|
+
names = sorted({PurePath(p).name for p in paths})
|
|
48
|
+
file_list = ", ".join(names[:5])
|
|
49
|
+
if len(names) > 5:
|
|
50
|
+
file_list += f", ... ({len(names)} files total)"
|
|
51
|
+
return (
|
|
52
|
+
f"Skipped {len(paths)} sensitive file(s) ({file_list}) "
|
|
53
|
+
f"to protect secrets. These files may contain credentials or private keys."
|
|
54
|
+
)
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"""Shared utilities for pythinker vis and pythinker web server startup."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import importlib
|
|
6
|
+
import socket
|
|
7
|
+
import textwrap
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def get_address_family(host: str) -> socket.AddressFamily:
|
|
11
|
+
"""Return AF_INET6 for IPv6 addresses, AF_INET for IPv4 and hostnames."""
|
|
12
|
+
return socket.AF_INET6 if ":" in host else socket.AF_INET
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def format_url(host: str, port: int) -> str:
|
|
16
|
+
"""Build ``http://host:port``, bracketing IPv6 literals per RFC 2732."""
|
|
17
|
+
if ":" in host:
|
|
18
|
+
return f"http://[{host}]:{port}"
|
|
19
|
+
return f"http://{host}:{port}"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def is_local_host(host: str) -> bool:
|
|
23
|
+
"""Check whether *host* resolves to a loopback address."""
|
|
24
|
+
return host in {"127.0.0.1", "localhost", "::1"}
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def find_available_port(host: str, start_port: int, max_attempts: int = 10) -> int:
|
|
28
|
+
"""Find an available port starting from *start_port*.
|
|
29
|
+
|
|
30
|
+
Raises ``RuntimeError`` if no port is available within the range.
|
|
31
|
+
"""
|
|
32
|
+
if max_attempts <= 0:
|
|
33
|
+
raise ValueError("max_attempts must be positive")
|
|
34
|
+
if start_port < 1 or start_port > 65535:
|
|
35
|
+
raise ValueError("start_port must be between 1 and 65535")
|
|
36
|
+
|
|
37
|
+
family = get_address_family(host)
|
|
38
|
+
for offset in range(max_attempts):
|
|
39
|
+
port = start_port + offset
|
|
40
|
+
with socket.socket(family, socket.SOCK_STREAM) as s:
|
|
41
|
+
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
|
42
|
+
try:
|
|
43
|
+
s.bind((host, port))
|
|
44
|
+
return port
|
|
45
|
+
except OSError:
|
|
46
|
+
continue
|
|
47
|
+
raise RuntimeError(
|
|
48
|
+
f"Cannot find available port in range {start_port}-{start_port + max_attempts - 1}"
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def get_network_addresses() -> list[str]:
|
|
53
|
+
"""Get non-loopback IPv4 addresses for this machine."""
|
|
54
|
+
addresses: list[str] = []
|
|
55
|
+
|
|
56
|
+
try:
|
|
57
|
+
hostname = socket.gethostname()
|
|
58
|
+
for info in socket.getaddrinfo(hostname, None, socket.AF_INET):
|
|
59
|
+
ip = info[4][0]
|
|
60
|
+
if isinstance(ip, str) and not ip.startswith("127.") and ip not in addresses:
|
|
61
|
+
addresses.append(ip)
|
|
62
|
+
except OSError:
|
|
63
|
+
pass
|
|
64
|
+
|
|
65
|
+
try:
|
|
66
|
+
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
|
|
67
|
+
s.connect(("8.8.8.8", 80))
|
|
68
|
+
ip = s.getsockname()[0]
|
|
69
|
+
if ip and not ip.startswith("127.") and ip not in addresses:
|
|
70
|
+
addresses.append(ip)
|
|
71
|
+
except OSError:
|
|
72
|
+
pass
|
|
73
|
+
|
|
74
|
+
try:
|
|
75
|
+
netifaces = importlib.import_module("netifaces")
|
|
76
|
+
for interface in netifaces.interfaces():
|
|
77
|
+
addrs = netifaces.ifaddresses(interface)
|
|
78
|
+
if netifaces.AF_INET in addrs:
|
|
79
|
+
for addr_info in addrs[netifaces.AF_INET]:
|
|
80
|
+
addr = addr_info.get("addr")
|
|
81
|
+
if addr and not addr.startswith("127.") and addr not in addresses:
|
|
82
|
+
addresses.append(addr)
|
|
83
|
+
except (ImportError, Exception):
|
|
84
|
+
pass
|
|
85
|
+
|
|
86
|
+
return addresses
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def print_banner(lines: list[str]) -> None:
|
|
90
|
+
"""Print a boxed banner with tag conventions (<center>, <nowrap>, <hr>)."""
|
|
91
|
+
processed: list[str] = []
|
|
92
|
+
for line in lines:
|
|
93
|
+
if line == "<hr>":
|
|
94
|
+
processed.append(line)
|
|
95
|
+
elif not line:
|
|
96
|
+
processed.append("")
|
|
97
|
+
elif line.startswith("<center>") or line.startswith("<nowrap>"):
|
|
98
|
+
processed.append(line)
|
|
99
|
+
else:
|
|
100
|
+
processed.extend(textwrap.wrap(line, width=78))
|
|
101
|
+
|
|
102
|
+
def strip_tags(s: str) -> str:
|
|
103
|
+
return s.removeprefix("<center>").removeprefix("<nowrap>")
|
|
104
|
+
|
|
105
|
+
content_lines = [strip_tags(line) for line in processed if line != "<hr>"]
|
|
106
|
+
width = max(60, *(len(line) for line in content_lines))
|
|
107
|
+
top = "+" + "=" * (width + 2) + "+"
|
|
108
|
+
|
|
109
|
+
print(top)
|
|
110
|
+
for line in processed:
|
|
111
|
+
if line == "<hr>":
|
|
112
|
+
print("|" + "-" * (width + 2) + "|")
|
|
113
|
+
elif line.startswith("<center>"):
|
|
114
|
+
content = line.removeprefix("<center>")
|
|
115
|
+
print(f"| {content.center(width)} |")
|
|
116
|
+
elif line.startswith("<nowrap>"):
|
|
117
|
+
content = line.removeprefix("<nowrap>")
|
|
118
|
+
print(f"| {content.ljust(width)} |")
|
|
119
|
+
else:
|
|
120
|
+
print(f"| {line.ljust(width)} |")
|
|
121
|
+
print(top)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import contextlib
|
|
5
|
+
import signal
|
|
6
|
+
from collections.abc import Callable
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def install_sigint_handler(
|
|
10
|
+
loop: asyncio.AbstractEventLoop, handler: Callable[[], None]
|
|
11
|
+
) -> Callable[[], None]:
|
|
12
|
+
"""
|
|
13
|
+
Install a SIGINT handler that works on Unix and Windows.
|
|
14
|
+
|
|
15
|
+
On Unix event loops, prefer `loop.add_signal_handler`.
|
|
16
|
+
On Windows (or other platforms) where it is not implemented, fall back to
|
|
17
|
+
`signal.signal`. The fallback cannot be removed from the loop, but we
|
|
18
|
+
restore the previous handler on uninstall.
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
A function that removes the installed handler. It is guaranteed that
|
|
22
|
+
no exceptions are raised when calling the returned function.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
try:
|
|
26
|
+
loop.add_signal_handler(signal.SIGINT, handler)
|
|
27
|
+
|
|
28
|
+
def remove() -> None:
|
|
29
|
+
with contextlib.suppress(RuntimeError):
|
|
30
|
+
loop.remove_signal_handler(signal.SIGINT)
|
|
31
|
+
|
|
32
|
+
return remove
|
|
33
|
+
except RuntimeError:
|
|
34
|
+
# Windows ProactorEventLoop and some environments do not support
|
|
35
|
+
# add_signal_handler. Use synchronous signal handling as a fallback.
|
|
36
|
+
previous = signal.getsignal(signal.SIGINT)
|
|
37
|
+
signal.signal(signal.SIGINT, lambda signum, frame: handler())
|
|
38
|
+
|
|
39
|
+
def remove() -> None:
|
|
40
|
+
with contextlib.suppress(RuntimeError):
|
|
41
|
+
signal.signal(signal.SIGINT, previous)
|
|
42
|
+
|
|
43
|
+
return remove
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from collections.abc import Awaitable, Callable, Sequence
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import overload
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass(frozen=True, slots=True, kw_only=True)
|
|
8
|
+
class SlashCommand[F: Callable[..., None | Awaitable[None]]]:
|
|
9
|
+
name: str
|
|
10
|
+
description: str
|
|
11
|
+
func: F
|
|
12
|
+
aliases: list[str]
|
|
13
|
+
|
|
14
|
+
def slash_name(self):
|
|
15
|
+
"""/name (aliases)"""
|
|
16
|
+
if self.aliases:
|
|
17
|
+
return f"/{self.name} ({', '.join(self.aliases)})"
|
|
18
|
+
return f"/{self.name}"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class SlashCommandRegistry[F: Callable[..., None | Awaitable[None]]]:
|
|
22
|
+
"""Registry for slash commands."""
|
|
23
|
+
|
|
24
|
+
def __init__(self) -> None:
|
|
25
|
+
self._commands: dict[str, SlashCommand[F]] = {}
|
|
26
|
+
"""Primary name -> SlashCommand"""
|
|
27
|
+
self._command_aliases: dict[str, SlashCommand[F]] = {}
|
|
28
|
+
"""Primary name or alias -> SlashCommand"""
|
|
29
|
+
|
|
30
|
+
@overload
|
|
31
|
+
def command(self, func: F, /) -> F: ...
|
|
32
|
+
|
|
33
|
+
@overload
|
|
34
|
+
def command(
|
|
35
|
+
self,
|
|
36
|
+
*,
|
|
37
|
+
name: str | None = None,
|
|
38
|
+
aliases: Sequence[str] | None = None,
|
|
39
|
+
) -> Callable[[F], F]: ...
|
|
40
|
+
|
|
41
|
+
def command(
|
|
42
|
+
self,
|
|
43
|
+
func: F | None = None,
|
|
44
|
+
*,
|
|
45
|
+
name: str | None = None,
|
|
46
|
+
aliases: Sequence[str] | None = None,
|
|
47
|
+
) -> F | Callable[[F], F]:
|
|
48
|
+
"""
|
|
49
|
+
Decorator to register a slash command with optional custom name and aliases.
|
|
50
|
+
|
|
51
|
+
Usage examples:
|
|
52
|
+
@registry.command
|
|
53
|
+
def help(app: App, args: str): ...
|
|
54
|
+
|
|
55
|
+
@registry.command(name="run")
|
|
56
|
+
def start(app: App, args: str): ...
|
|
57
|
+
|
|
58
|
+
@registry.command(aliases=["h", "?", "assist"])
|
|
59
|
+
def help(app: App, args: str): ...
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
def _register(f: F) -> F:
|
|
63
|
+
primary = name or f.__name__
|
|
64
|
+
alias_list = list(aliases) if aliases else []
|
|
65
|
+
|
|
66
|
+
# Create the primary command with aliases
|
|
67
|
+
cmd = SlashCommand[F](
|
|
68
|
+
name=primary,
|
|
69
|
+
description=(f.__doc__ or "").strip(),
|
|
70
|
+
func=f,
|
|
71
|
+
aliases=alias_list,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
# Register primary command
|
|
75
|
+
self._commands[primary] = cmd
|
|
76
|
+
self._command_aliases[primary] = cmd
|
|
77
|
+
|
|
78
|
+
# Register aliases pointing to the same command
|
|
79
|
+
for alias in alias_list:
|
|
80
|
+
self._command_aliases[alias] = cmd
|
|
81
|
+
|
|
82
|
+
return f
|
|
83
|
+
|
|
84
|
+
if func is not None:
|
|
85
|
+
return _register(func)
|
|
86
|
+
return _register
|
|
87
|
+
|
|
88
|
+
def find_command(self, name: str) -> SlashCommand[F] | None:
|
|
89
|
+
return self._command_aliases.get(name)
|
|
90
|
+
|
|
91
|
+
def list_commands(self) -> list[SlashCommand[F]]:
|
|
92
|
+
"""Get all unique primary slash commands (without duplicating aliases)."""
|
|
93
|
+
return list(self._commands.values())
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@dataclass(frozen=True, slots=True, kw_only=True)
|
|
97
|
+
class SlashCommandCall:
|
|
98
|
+
name: str
|
|
99
|
+
args: str
|
|
100
|
+
raw_input: str
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def parse_slash_command_call(user_input: str) -> SlashCommandCall | None:
|
|
104
|
+
"""
|
|
105
|
+
Parse a slash command call from user input.
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
SlashCommandCall if a slash command is found, else None. The `args` field contains
|
|
109
|
+
the raw argument string after the command name.
|
|
110
|
+
"""
|
|
111
|
+
user_input = user_input.strip()
|
|
112
|
+
if not user_input or not user_input.startswith("/"):
|
|
113
|
+
return None
|
|
114
|
+
|
|
115
|
+
name_match = re.match(r"^\/([a-zA-Z0-9_-]+(?::[a-zA-Z0-9_-]+)*)", user_input)
|
|
116
|
+
|
|
117
|
+
if not name_match:
|
|
118
|
+
return None
|
|
119
|
+
|
|
120
|
+
command_name = name_match.group(1)
|
|
121
|
+
if len(user_input) > name_match.end() and not user_input[name_match.end()].isspace():
|
|
122
|
+
return None
|
|
123
|
+
raw_args = user_input[name_match.end() :].lstrip()
|
|
124
|
+
return SlashCommandCall(name=command_name, args=raw_args, raw_input=user_input)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import random
|
|
4
|
+
import re
|
|
5
|
+
import string
|
|
6
|
+
|
|
7
|
+
_NEWLINE_RE = re.compile(r"[\r\n]+")
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def shorten(text: str, *, width: int, placeholder: str = "…") -> str:
|
|
11
|
+
"""Shorten text to at most *width* characters.
|
|
12
|
+
|
|
13
|
+
Normalises whitespace, then truncates — preferring a word boundary
|
|
14
|
+
when one exists near the cut point, but falling back to a hard cut
|
|
15
|
+
so that CJK text without spaces won't collapse to just the placeholder.
|
|
16
|
+
"""
|
|
17
|
+
text = " ".join(text.split())
|
|
18
|
+
if len(text) <= width:
|
|
19
|
+
return text
|
|
20
|
+
cut = width - len(placeholder)
|
|
21
|
+
if cut <= 0:
|
|
22
|
+
return text[:width]
|
|
23
|
+
space = text.rfind(" ", 0, cut + 1)
|
|
24
|
+
if space > 0:
|
|
25
|
+
cut = space
|
|
26
|
+
return text[:cut].rstrip() + placeholder
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def shorten_middle(text: str, width: int, remove_newline: bool = True) -> str:
|
|
30
|
+
"""Shorten the text by inserting ellipsis in the middle."""
|
|
31
|
+
if len(text) <= width:
|
|
32
|
+
return text
|
|
33
|
+
if remove_newline:
|
|
34
|
+
text = _NEWLINE_RE.sub(" ", text)
|
|
35
|
+
return text[: width // 2] + "..." + text[-width // 2 :]
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def random_string(length: int = 8) -> str:
|
|
39
|
+
"""Generate a random string of fixed length."""
|
|
40
|
+
letters = string.ascii_lowercase
|
|
41
|
+
return "".join(random.choice(letters) for _ in range(length))
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""Utilities for subprocess environment handling.
|
|
2
|
+
|
|
3
|
+
This module provides utilities to handle environment variables when spawning
|
|
4
|
+
subprocesses from a PyInstaller-frozen application. The main issue is that
|
|
5
|
+
PyInstaller's bootloader modifies LD_LIBRARY_PATH to prioritize bundled libraries,
|
|
6
|
+
which can cause conflicts when spawning external programs that expect system libraries.
|
|
7
|
+
|
|
8
|
+
See: https://pyinstaller.org/en/stable/common-issues-and-pitfalls.html
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import os
|
|
14
|
+
import sys
|
|
15
|
+
|
|
16
|
+
# Environment variables that PyInstaller may modify on Linux
|
|
17
|
+
_PYINSTALLER_LD_VARS = [
|
|
18
|
+
"LD_LIBRARY_PATH",
|
|
19
|
+
"LD_PRELOAD",
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def get_clean_env(base_env: dict[str, str] | None = None) -> dict[str, str]:
|
|
24
|
+
"""
|
|
25
|
+
Get a clean environment suitable for spawning subprocesses.
|
|
26
|
+
|
|
27
|
+
In a PyInstaller-frozen application on Linux, this function restores
|
|
28
|
+
the original library path environment variables, preventing subprocesses
|
|
29
|
+
from loading incompatible bundled libraries.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
base_env: Base environment to start from. If None, uses os.environ.
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
A dictionary of environment variables safe for subprocess use.
|
|
36
|
+
"""
|
|
37
|
+
env = dict(base_env if base_env is not None else os.environ)
|
|
38
|
+
|
|
39
|
+
# Only process in PyInstaller frozen environment on Linux
|
|
40
|
+
if not getattr(sys, "frozen", False) or sys.platform != "linux":
|
|
41
|
+
return env
|
|
42
|
+
|
|
43
|
+
for var in _PYINSTALLER_LD_VARS:
|
|
44
|
+
orig_key = f"{var}_ORIG"
|
|
45
|
+
if orig_key in env:
|
|
46
|
+
# Restore the original value that was saved by PyInstaller bootloader
|
|
47
|
+
env[var] = env[orig_key]
|
|
48
|
+
elif var in env:
|
|
49
|
+
# Variable was not set before PyInstaller modified it, so remove it
|
|
50
|
+
del env[var]
|
|
51
|
+
|
|
52
|
+
return env
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def get_noninteractive_env(base_env: dict[str, str] | None = None) -> dict[str, str]:
|
|
56
|
+
"""
|
|
57
|
+
Get an environment for subprocesses that must not block on interactive prompts.
|
|
58
|
+
|
|
59
|
+
Builds on :func:`get_clean_env` and additionally configures git to fail
|
|
60
|
+
fast instead of waiting for user input that will never arrive.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
base_env: Base environment to start from. If None, uses os.environ.
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
A dictionary of environment variables safe for non-interactive subprocess use.
|
|
67
|
+
"""
|
|
68
|
+
env = get_clean_env(base_env)
|
|
69
|
+
|
|
70
|
+
# GIT_TERMINAL_PROMPT=0 makes git fail instead of prompting for credentials.
|
|
71
|
+
env.setdefault("GIT_TERMINAL_PROMPT", "0")
|
|
72
|
+
|
|
73
|
+
return env
|