pythinker-code 0.8.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 +60 -0
- pythinker_code/__init__.py +0 -0
- pythinker_code/__main__.py +97 -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 +301 -0
- pythinker_code/acp/mcp.py +46 -0
- pythinker_code/acp/server.py +497 -0
- pythinker_code/acp/session.py +502 -0
- pythinker_code/acp/tools.py +174 -0
- pythinker_code/acp/types.py +13 -0
- pythinker_code/acp/version.py +45 -0
- pythinker_code/agents/default/agent.yaml +55 -0
- pythinker_code/agents/default/code_reviewer.yaml +47 -0
- pythinker_code/agents/default/coder.yaml +42 -0
- pythinker_code/agents/default/debugger.yaml +35 -0
- pythinker_code/agents/default/explore.yaml +59 -0
- pythinker_code/agents/default/implementer.yaml +46 -0
- pythinker_code/agents/default/plan.yaml +42 -0
- pythinker_code/agents/default/review.yaml +47 -0
- pythinker_code/agents/default/security_reviewer.yaml +37 -0
- pythinker_code/agents/default/system.md +192 -0
- pythinker_code/agents/default/verifier.yaml +46 -0
- pythinker_code/agents/okabe/agent.yaml +22 -0
- pythinker_code/agentspec.py +163 -0
- pythinker_code/app.py +847 -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/github_feedback.py +228 -0
- pythinker_code/auth/lm_studio.py +418 -0
- pythinker_code/auth/minimax.py +203 -0
- pythinker_code/auth/oauth.py +1145 -0
- pythinker_code/auth/ollama.py +293 -0
- pythinker_code/auth/openai.py +783 -0
- pythinker_code/auth/opencode_go.py +203 -0
- pythinker_code/auth/openrouter.py +225 -0
- pythinker_code/auth/platforms.py +475 -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 +668 -0
- pythinker_code/background/models.py +118 -0
- pythinker_code/background/store.py +243 -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 +268 -0
- pythinker_code/cli/debug.py +11 -0
- pythinker_code/cli/export.py +322 -0
- pythinker_code/cli/info.py +62 -0
- pythinker_code/cli/mcp.py +362 -0
- pythinker_code/cli/plugin.py +351 -0
- pythinker_code/cli/review.py +74 -0
- pythinker_code/cli/secscan.py +11 -0
- pythinker_code/cli/security_scan.py +35 -0
- pythinker_code/cli/toad.py +74 -0
- pythinker_code/cli/update.py +26 -0
- pythinker_code/cli/vis.py +38 -0
- pythinker_code/cli/web.py +80 -0
- pythinker_code/config.py +511 -0
- pythinker_code/constant.py +33 -0
- pythinker_code/events.py +106 -0
- pythinker_code/exception.py +43 -0
- pythinker_code/extensions.py +151 -0
- pythinker_code/hooks/__init__.py +4 -0
- pythinker_code/hooks/config.py +34 -0
- pythinker_code/hooks/engine.py +383 -0
- pythinker_code/hooks/events.py +190 -0
- pythinker_code/hooks/runner.py +92 -0
- pythinker_code/llm.py +441 -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 +166 -0
- pythinker_code/plugin/tool.py +173 -0
- pythinker_code/prompt_templates.py +181 -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 +552 -0
- pythinker_code/soul/approval.py +267 -0
- pythinker_code/soul/btw.py +220 -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/permission.py +368 -0
- pythinker_code/soul/pythinkersoul.py +1763 -0
- pythinker_code/soul/slash.py +340 -0
- pythinker_code/soul/toolset.py +826 -0
- pythinker_code/subagents/__init__.py +21 -0
- pythinker_code/subagents/builder.py +43 -0
- pythinker_code/subagents/core.py +86 -0
- pythinker_code/subagents/discovery.py +234 -0
- pythinker_code/subagents/git_context.py +172 -0
- pythinker_code/subagents/models.py +56 -0
- pythinker_code/subagents/output.py +71 -0
- pythinker_code/subagents/registry.py +28 -0
- pythinker_code/subagents/runner.py +442 -0
- pythinker_code/subagents/store.py +200 -0
- pythinker_code/telemetry/__init__.py +217 -0
- pythinker_code/telemetry/config.py +113 -0
- pythinker_code/telemetry/crash.py +191 -0
- pythinker_code/telemetry/errors.py +113 -0
- pythinker_code/telemetry/metrics.py +208 -0
- pythinker_code/telemetry/otel.py +303 -0
- pythinker_code/telemetry/sentry.py +212 -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 +326 -0
- pythinker_code/tools/agent/description.md +65 -0
- pythinker_code/tools/ask_user/__init__.py +162 -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 +31 -0
- pythinker_code/tools/file/glob.md +17 -0
- pythinker_code/tools/file/glob.py +163 -0
- pythinker_code/tools/file/grep.md +6 -0
- pythinker_code/tools/file/grep_local.py +904 -0
- pythinker_code/tools/file/plan_mode.py +45 -0
- pythinker_code/tools/file/read.md +16 -0
- pythinker_code/tools/file/read.py +303 -0
- pythinker_code/tools/file/read_media.md +24 -0
- pythinker_code/tools/file/read_media.py +220 -0
- pythinker_code/tools/file/replace.md +7 -0
- pythinker_code/tools/file/replace.py +204 -0
- pythinker_code/tools/file/utils.py +257 -0
- pythinker_code/tools/file/write.md +5 -0
- pythinker_code/tools/file/write.py +186 -0
- pythinker_code/tools/plan/__init__.py +362 -0
- pythinker_code/tools/plan/description.md +29 -0
- pythinker_code/tools/plan/enter.py +193 -0
- pythinker_code/tools/plan/enter_description.md +35 -0
- pythinker_code/tools/plan/handoff.py +69 -0
- pythinker_code/tools/plan/heroes.py +277 -0
- pythinker_code/tools/shell/__init__.py +263 -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 +200 -0
- pythinker_code/tools/web/__init__.py +4 -0
- pythinker_code/tools/web/fetch.md +1 -0
- pythinker_code/tools/web/fetch.py +261 -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 +1806 -0
- pythinker_code/ui/shell/components/__init__.py +110 -0
- pythinker_code/ui/shell/components/base.py +25 -0
- pythinker_code/ui/shell/components/bash_execution.py +249 -0
- pythinker_code/ui/shell/components/bordered_loader.py +62 -0
- pythinker_code/ui/shell/components/diff.py +308 -0
- pythinker_code/ui/shell/components/footer.py +231 -0
- pythinker_code/ui/shell/components/key_hints.py +27 -0
- pythinker_code/ui/shell/components/messages.py +152 -0
- pythinker_code/ui/shell/components/render_utils.py +198 -0
- pythinker_code/ui/shell/components/settings_list.py +369 -0
- pythinker_code/ui/shell/components/special_messages.py +125 -0
- pythinker_code/ui/shell/components/tool_execution.py +261 -0
- pythinker_code/ui/shell/console.py +109 -0
- pythinker_code/ui/shell/debug.py +190 -0
- pythinker_code/ui/shell/echo.py +30 -0
- pythinker_code/ui/shell/export_import.py +117 -0
- pythinker_code/ui/shell/keyboard.py +300 -0
- pythinker_code/ui/shell/keymap.py +84 -0
- pythinker_code/ui/shell/mcp_status.py +112 -0
- pythinker_code/ui/shell/model_picker.py +318 -0
- pythinker_code/ui/shell/oauth.py +273 -0
- pythinker_code/ui/shell/placeholders.py +578 -0
- pythinker_code/ui/shell/prompt.py +2888 -0
- pythinker_code/ui/shell/replay.py +215 -0
- pythinker_code/ui/shell/selector.py +364 -0
- pythinker_code/ui/shell/selectors/__init__.py +38 -0
- pythinker_code/ui/shell/selectors/extension.py +37 -0
- pythinker_code/ui/shell/selectors/oauth.py +63 -0
- pythinker_code/ui/shell/selectors/settings.py +349 -0
- pythinker_code/ui/shell/selectors/show_images.py +29 -0
- pythinker_code/ui/shell/selectors/theme.py +28 -0
- pythinker_code/ui/shell/selectors/thinking.py +42 -0
- pythinker_code/ui/shell/session_picker.py +227 -0
- pythinker_code/ui/shell/setup.py +212 -0
- pythinker_code/ui/shell/slash.py +1433 -0
- pythinker_code/ui/shell/spinner_words.py +222 -0
- pythinker_code/ui/shell/startup.py +32 -0
- pythinker_code/ui/shell/task_browser.py +486 -0
- pythinker_code/ui/shell/tool_renderers/__init__.py +197 -0
- pythinker_code/ui/shell/tool_renderers/_render_utils.py +168 -0
- pythinker_code/ui/shell/tool_renderers/agent.py +140 -0
- pythinker_code/ui/shell/tool_renderers/ask_user.py +93 -0
- pythinker_code/ui/shell/tool_renderers/background.py +144 -0
- pythinker_code/ui/shell/tool_renderers/bash.py +103 -0
- pythinker_code/ui/shell/tool_renderers/edit.py +163 -0
- pythinker_code/ui/shell/tool_renderers/find.py +81 -0
- pythinker_code/ui/shell/tool_renderers/generic.py +60 -0
- pythinker_code/ui/shell/tool_renderers/grep.py +98 -0
- pythinker_code/ui/shell/tool_renderers/plan.py +98 -0
- pythinker_code/ui/shell/tool_renderers/read.py +103 -0
- pythinker_code/ui/shell/tool_renderers/think.py +66 -0
- pythinker_code/ui/shell/tool_renderers/todo.py +164 -0
- pythinker_code/ui/shell/tool_renderers/web.py +128 -0
- pythinker_code/ui/shell/tool_renderers/write.py +102 -0
- pythinker_code/ui/shell/update.py +352 -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 +539 -0
- pythinker_code/ui/shell/visualize/_blocks.py +802 -0
- pythinker_code/ui/shell/visualize/_btw_panel.py +227 -0
- pythinker_code/ui/shell/visualize/_input_router.py +48 -0
- pythinker_code/ui/shell/visualize/_interactive.py +531 -0
- pythinker_code/ui/shell/visualize/_live_view.py +891 -0
- pythinker_code/ui/shell/visualize/_question_panel.py +586 -0
- pythinker_code/ui/shell/visualize/_worklog.py +245 -0
- pythinker_code/ui/theme.py +395 -0
- pythinker_code/ui/tui_config.py +82 -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 +38 -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 +935 -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 +83 -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 +714 -0
- pythinker_code/vis/api/statistics.py +209 -0
- pythinker_code/vis/api/system.py +19 -0
- pythinker_code/vis/app.py +199 -0
- pythinker_code/vis/static/assets/highlighted-body-B3W2YXNL-CY1rtwrX.js +1 -0
- pythinker_code/vis/static/assets/index-DSRInNnm.css +1 -0
- pythinker_code/vis/static/assets/index-DgmTI2M_.js +185 -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 +217 -0
- pythinker_code/web/api/open_in.py +233 -0
- pythinker_code/web/api/sessions.py +1256 -0
- pythinker_code/web/app.py +449 -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-DpSMr1jx.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-DpsahJyV.js +1 -0
- pythinker_code/web/static/assets/architectureDiagram-VXUJARFQ-DqiRv9Eg.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-WgtUvqbp.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-rK0RPuZd.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-B0rlvkH-.js +1 -0
- pythinker_code/web/static/assets/chunk-4BX2VUAB-DIkMuLV-.js +1 -0
- pythinker_code/web/static/assets/chunk-55IACEB6-CORdm4k4.js +1 -0
- pythinker_code/web/static/assets/chunk-B4BG7PRW-D9xDhwHO.js +165 -0
- pythinker_code/web/static/assets/chunk-DI55MBZ5-BDmF9Bh-.js +220 -0
- pythinker_code/web/static/assets/chunk-FMBD7UC4-BCse_HmM.js +15 -0
- pythinker_code/web/static/assets/chunk-QN33PNHL-DCpBmTzA.js +1 -0
- pythinker_code/web/static/assets/chunk-QZHKN3VN-BqLuqobw.js +1 -0
- pythinker_code/web/static/assets/chunk-TZMSLE5B-8K2ogOKS.js +1 -0
- pythinker_code/web/static/assets/clarity-D53aC0YG.js +1 -0
- pythinker_code/web/static/assets/classDiagram-2ON5EDUG-D_ZHSii2.js +1 -0
- pythinker_code/web/static/assets/classDiagram-v2-WZHVMYZB-D_ZHSii2.js +1 -0
- pythinker_code/web/static/assets/clojure-P80f7IUj.js +1 -0
- pythinker_code/web/static/assets/clone-GSXejyY1.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-DWTFYA28.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-BRI7ES-N.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-B6BxUuKW.js +321 -0
- pythinker_code/web/static/assets/d-85-TOEBH.js +1 -0
- pythinker_code/web/static/assets/dagre-6UL2VRFP-Ci5GdWfi.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-0hhAylV4.js +24 -0
- pythinker_code/web/static/assets/diagram-QEK2KX5R-8fxgaW6d.js +43 -0
- pythinker_code/web/static/assets/diagram-S2PKOQOG-FRr0_atE.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-B3T-hJUM.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-D0S3u7ot.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-CHrN2a23.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-CfcXZWg0.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-8jMJwCqE.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-BXrFnzMy.js +153 -0
- pythinker_code/web/static/assets/index-BpoLgcEt.js +1 -0
- pythinker_code/web/static/assets/index-BrfQJnRD.js +5 -0
- pythinker_code/web/static/assets/index-C4gFzubz.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/infoDiagram-WHAUD3N6-DdxonBf3.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-BXf4aQei.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-DLpPPOu8.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-DH73UoAH.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-bAer2-sK.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-CuqbwKXv.js +465 -0
- pythinker_code/web/static/assets/mermaid-mWjccvbQ.js +1 -0
- pythinker_code/web/static/assets/mermaid.core-Nx-rTKiV.js +191 -0
- pythinker_code/web/static/assets/min-DbfD8Ywu.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-C6l761Ue.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-fNg41mT9.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-DJz3Kx87.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-B4SbrfE9.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-CoSUjLAG.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-PjhBNHi3.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-DOwESt8-.js +1 -0
- pythinker_code/web/static/assets/stateDiagram-v2-4FDKWEC3-yl3OHWiP.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-CkCLnAgi.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-CZS5XwTf.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-DkqqHNLh.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 +433 -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 +1072 -0
- pythinker_code/wire/types.py +698 -0
- pythinker_code-0.8.0.dist-info/METADATA +706 -0
- pythinker_code-0.8.0.dist-info/RECORD +790 -0
- pythinker_code-0.8.0.dist-info/WHEEL +4 -0
- pythinker_code-0.8.0.dist-info/entry_points.txt +4 -0
- pythinker_code-0.8.0.dist-info/licenses/LICENSE +202 -0
- pythinker_code-0.8.0.dist-info/licenses/NOTICE +14 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from pythinker_code.subagents.models import (
|
|
2
|
+
AgentInstanceRecord,
|
|
3
|
+
AgentLaunchSpec,
|
|
4
|
+
AgentTypeDefinition,
|
|
5
|
+
SubagentStatus,
|
|
6
|
+
ToolPolicy,
|
|
7
|
+
ToolPolicyMode,
|
|
8
|
+
)
|
|
9
|
+
from pythinker_code.subagents.registry import LaborMarket
|
|
10
|
+
from pythinker_code.subagents.store import SubagentStore
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"AgentInstanceRecord",
|
|
14
|
+
"AgentLaunchSpec",
|
|
15
|
+
"AgentTypeDefinition",
|
|
16
|
+
"LaborMarket",
|
|
17
|
+
"SubagentStatus",
|
|
18
|
+
"SubagentStore",
|
|
19
|
+
"ToolPolicy",
|
|
20
|
+
"ToolPolicyMode",
|
|
21
|
+
]
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pythinker_code.llm import clone_llm_with_model_alias
|
|
4
|
+
from pythinker_code.soul.agent import Agent, Runtime, load_agent
|
|
5
|
+
from pythinker_code.subagents.models import AgentLaunchSpec, AgentTypeDefinition
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class SubagentBuilder:
|
|
9
|
+
def __init__(self, root_runtime: Runtime):
|
|
10
|
+
self._root_runtime = root_runtime
|
|
11
|
+
|
|
12
|
+
async def build_builtin_instance(
|
|
13
|
+
self,
|
|
14
|
+
*,
|
|
15
|
+
agent_id: str,
|
|
16
|
+
type_def: AgentTypeDefinition,
|
|
17
|
+
launch_spec: AgentLaunchSpec,
|
|
18
|
+
) -> Agent:
|
|
19
|
+
effective_model = self.resolve_effective_model(type_def=type_def, launch_spec=launch_spec)
|
|
20
|
+
llm_override = clone_llm_with_model_alias(
|
|
21
|
+
self._root_runtime.llm,
|
|
22
|
+
self._root_runtime.config,
|
|
23
|
+
effective_model,
|
|
24
|
+
session_id=self._root_runtime.session.id,
|
|
25
|
+
oauth=self._root_runtime.oauth,
|
|
26
|
+
thinking=launch_spec.thinking,
|
|
27
|
+
)
|
|
28
|
+
runtime = self._root_runtime.copy_for_subagent(
|
|
29
|
+
agent_id=agent_id,
|
|
30
|
+
subagent_type=type_def.name,
|
|
31
|
+
llm_override=llm_override,
|
|
32
|
+
)
|
|
33
|
+
return await load_agent(
|
|
34
|
+
type_def.agent_file,
|
|
35
|
+
runtime,
|
|
36
|
+
mcp_configs=[],
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
@staticmethod
|
|
40
|
+
def resolve_effective_model(
|
|
41
|
+
*, type_def: AgentTypeDefinition, launch_spec: AgentLaunchSpec
|
|
42
|
+
) -> str | None:
|
|
43
|
+
return launch_spec.model_override or launch_spec.effective_model or type_def.default_model
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""Shared core logic for preparing a subagent soul.
|
|
2
|
+
|
|
3
|
+
Both ``ForegroundSubagentRunner`` and ``BackgroundAgentRunner`` delegate
|
|
4
|
+
the repetitive build-restore-prompt pipeline to :func:`prepare_soul` so
|
|
5
|
+
that prompt enhancements (e.g. git context injection) only need to be
|
|
6
|
+
implemented once.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from collections.abc import Callable
|
|
12
|
+
from dataclasses import dataclass, replace
|
|
13
|
+
from typing import TYPE_CHECKING
|
|
14
|
+
|
|
15
|
+
from pythinker_code.soul.context import Context
|
|
16
|
+
from pythinker_code.soul.pythinkersoul import PythinkerSoul
|
|
17
|
+
from pythinker_code.subagents.builder import SubagentBuilder
|
|
18
|
+
from pythinker_code.subagents.models import AgentLaunchSpec, AgentTypeDefinition
|
|
19
|
+
from pythinker_code.subagents.store import SubagentStore
|
|
20
|
+
|
|
21
|
+
if TYPE_CHECKING:
|
|
22
|
+
from pythinker_code.soul.agent import Runtime
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass(frozen=True, slots=True, kw_only=True)
|
|
26
|
+
class SubagentRunSpec:
|
|
27
|
+
"""Everything needed to prepare a soul, without lifecycle concerns."""
|
|
28
|
+
|
|
29
|
+
agent_id: str
|
|
30
|
+
type_def: AgentTypeDefinition
|
|
31
|
+
launch_spec: AgentLaunchSpec
|
|
32
|
+
prompt: str
|
|
33
|
+
resumed: bool
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
async def prepare_soul(
|
|
37
|
+
spec: SubagentRunSpec,
|
|
38
|
+
runtime: Runtime,
|
|
39
|
+
builder: SubagentBuilder,
|
|
40
|
+
store: SubagentStore,
|
|
41
|
+
on_stage: Callable[[str], None] | None = None,
|
|
42
|
+
) -> tuple[PythinkerSoul, str]:
|
|
43
|
+
"""Build agent, restore context, handle system prompt, write prompt file.
|
|
44
|
+
|
|
45
|
+
Returns ``(soul, final_prompt)`` ready for execution via
|
|
46
|
+
:func:`run_with_summary_continuation`.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
# 1. Build agent from type definition
|
|
50
|
+
agent = await builder.build_builtin_instance(
|
|
51
|
+
agent_id=spec.agent_id,
|
|
52
|
+
type_def=spec.type_def,
|
|
53
|
+
launch_spec=spec.launch_spec,
|
|
54
|
+
)
|
|
55
|
+
if on_stage:
|
|
56
|
+
on_stage("agent_built")
|
|
57
|
+
|
|
58
|
+
# 2. Restore conversation context
|
|
59
|
+
context = Context(store.context_path(spec.agent_id))
|
|
60
|
+
await context.restore()
|
|
61
|
+
if on_stage:
|
|
62
|
+
on_stage("context_restored")
|
|
63
|
+
|
|
64
|
+
# 3. System prompt: reuse persisted prompt on resume, persist on first run
|
|
65
|
+
if context.system_prompt is not None:
|
|
66
|
+
agent = replace(agent, system_prompt=context.system_prompt)
|
|
67
|
+
else:
|
|
68
|
+
await context.write_system_prompt(agent.system_prompt)
|
|
69
|
+
if on_stage:
|
|
70
|
+
on_stage("context_ready")
|
|
71
|
+
|
|
72
|
+
# 4. For new (non-resumed) explore agents, prepend git context to the prompt
|
|
73
|
+
prompt = spec.prompt
|
|
74
|
+
if spec.type_def.name == "explore" and not spec.resumed:
|
|
75
|
+
from pythinker_code.subagents.git_context import collect_git_context
|
|
76
|
+
|
|
77
|
+
git_ctx = await collect_git_context(runtime.builtin_args.PYTHINKER_WORK_DIR)
|
|
78
|
+
if git_ctx:
|
|
79
|
+
prompt = f"{git_ctx}\n\n{prompt}"
|
|
80
|
+
|
|
81
|
+
# 5. Write prompt snapshot (debugging aid)
|
|
82
|
+
store.prompt_path(spec.agent_id).write_text(prompt, encoding="utf-8")
|
|
83
|
+
|
|
84
|
+
# 6. Create soul
|
|
85
|
+
soul = PythinkerSoul(agent, context=context)
|
|
86
|
+
return soul, prompt
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
"""Discovery for markdown-defined subagents from Claude/Agents-style directories."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Iterable
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Any, Literal, cast
|
|
9
|
+
|
|
10
|
+
import yaml
|
|
11
|
+
from pythinker_host.path import HostPath
|
|
12
|
+
|
|
13
|
+
from pythinker_code.subagents.models import AgentTypeDefinition, ToolPolicy
|
|
14
|
+
from pythinker_code.utils.frontmatter import parse_frontmatter, strip_frontmatter
|
|
15
|
+
from pythinker_code.utils.logging import logger
|
|
16
|
+
from pythinker_code.utils.path import find_project_root
|
|
17
|
+
|
|
18
|
+
AgentScope = Literal["project"]
|
|
19
|
+
|
|
20
|
+
CLAUDE_TOOL_MAP: dict[str, str] = {
|
|
21
|
+
"Agent": "pythinker_code.tools.agent:Agent",
|
|
22
|
+
"Bash": "pythinker_code.tools.shell:Shell",
|
|
23
|
+
"Edit": "pythinker_code.tools.file:StrReplaceFile",
|
|
24
|
+
"Fetch": "pythinker_code.tools.web:FetchURL",
|
|
25
|
+
"Glob": "pythinker_code.tools.file:Glob",
|
|
26
|
+
"Grep": "pythinker_code.tools.file:Grep",
|
|
27
|
+
"Read": "pythinker_code.tools.file:ReadFile",
|
|
28
|
+
"TodoWrite": "pythinker_code.tools.todo:SetTodoList",
|
|
29
|
+
"WebFetch": "pythinker_code.tools.web:FetchURL",
|
|
30
|
+
"WebSearch": "pythinker_code.tools.web:SearchWeb",
|
|
31
|
+
"Write": "pythinker_code.tools.file:WriteFile",
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@dataclass(frozen=True, slots=True)
|
|
36
|
+
class ScopedAgentRoot:
|
|
37
|
+
root: HostPath
|
|
38
|
+
scope: AgentScope
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@dataclass(frozen=True, slots=True)
|
|
42
|
+
class MarkdownAgentSpec:
|
|
43
|
+
name: str
|
|
44
|
+
description: str
|
|
45
|
+
prompt_file: HostPath
|
|
46
|
+
scope: AgentScope
|
|
47
|
+
tools: tuple[str, ...] | None = None
|
|
48
|
+
model: str | None = None
|
|
49
|
+
when_to_use: str = ""
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _project_agent_dir_candidates(project_root: HostPath) -> tuple[HostPath, ...]:
|
|
53
|
+
return (
|
|
54
|
+
project_root / ".pythinker" / "agents",
|
|
55
|
+
project_root / ".claude" / "agents",
|
|
56
|
+
project_root / ".agents" / "agents",
|
|
57
|
+
project_root / ".codex" / "agents",
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
async def resolve_agent_roots(work_dir: HostPath) -> list[ScopedAgentRoot]:
|
|
62
|
+
"""Return existing markdown-agent roots in priority order."""
|
|
63
|
+
project_root = await find_project_root(work_dir)
|
|
64
|
+
roots: list[ScopedAgentRoot] = []
|
|
65
|
+
seen: set[str] = set()
|
|
66
|
+
|
|
67
|
+
async def add_existing(candidates: Iterable[HostPath], scope: AgentScope) -> None:
|
|
68
|
+
for candidate in candidates:
|
|
69
|
+
try:
|
|
70
|
+
if not await candidate.is_dir():
|
|
71
|
+
continue
|
|
72
|
+
canon = candidate.canonical()
|
|
73
|
+
except OSError as exc:
|
|
74
|
+
logger.info("Skipping agent directory {path}: {error}", path=candidate, error=exc)
|
|
75
|
+
continue
|
|
76
|
+
key = str(canon)
|
|
77
|
+
if key in seen:
|
|
78
|
+
continue
|
|
79
|
+
seen.add(key)
|
|
80
|
+
roots.append(ScopedAgentRoot(root=canon, scope=scope))
|
|
81
|
+
|
|
82
|
+
await add_existing(_project_agent_dir_candidates(project_root), "project")
|
|
83
|
+
return roots
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
async def discover_markdown_agents(roots: Iterable[ScopedAgentRoot]) -> list[MarkdownAgentSpec]:
|
|
87
|
+
"""Discover Claude/Agents-style ``*.md`` subagent definitions."""
|
|
88
|
+
by_name: dict[str, MarkdownAgentSpec] = {}
|
|
89
|
+
for scoped in roots:
|
|
90
|
+
try:
|
|
91
|
+
async for entry in scoped.root.iterdir():
|
|
92
|
+
if not entry.name.lower().endswith(".md"):
|
|
93
|
+
continue
|
|
94
|
+
try:
|
|
95
|
+
if await entry.is_dir():
|
|
96
|
+
continue
|
|
97
|
+
content = await entry.read_text(encoding="utf-8")
|
|
98
|
+
spec = parse_markdown_agent(content, prompt_file=entry, scope=scoped.scope)
|
|
99
|
+
except Exception as exc:
|
|
100
|
+
logger.info(
|
|
101
|
+
"Skipping invalid markdown agent {path}: {error}",
|
|
102
|
+
path=entry,
|
|
103
|
+
error=exc,
|
|
104
|
+
)
|
|
105
|
+
continue
|
|
106
|
+
by_name.setdefault(spec.name.casefold(), spec)
|
|
107
|
+
except OSError as exc:
|
|
108
|
+
logger.warning(
|
|
109
|
+
"Failed to iterate agent directory {path}: {error}",
|
|
110
|
+
path=scoped.root,
|
|
111
|
+
error=exc,
|
|
112
|
+
)
|
|
113
|
+
return sorted(by_name.values(), key=lambda s: s.name)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def parse_markdown_agent(
|
|
117
|
+
content: str,
|
|
118
|
+
*,
|
|
119
|
+
prompt_file: HostPath,
|
|
120
|
+
scope: AgentScope,
|
|
121
|
+
) -> MarkdownAgentSpec:
|
|
122
|
+
"""Parse a Claude-style markdown agent file."""
|
|
123
|
+
fm = parse_frontmatter(content) or {}
|
|
124
|
+
default_name = Path(prompt_file.name).stem
|
|
125
|
+
name = _as_nonempty_str(fm.get("name")) or default_name
|
|
126
|
+
description = _as_nonempty_str(fm.get("description")) or _first_body_line(content) or ""
|
|
127
|
+
model = _as_nonempty_str(fm.get("model"))
|
|
128
|
+
when_to_use = _as_nonempty_str(fm.get("when_to_use")) or description
|
|
129
|
+
tools = _map_tools(fm.get("tools"), source=prompt_file)
|
|
130
|
+
return MarkdownAgentSpec(
|
|
131
|
+
name=name,
|
|
132
|
+
description=description,
|
|
133
|
+
prompt_file=prompt_file,
|
|
134
|
+
scope=scope,
|
|
135
|
+
tools=tools,
|
|
136
|
+
model=model,
|
|
137
|
+
when_to_use=when_to_use,
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def materialize_markdown_agent_specs(
|
|
142
|
+
agents: Iterable[MarkdownAgentSpec],
|
|
143
|
+
*,
|
|
144
|
+
output_dir: Path,
|
|
145
|
+
available_models: set[str] | None = None,
|
|
146
|
+
) -> list[AgentTypeDefinition]:
|
|
147
|
+
"""Write small Pythinker YAML wrappers and return registered type definitions."""
|
|
148
|
+
output_dir.mkdir(parents=True, exist_ok=True)
|
|
149
|
+
type_defs: list[AgentTypeDefinition] = []
|
|
150
|
+
for agent in agents:
|
|
151
|
+
filename = _safe_filename(agent.name)
|
|
152
|
+
wrapper_path = output_dir / f"{filename}.yaml"
|
|
153
|
+
prompt_path = output_dir / f"{filename}.system.md"
|
|
154
|
+
try:
|
|
155
|
+
prompt_text = Path(str(agent.prompt_file)).read_text(encoding="utf-8")
|
|
156
|
+
except OSError as exc:
|
|
157
|
+
logger.warning(
|
|
158
|
+
"Failed to read markdown agent prompt {path}: {error}",
|
|
159
|
+
path=agent.prompt_file,
|
|
160
|
+
error=exc,
|
|
161
|
+
)
|
|
162
|
+
prompt_text = ""
|
|
163
|
+
prompt_path.write_text(strip_frontmatter(prompt_text).strip(), encoding="utf-8")
|
|
164
|
+
payload: dict[str, Any] = {
|
|
165
|
+
"version": 1,
|
|
166
|
+
"agent": {
|
|
167
|
+
"extend": "default",
|
|
168
|
+
"name": agent.name,
|
|
169
|
+
"system_prompt_path": str(prompt_path),
|
|
170
|
+
"when_to_use": agent.when_to_use,
|
|
171
|
+
},
|
|
172
|
+
}
|
|
173
|
+
model = agent.model if available_models is None or agent.model in available_models else None
|
|
174
|
+
if model:
|
|
175
|
+
payload["agent"]["model"] = model
|
|
176
|
+
if agent.tools is not None:
|
|
177
|
+
payload["agent"]["allowed_tools"] = list(agent.tools)
|
|
178
|
+
wrapper_path.write_text(yaml.safe_dump(payload, sort_keys=False), encoding="utf-8")
|
|
179
|
+
policy = (
|
|
180
|
+
ToolPolicy(mode="allowlist", tools=agent.tools)
|
|
181
|
+
if agent.tools is not None
|
|
182
|
+
else ToolPolicy(mode="inherit")
|
|
183
|
+
)
|
|
184
|
+
type_defs.append(
|
|
185
|
+
AgentTypeDefinition(
|
|
186
|
+
name=agent.name,
|
|
187
|
+
description=agent.description,
|
|
188
|
+
agent_file=wrapper_path,
|
|
189
|
+
when_to_use=agent.when_to_use,
|
|
190
|
+
default_model=model,
|
|
191
|
+
tool_policy=policy,
|
|
192
|
+
)
|
|
193
|
+
)
|
|
194
|
+
return type_defs
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def _map_tools(value: Any, *, source: HostPath) -> tuple[str, ...] | None:
|
|
198
|
+
if value is None:
|
|
199
|
+
return None
|
|
200
|
+
if not isinstance(value, list):
|
|
201
|
+
logger.info("Ignoring non-list tools field in markdown agent {path}", path=source)
|
|
202
|
+
return None
|
|
203
|
+
mapped: list[str] = []
|
|
204
|
+
for item in cast(list[Any], value):
|
|
205
|
+
if not isinstance(item, str):
|
|
206
|
+
continue
|
|
207
|
+
tool = CLAUDE_TOOL_MAP.get(item)
|
|
208
|
+
if tool is None:
|
|
209
|
+
logger.warning(
|
|
210
|
+
"Ignoring unknown markdown-agent tool {tool} in {path}",
|
|
211
|
+
tool=item,
|
|
212
|
+
path=source,
|
|
213
|
+
)
|
|
214
|
+
continue
|
|
215
|
+
if tool not in mapped:
|
|
216
|
+
mapped.append(tool)
|
|
217
|
+
return tuple(mapped)
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def _as_nonempty_str(value: Any) -> str | None:
|
|
221
|
+
return value.strip() if isinstance(value, str) and value.strip() else None
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def _first_body_line(content: str) -> str | None:
|
|
225
|
+
for line in strip_frontmatter(content).splitlines():
|
|
226
|
+
stripped = line.strip()
|
|
227
|
+
if stripped and stripped != "---":
|
|
228
|
+
return stripped
|
|
229
|
+
return None
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def _safe_filename(name: str) -> str:
|
|
233
|
+
safe = "".join(ch if ch.isalnum() or ch in "._-" else "_" for ch in name).strip("._")
|
|
234
|
+
return safe or "agent"
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"""Collect git repository context for explore subagents."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
import re
|
|
7
|
+
from urllib.parse import urlparse
|
|
8
|
+
|
|
9
|
+
import pythinker_host
|
|
10
|
+
from pythinker_host.path import HostPath
|
|
11
|
+
|
|
12
|
+
from pythinker_code.utils.logging import logger
|
|
13
|
+
|
|
14
|
+
_TIMEOUT = 5.0
|
|
15
|
+
_MAX_DIRTY_FILES = 20
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
async def collect_git_context(work_dir: HostPath) -> str:
|
|
19
|
+
"""Collect git context information for the explore agent.
|
|
20
|
+
|
|
21
|
+
Returns a formatted ``<git-context>`` block, or an empty string if the
|
|
22
|
+
directory is not a git repository or all git commands fail. Every git
|
|
23
|
+
command is individually guarded so a single failure never breaks the whole
|
|
24
|
+
collection.
|
|
25
|
+
"""
|
|
26
|
+
cwd = str(work_dir)
|
|
27
|
+
|
|
28
|
+
# Quick check: is this a git repo?
|
|
29
|
+
if await _run_git(["rev-parse", "--is-inside-work-tree"], cwd) is None:
|
|
30
|
+
return ""
|
|
31
|
+
|
|
32
|
+
# Run all git commands in parallel for speed
|
|
33
|
+
remote_url, branch, dirty_raw, log_raw = await asyncio.gather(
|
|
34
|
+
_run_git(["remote", "get-url", "origin"], cwd),
|
|
35
|
+
_run_git(["branch", "--show-current"], cwd),
|
|
36
|
+
_run_git(["status", "--porcelain"], cwd),
|
|
37
|
+
_run_git(["log", "-3", "--format=%h %s"], cwd),
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
sections: list[str] = []
|
|
41
|
+
sections.append(f"Working directory: {cwd}")
|
|
42
|
+
|
|
43
|
+
# Remote origin & project name
|
|
44
|
+
if remote_url:
|
|
45
|
+
safe_url = _sanitize_remote_url(remote_url)
|
|
46
|
+
if safe_url:
|
|
47
|
+
sections.append(f"Remote: {safe_url}")
|
|
48
|
+
project = _parse_project_name(remote_url)
|
|
49
|
+
if project:
|
|
50
|
+
sections.append(f"Project: {project}")
|
|
51
|
+
|
|
52
|
+
# Current branch
|
|
53
|
+
if branch:
|
|
54
|
+
sections.append(f"Branch: {branch}")
|
|
55
|
+
|
|
56
|
+
# Dirty files
|
|
57
|
+
if dirty_raw is not None:
|
|
58
|
+
dirty_lines = [line for line in dirty_raw.splitlines() if line.strip()]
|
|
59
|
+
if dirty_lines:
|
|
60
|
+
total = len(dirty_lines)
|
|
61
|
+
shown = dirty_lines[:_MAX_DIRTY_FILES]
|
|
62
|
+
header = f"Dirty files ({total}):"
|
|
63
|
+
body = "\n".join(f" {line}" for line in shown)
|
|
64
|
+
if total > _MAX_DIRTY_FILES:
|
|
65
|
+
body += f"\n ... and {total - _MAX_DIRTY_FILES} more"
|
|
66
|
+
sections.append(f"{header}\n{body}")
|
|
67
|
+
|
|
68
|
+
# Recent commits
|
|
69
|
+
if log_raw:
|
|
70
|
+
log_lines = [line for line in log_raw.splitlines() if line.strip()]
|
|
71
|
+
if log_lines:
|
|
72
|
+
body = "\n".join(f" {line[:200]}" for line in log_lines)
|
|
73
|
+
sections.append(f"Recent commits:\n{body}")
|
|
74
|
+
|
|
75
|
+
if len(sections) <= 1:
|
|
76
|
+
# Only the working directory line — nothing useful collected
|
|
77
|
+
return ""
|
|
78
|
+
|
|
79
|
+
content = "\n".join(sections)
|
|
80
|
+
return f"<git-context>\n{content}\n</git-context>"
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
async def _run_git(args: list[str], cwd: str, timeout: float = _TIMEOUT) -> str | None:
|
|
84
|
+
"""Run one git command via pythinker_host.exec.
|
|
85
|
+
|
|
86
|
+
Return stripped stdout, or None on failure.
|
|
87
|
+
|
|
88
|
+
Uses ``git -C <cwd>`` so the command runs in the specified directory
|
|
89
|
+
regardless of the host backend's current working directory. Works
|
|
90
|
+
transparently on both local and remote (SSH) backends.
|
|
91
|
+
"""
|
|
92
|
+
proc = None
|
|
93
|
+
try:
|
|
94
|
+
proc = await pythinker_host.exec("git", "-C", cwd, *args)
|
|
95
|
+
proc.stdin.close()
|
|
96
|
+
stdout_bytes = await asyncio.wait_for(proc.stdout.read(-1), timeout=timeout)
|
|
97
|
+
exit_code = await asyncio.wait_for(proc.wait(), timeout=timeout)
|
|
98
|
+
if exit_code != 0:
|
|
99
|
+
return None
|
|
100
|
+
return stdout_bytes.decode("utf-8", errors="replace").strip()
|
|
101
|
+
except TimeoutError:
|
|
102
|
+
logger.debug("git {args} timed out after {t}s", args=args, t=timeout)
|
|
103
|
+
if proc is not None:
|
|
104
|
+
await proc.kill()
|
|
105
|
+
await proc.wait()
|
|
106
|
+
return None
|
|
107
|
+
except Exception:
|
|
108
|
+
logger.debug("git {args} failed", args=args)
|
|
109
|
+
if proc is not None and proc.returncode is None:
|
|
110
|
+
await proc.kill()
|
|
111
|
+
await proc.wait()
|
|
112
|
+
return None
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
# Well-known public hosts whose remote URLs are safe to surface and
|
|
116
|
+
# recognizable enough for the model to infer project ecosystem context.
|
|
117
|
+
_ALLOWED_HOSTS = (
|
|
118
|
+
"github.com",
|
|
119
|
+
"gitlab.com",
|
|
120
|
+
"gitee.com",
|
|
121
|
+
"bitbucket.org",
|
|
122
|
+
"codeberg.org",
|
|
123
|
+
"sr.ht",
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def _sanitize_remote_url(remote_url: str) -> str | None:
|
|
128
|
+
"""Return the remote URL if it points to a well-known public host.
|
|
129
|
+
|
|
130
|
+
Credentials are stripped from HTTPS URLs.
|
|
131
|
+
|
|
132
|
+
Recognizable remote URLs help orient the agent within the broader project
|
|
133
|
+
ecosystem (e.g. issue tracker conventions, CI patterns). Self-hosted or
|
|
134
|
+
unrecognized hosts are excluded to avoid leaking internal infrastructure.
|
|
135
|
+
"""
|
|
136
|
+
# SSH format: git@host:owner/repo.git — no credentials possible
|
|
137
|
+
for host in _ALLOWED_HOSTS:
|
|
138
|
+
if re.match(rf"^git@{re.escape(host)}:", remote_url):
|
|
139
|
+
return remote_url
|
|
140
|
+
|
|
141
|
+
# HTTPS format: parse hostname exactly, strip userinfo
|
|
142
|
+
try:
|
|
143
|
+
parsed = urlparse(remote_url)
|
|
144
|
+
_ = parsed.port # raises ValueError on malformed port like :443.evil
|
|
145
|
+
except ValueError:
|
|
146
|
+
return None
|
|
147
|
+
if parsed.hostname in _ALLOWED_HOSTS:
|
|
148
|
+
# Rebuild without userinfo: https://host[:port]/path
|
|
149
|
+
port_part = f":{parsed.port}" if parsed.port else ""
|
|
150
|
+
return f"https://{parsed.hostname}{port_part}{parsed.path}"
|
|
151
|
+
|
|
152
|
+
return None
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def _parse_project_name(remote_url: str) -> str | None:
|
|
156
|
+
"""Extract ``owner/repo`` from a git remote URL.
|
|
157
|
+
|
|
158
|
+
Supports typical SSH (e.g. ``git@github.com:owner/repo.git``,
|
|
159
|
+
``git@gitlab.com:owner/repo.git``) and HTTPS (e.g.
|
|
160
|
+
``https://github.com/owner/repo.git``,
|
|
161
|
+
``https://gitee.com/owner/repo.git``) formats by taking the
|
|
162
|
+
trailing ``owner/repo`` component regardless of host.
|
|
163
|
+
"""
|
|
164
|
+
# SSH format: git@host:owner/repo.git
|
|
165
|
+
m = re.search(r":([^/]+/[^/]+?)(?:\.git)?$", remote_url)
|
|
166
|
+
if m:
|
|
167
|
+
return m.group(1)
|
|
168
|
+
# HTTPS format: https://host/owner/repo.git
|
|
169
|
+
m = re.search(r"/([^/]+/[^/]+?)(?:\.git)?$", remote_url)
|
|
170
|
+
if m:
|
|
171
|
+
return m.group(1)
|
|
172
|
+
return None
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
from dataclasses import dataclass, field
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Literal
|
|
7
|
+
|
|
8
|
+
type ToolPolicyMode = Literal["inherit", "allowlist"]
|
|
9
|
+
type SubagentStatus = Literal[
|
|
10
|
+
"idle",
|
|
11
|
+
"running_foreground",
|
|
12
|
+
"running_background",
|
|
13
|
+
"completed",
|
|
14
|
+
"failed",
|
|
15
|
+
"killed",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass(frozen=True, slots=True, kw_only=True)
|
|
20
|
+
class ToolPolicy:
|
|
21
|
+
mode: ToolPolicyMode
|
|
22
|
+
tools: tuple[str, ...] = ()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass(frozen=True, slots=True, kw_only=True)
|
|
26
|
+
class AgentTypeDefinition:
|
|
27
|
+
name: str
|
|
28
|
+
description: str
|
|
29
|
+
agent_file: Path
|
|
30
|
+
when_to_use: str = ""
|
|
31
|
+
default_model: str | None = None
|
|
32
|
+
tool_policy: ToolPolicy = field(default_factory=lambda: ToolPolicy(mode="inherit"))
|
|
33
|
+
supports_background: bool = True
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@dataclass(frozen=True, slots=True, kw_only=True)
|
|
37
|
+
class AgentLaunchSpec:
|
|
38
|
+
agent_id: str
|
|
39
|
+
subagent_type: str
|
|
40
|
+
model_override: str | None
|
|
41
|
+
effective_model: str | None
|
|
42
|
+
thinking: bool | None = None
|
|
43
|
+
variant: str | None = None
|
|
44
|
+
created_at: float = field(default_factory=time.time)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@dataclass(frozen=True, slots=True, kw_only=True)
|
|
48
|
+
class AgentInstanceRecord:
|
|
49
|
+
agent_id: str
|
|
50
|
+
subagent_type: str
|
|
51
|
+
status: SubagentStatus
|
|
52
|
+
description: str
|
|
53
|
+
created_at: float
|
|
54
|
+
updated_at: float
|
|
55
|
+
last_task_id: str | None
|
|
56
|
+
launch_spec: AgentLaunchSpec
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""Unified output writer for subagent executions (foreground and background)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Sequence
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from pythinker_core.message import TextPart, ToolCall, ToolCallPart
|
|
9
|
+
from pythinker_core.tooling import ToolResult
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class SubagentOutputWriter:
|
|
13
|
+
"""Appends human-readable transcript lines to one or more output files.
|
|
14
|
+
|
|
15
|
+
Both foreground and background runners use this so the output format
|
|
16
|
+
is identical regardless of execution mode. When *extra_paths* are
|
|
17
|
+
provided every write is tee'd to those files as well (used by the
|
|
18
|
+
background agent runner to keep the task ``output.log`` in sync with
|
|
19
|
+
the canonical subagent output).
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def __init__(self, path: Path, *, extra_paths: Sequence[Path] = ()) -> None:
|
|
23
|
+
self._path = path
|
|
24
|
+
self._extra_paths = extra_paths
|
|
25
|
+
|
|
26
|
+
def stage(self, name: str) -> None:
|
|
27
|
+
self._append(f"[stage] {name}\n")
|
|
28
|
+
|
|
29
|
+
def tool_call(self, tc: ToolCall) -> None:
|
|
30
|
+
name = tc.function.name if tc.function else "?"
|
|
31
|
+
self._append(f"[tool] {name}\n")
|
|
32
|
+
|
|
33
|
+
def tool_result(self, tr: ToolResult) -> None:
|
|
34
|
+
status = "error" if tr.return_value.is_error else "success"
|
|
35
|
+
brief = getattr(tr.return_value, "brief", None)
|
|
36
|
+
if brief:
|
|
37
|
+
self._append(f"[tool_result] {status}: {brief}\n")
|
|
38
|
+
else:
|
|
39
|
+
self._append(f"[tool_result] {status}\n")
|
|
40
|
+
|
|
41
|
+
def text(self, text: str) -> None:
|
|
42
|
+
if text:
|
|
43
|
+
self._append(text)
|
|
44
|
+
|
|
45
|
+
def summary(self, text: str) -> None:
|
|
46
|
+
if text:
|
|
47
|
+
self._append(f"\n[summary]\n{text}\n")
|
|
48
|
+
|
|
49
|
+
def error(self, message: str) -> None:
|
|
50
|
+
self._append(f"[error] {message}\n")
|
|
51
|
+
|
|
52
|
+
def write_wire_message(self, msg: object) -> None:
|
|
53
|
+
"""Dispatch a wire message to the appropriate writer method."""
|
|
54
|
+
if isinstance(msg, TextPart):
|
|
55
|
+
self.text(msg.text)
|
|
56
|
+
elif isinstance(msg, ToolCall):
|
|
57
|
+
self.tool_call(msg)
|
|
58
|
+
elif isinstance(msg, ToolResult):
|
|
59
|
+
self.tool_result(msg)
|
|
60
|
+
elif isinstance(msg, ToolCallPart):
|
|
61
|
+
pass # incremental argument chunks — not useful in transcript
|
|
62
|
+
|
|
63
|
+
def _append(self, text: str) -> None:
|
|
64
|
+
with self._path.open("a", encoding="utf-8") as f:
|
|
65
|
+
f.write(text)
|
|
66
|
+
for p in self._extra_paths:
|
|
67
|
+
try:
|
|
68
|
+
with p.open("a", encoding="utf-8") as f:
|
|
69
|
+
f.write(text)
|
|
70
|
+
except OSError:
|
|
71
|
+
pass # best-effort — never interrupt the agent for a tee failure
|