micro-cc 0.2.78__tar.gz → 0.2.81__tar.gz
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.
- micro_cc-0.2.81/LICENSE +21 -0
- micro_cc-0.2.81/PKG-INFO +105 -0
- micro_cc-0.2.81/README.md +38 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/pyproject.toml +2 -3
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/browser/_md_convert.py +12 -19
- micro_cc-0.2.81/src/micro_cc/cache/state_store.py +197 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/claude_loop_.py +36 -65
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/execute_tool.py +5 -1
- micro_cc-0.2.81/src/micro_cc/models/__init__.py +6 -0
- micro_cc-0.2.81/src/micro_cc/models/adapters/__init__.py +1 -0
- micro_cc-0.2.81/src/micro_cc/models/adapters/anthropic.py +95 -0
- micro_cc-0.2.81/src/micro_cc/models/adapters/chat.py +108 -0
- micro_cc-0.2.81/src/micro_cc/models/adapters/responses.py +74 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/models/anthropic.py +49 -118
- micro_cc-0.2.81/src/micro_cc/models/client.py +65 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/models/foundry.py +8 -86
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/models/litellm.py +26 -235
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/models/ollama.py +16 -166
- micro_cc-0.2.81/src/micro_cc/models/openai.py +569 -0
- micro_cc-0.2.81/src/micro_cc/models/priming.py +38 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/models/registry.py +17 -10
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/models/schema.py +22 -0
- micro_cc-0.2.81/src/micro_cc/models/types.py +59 -0
- {micro_cc-0.2.78/src/micro_cc/utils → micro_cc-0.2.81/src/micro_cc/postgres_store}/pg_store_.py +75 -89
- micro_cc-0.2.81/src/micro_cc/postgres_store/schema_.py +109 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/graph-orchestration/SKILL.md +12 -1
- micro_cc-0.2.81/src/micro_cc/skills/system-design-review/REFERENCE.md +174 -0
- micro_cc-0.2.81/src/micro_cc/skills/system-design-review/SKILL.md +161 -0
- micro_cc-0.2.81/src/micro_cc/skills/system-design-review/scripts/design_graph.py +290 -0
- micro_cc-0.2.81/src/micro_cc/skills/system-design-review/scripts/design_review.py +528 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/start_headless_.py +9 -5
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/start_live_tui_.py +75 -27
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/tools/bash_tool.py +86 -2
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/tools/file_tools_.py +2 -2
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/tools/memory_tool_.py +10 -35
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/tools/monitor_.py +34 -5
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/tools/monitor_watch_.py +7 -10
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/tools/todo_tools_.py +6 -6
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/tools/vision_tools_.py +6 -28
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/tui_native/alt_screen_.py +16 -6
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/tui_native/detect_images_.py +29 -40
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/tui_native/diff_viewer_.py +2 -3
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/tui_native/etype_handler_.py +24 -3
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/tui_native/keys_.py +27 -33
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/tui_native/kill_ring_.py +6 -10
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/tui_native/list_picker_.py +3 -7
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/tui_native/message_row_.py +31 -43
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/tui_native/prompt_input_.py +7 -9
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/tui_native/screen_cmds_.py +3 -7
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/tui_native/stack_.py +23 -30
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/tui_native/stdin_buffer_.py +16 -21
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/tui_native/terminal_.py +16 -30
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/tui_native/text_.py +28 -32
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/tui_native/text_utils_.py +10 -12
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/tui_native/theme_.py +3 -4
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/tui_native/truncated_text_.py +7 -9
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/tui_native/undo_stack_.py +7 -10
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/tui_native/word_navigation_.py +10 -28
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/utils/claude_subscription.py +10 -12
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/utils/command_registry.py +0 -6
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/utils/helpers.py +22 -7
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/utils/hidden_prompts.py +0 -32
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/utils/memory_store_.py +31 -1
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/utils/msg_store_.py +78 -72
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/utils/settings_store_.py +41 -9
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/utils/status_marker.py +4 -5
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/utils/subagent_tracker_.py +29 -3
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/utils/tokenization_simple.py +146 -13
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/webui/bridge.py +2 -4
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/webui/server.py +2 -2
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/webui/session.py +6 -5
- micro_cc-0.2.81/src/micro_cc.egg-info/PKG-INFO +105 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc.egg-info/SOURCES.txt +19 -9
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc.egg-info/entry_points.txt +0 -1
- micro_cc-0.2.81/tests/test_model_consumers.py +168 -0
- micro_cc-0.2.81/tests/test_models.py +438 -0
- micro_cc-0.2.78/LICENSE +0 -18
- micro_cc-0.2.78/PKG-INFO +0 -200
- micro_cc-0.2.78/README.md +0 -136
- micro_cc-0.2.78/src/micro_cc/cache/redis_cache.py +0 -178
- micro_cc-0.2.78/src/micro_cc/code_test/run_token_cutter.py +0 -61
- micro_cc-0.2.78/src/micro_cc/code_test/test_messages.py +0 -127
- micro_cc-0.2.78/src/micro_cc/skills/autoresearch/SKILL.md +0 -69
- micro_cc-0.2.78/src/micro_cc/start_batch_.py +0 -127
- micro_cc-0.2.78/src/micro_cc/start_watch_.py +0 -104
- micro_cc-0.2.78/src/micro_cc/webui/__init__.py +0 -0
- micro_cc-0.2.78/src/micro_cc.egg-info/PKG-INFO +0 -200
- {micro_cc-0.2.78 → micro_cc-0.2.81}/setup.cfg +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/__init__.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/browser/__init__.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/browser/_cookies.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/browser/browser_manager.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/browser/simpletextbrowser.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/cache/__init__.py +0 -0
- {micro_cc-0.2.78/src/micro_cc/code_test → micro_cc-0.2.81/src/micro_cc/postgres_store}/__init__.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/SKILL.md +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/ArsenalSC-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/ArsenalSC-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/BigShoulders-Bold.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/BigShoulders-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/BigShoulders-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/Boldonse-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/Boldonse-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/BricolageGrotesque-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/CrimsonPro-Bold.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/CrimsonPro-Italic.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/CrimsonPro-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/CrimsonPro-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/DMMono-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/DMMono-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/EricaOne-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/EricaOne-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/GeistMono-Bold.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/GeistMono-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/GeistMono-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/Gloock-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/Gloock-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/IBMPlexMono-Bold.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/IBMPlexMono-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/IBMPlexMono-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/IBMPlexSerif-Bold.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/IBMPlexSerif-BoldItalic.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/IBMPlexSerif-Italic.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/IBMPlexSerif-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/InstrumentSans-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/Italiana-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/Italiana-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/JetBrainsMono-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/Jura-Light.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/Jura-Medium.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/Jura-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/LibreBaskerville-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/LibreBaskerville-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/Lora-Bold.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/Lora-BoldItalic.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/Lora-Italic.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/Lora-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/Lora-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/NationalPark-Bold.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/NationalPark-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/NationalPark-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/NothingYouCouldDo-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/Outfit-Bold.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/Outfit-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/Outfit-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/PixelifySans-Medium.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/PixelifySans-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/PoiretOne-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/PoiretOne-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/RedHatMono-Bold.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/RedHatMono-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/RedHatMono-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/Silkscreen-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/Silkscreen-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/SmoochSans-Medium.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/SmoochSans-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/Tektur-Medium.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/Tektur-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/Tektur-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/WorkSans-Bold.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/WorkSans-BoldItalic.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/WorkSans-Italic.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/WorkSans-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/WorkSans-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/YoungSerif-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/canvas-fonts/YoungSerif-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/design/references/blueprint-tokens.md +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/github/SKILL.md +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/pptx/SKILL.md +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/pptx/brief.md +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/pptx/scripts/build_deck.js +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/pptx/scripts/deck_to_images.py +0 -0
- {micro_cc-0.2.78/src/micro_cc/models → micro_cc-0.2.81/src/micro_cc/skills/pptx/scripts/office}/__init__.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/pptx/scripts/office/soffice.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/pptx/scripts/render_svg.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/pptx/svg-slides.md +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/skill_loader.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/skills/xlsx/SKILL.md +0 -0
- {micro_cc-0.2.78/src/micro_cc/skills/pptx/scripts/office → micro_cc-0.2.81/src/micro_cc/tools}/__init__.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/tools/ask_user_tool.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/tools/browser_tool_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/tools/computer_tool_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/tools/mcp_client_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/tools/message_session_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/tools/search_history_tool_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/tools/search_tool_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/tools/skill_tools_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/tools/web_tools_.py +0 -0
- {micro_cc-0.2.78/src/micro_cc/tools → micro_cc-0.2.81/src/micro_cc/tui_native}/__init__.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/tui_native/md_render_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/tui_native/multi_select_list_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/tui_native/question_panel_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/tui_native/scroll_view_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/tui_native/self_terminal_setup_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/tui_native/self_update_.py +0 -0
- {micro_cc-0.2.78/src/micro_cc/tui_native → micro_cc-0.2.81/src/micro_cc/utils}/__init__.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/utils/annotate_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/utils/banner_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/utils/claude_md_loader.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/utils/default_status_sh.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/utils/hints.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/utils/history_mount_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/utils/inbox_store_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/utils/msg_normalize_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/utils/project_files_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/utils/session_ipc_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/utils/terminal_setup.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/utils/tool_limits.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/utils/tool_result_storage.py +0 -0
- {micro_cc-0.2.78/src/micro_cc/utils → micro_cc-0.2.81/src/micro_cc/webui}/__init__.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/webui/dist/assets/index-9B5FcRm2.css +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/webui/dist/assets/index-CDG9HO3B.js +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/webui/dist/index.html +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/webui/history.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc/webui/launch.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc.egg-info/dependency_links.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc.egg-info/requires.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.81}/src/micro_cc.egg-info/top_level.txt +0 -0
micro_cc-0.2.81/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 George Salapa
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
micro_cc-0.2.81/PKG-INFO
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: micro-cc
|
|
3
|
+
Version: 0.2.81
|
|
4
|
+
Summary: Harness that gives frontier models full system access — shell, filesystem, browser, MCP — running directly on the metal.
|
|
5
|
+
Author: George Salapa
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 George Salapa
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
29
|
+
Requires-Python: >=3.12
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
License-File: LICENSE
|
|
32
|
+
Requires-Dist: anthropic>=0.76.0
|
|
33
|
+
Requires-Dist: anyio>=4.0
|
|
34
|
+
Requires-Dist: beautifulsoup4>=4.14
|
|
35
|
+
Requires-Dist: fastapi>=0.135
|
|
36
|
+
Requires-Dist: google-search-results>=2.4
|
|
37
|
+
Requires-Dist: httpx>=0.28
|
|
38
|
+
Requires-Dist: httpx-sse>=0.4
|
|
39
|
+
Requires-Dist: lxml>=6.0
|
|
40
|
+
Requires-Dist: mammoth>=1.11
|
|
41
|
+
Requires-Dist: markdown-it-py>=4.0
|
|
42
|
+
Requires-Dist: markdownify>=1.2
|
|
43
|
+
Requires-Dist: mcp>=1.26
|
|
44
|
+
Requires-Dist: numpy>=2.4
|
|
45
|
+
Requires-Dist: openai>=2.16
|
|
46
|
+
Requires-Dist: openpyxl>=3.1
|
|
47
|
+
Requires-Dist: pathvalidate>=3.3
|
|
48
|
+
Requires-Dist: pdfminer.six>=20260107
|
|
49
|
+
Requires-Dist: pillow>=12.0
|
|
50
|
+
Requires-Dist: playwright>=1.58
|
|
51
|
+
Requires-Dist: prompt_toolkit>=3.0
|
|
52
|
+
Requires-Dist: puremagic>=1.30
|
|
53
|
+
Requires-Dist: PyAutoGUI>=0.9
|
|
54
|
+
Requires-Dist: pydantic>=2.12
|
|
55
|
+
Requires-Dist: pydantic-settings>=2.13
|
|
56
|
+
Requires-Dist: pyperclip>=1.9
|
|
57
|
+
Requires-Dist: python-dotenv>=1.2
|
|
58
|
+
Requires-Dist: python-pptx>=1.0
|
|
59
|
+
Requires-Dist: requests>=2.32
|
|
60
|
+
Requires-Dist: rich>=14.0
|
|
61
|
+
Requires-Dist: uvicorn>=0.42
|
|
62
|
+
Requires-Dist: xlsxwriter>=3.2
|
|
63
|
+
Requires-Dist: youtube-transcript-api>=1.2
|
|
64
|
+
Provides-Extra: postgres
|
|
65
|
+
Requires-Dist: psycopg[binary]>=3.2; extra == "postgres"
|
|
66
|
+
Dynamic: license-file
|
|
67
|
+
|
|
68
|
+
# micro · cc — cognitive compute
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
88
|
|
72
|
+
""
|
|
73
|
+
|
|
74
|
+
88,dPYba,,adPYba, 88 ,adPPYba, 8b,dPPYba, ,adPPYba, ,adPPYba, ,adPPYba,
|
|
75
|
+
88P' "88" "8a 88 a8" "" 88P' "Y8 a8" "8a a8" "" a8" ""
|
|
76
|
+
88 88 88 88 8b 88 8b d8 · 8b 8b
|
|
77
|
+
88 88 88 88 "8a, ,aa 88 "8a, ,a8" "8a, ,aa "8a, ,aa
|
|
78
|
+
88 88 88 88 `"Ybbd8"' 88 `"YbbdP"' `"Ybbd8"' `"Ybbd8"'
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
> Knowledge work is, by extension, a coding problem.
|
|
82
|
+
|
|
83
|
+
Frontier models with full system access — shell, filesystem, browser, MCP. Verbose, thorough planning paired with unrestricted file operations lets micro·cc take on complex multi-step work autonomously. Point it at any project directory and go.
|
|
84
|
+
|
|
85
|
+
## Install
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
pip install micro-cc
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
macOS and WSL only — both are real POSIX/bash environments, which the `bash_` tool requires. On Windows, install WSL first, then run `pip install micro-cc` *inside* the WSL shell.
|
|
92
|
+
|
|
93
|
+
## Usage
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
microcc /path/to/your/project
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
First run, type `/login` to configure your model endpoint. Type `/` inside the app for the full command list — it's always current with what's actually built.
|
|
100
|
+
|
|
101
|
+
Non-interactive entry point: `microcc-headless` (single prompt, cron-friendly). Run with `--help` for usage.
|
|
102
|
+
|
|
103
|
+
## License
|
|
104
|
+
|
|
105
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# micro · cc — cognitive compute
|
|
2
|
+
|
|
3
|
+
```
|
|
4
|
+
88
|
|
5
|
+
""
|
|
6
|
+
|
|
7
|
+
88,dPYba,,adPYba, 88 ,adPPYba, 8b,dPPYba, ,adPPYba, ,adPPYba, ,adPPYba,
|
|
8
|
+
88P' "88" "8a 88 a8" "" 88P' "Y8 a8" "8a a8" "" a8" ""
|
|
9
|
+
88 88 88 88 8b 88 8b d8 · 8b 8b
|
|
10
|
+
88 88 88 88 "8a, ,aa 88 "8a, ,a8" "8a, ,aa "8a, ,aa
|
|
11
|
+
88 88 88 88 `"Ybbd8"' 88 `"YbbdP"' `"Ybbd8"' `"Ybbd8"'
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
> Knowledge work is, by extension, a coding problem.
|
|
15
|
+
|
|
16
|
+
Frontier models with full system access — shell, filesystem, browser, MCP. Verbose, thorough planning paired with unrestricted file operations lets micro·cc take on complex multi-step work autonomously. Point it at any project directory and go.
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pip install micro-cc
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
macOS and WSL only — both are real POSIX/bash environments, which the `bash_` tool requires. On Windows, install WSL first, then run `pip install micro-cc` *inside* the WSL shell.
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
microcc /path/to/your/project
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
First run, type `/login` to configure your model endpoint. Type `/` inside the app for the full command list — it's always current with what's actually built.
|
|
33
|
+
|
|
34
|
+
Non-interactive entry point: `microcc-headless` (single prompt, cron-friendly). Run with `--help` for usage.
|
|
35
|
+
|
|
36
|
+
## License
|
|
37
|
+
|
|
38
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -4,13 +4,13 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "micro-cc"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.81"
|
|
8
8
|
description = "Harness that gives frontier models full system access — shell, filesystem, browser, MCP — running directly on the metal."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.12"
|
|
11
11
|
license = {file = "LICENSE"}
|
|
12
12
|
authors = [{name = "George Salapa"}]
|
|
13
|
-
classifiers = ["License ::
|
|
13
|
+
classifiers = ["License :: OSI Approved :: MIT License"]
|
|
14
14
|
|
|
15
15
|
dependencies = [
|
|
16
16
|
"anthropic>=0.76.0",
|
|
@@ -53,7 +53,6 @@ postgres = ["psycopg[binary]>=3.2"]
|
|
|
53
53
|
[project.scripts]
|
|
54
54
|
microcc = "micro_cc.start_live_tui_:start_"
|
|
55
55
|
microcc-headless = "micro_cc.start_headless_:start_headless_"
|
|
56
|
-
microcc-batch = "micro_cc.start_batch_:start_batch_"
|
|
57
56
|
|
|
58
57
|
[tool.setuptools.packages.find]
|
|
59
58
|
where = ["src"]
|
|
@@ -24,7 +24,8 @@ import os
|
|
|
24
24
|
import re
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
from micro_cc.
|
|
27
|
+
from micro_cc.models import model_call
|
|
28
|
+
from micro_cc.utils import settings_store_
|
|
28
29
|
|
|
29
30
|
|
|
30
31
|
class _CustomMarkdownify(markdownify.MarkdownConverter):
|
|
@@ -639,26 +640,18 @@ class ImageConverter(MediaConverter):
|
|
|
639
640
|
def _get_image_description(self, local_path, extension):
|
|
640
641
|
prompt = "Write a detailed caption for this image."
|
|
641
642
|
|
|
642
|
-
data_uri = ""
|
|
643
643
|
with open(local_path, "rb") as image_file:
|
|
644
|
-
content_type, encoding = mimetypes.guess_type("_dummy" + extension)
|
|
645
|
-
if content_type is None:
|
|
646
|
-
content_type = "image/jpeg"
|
|
647
644
|
image_base64 = base64.b64encode(image_file.read()).decode("utf-8")
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
else:
|
|
659
|
-
from micro_cc.models.anthropic import a_model_call
|
|
660
|
-
response = asyncio.run(a_model_call(input=prompt, encoded_image=data_uri))
|
|
661
|
-
return response.content[0].text
|
|
645
|
+
|
|
646
|
+
# Providers add their own image envelope; encoded_image is bare base64.
|
|
647
|
+
# Use the selected model rather than a Claude default on OpenAI/Ollama.
|
|
648
|
+
response = asyncio.run(model_call(
|
|
649
|
+
input=prompt, encoded_image=image_base64,
|
|
650
|
+
model=settings_store_.get_setting("model"),
|
|
651
|
+
))
|
|
652
|
+
if response is None:
|
|
653
|
+
return ""
|
|
654
|
+
return "\n".join(block.text for block in response.content if block.type == "text")
|
|
662
655
|
|
|
663
656
|
|
|
664
657
|
class FileConversionException(BaseException):
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import time
|
|
3
|
+
import threading
|
|
4
|
+
from typing import Dict, Optional, Any
|
|
5
|
+
|
|
6
|
+
logger = logging.getLogger(__name__)
|
|
7
|
+
|
|
8
|
+
# In-memory, single-process state store for the running project's loop state
|
|
9
|
+
# (todos, discovered tools/MCPs, streaming flag). microcc is always one user
|
|
10
|
+
# in one process, so a namespaced module-level dict with per-entry TTLs is
|
|
11
|
+
# all this needs — no separate process, no connection, no serialization
|
|
12
|
+
# boundary to manage.
|
|
13
|
+
|
|
14
|
+
_NAMESPACE = "micro_cc"
|
|
15
|
+
|
|
16
|
+
_store: Dict[str, Dict[str, Any]] = {}
|
|
17
|
+
_lock = threading.RLock() # reentrant, since some ops call other ops while holding it
|
|
18
|
+
_cleanup_running = False
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _make_key(key_type: str, *parts: str) -> str:
|
|
22
|
+
"""Generate namespaced key"""
|
|
23
|
+
return f"{_NAMESPACE}:{key_type}:" + ":".join(parts)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _set_with_ttl(key: str, value: Any, ttl: int) -> None:
|
|
27
|
+
"""Set value with expiration timestamp"""
|
|
28
|
+
expiry = time.time() + ttl
|
|
29
|
+
with _lock:
|
|
30
|
+
_store[key] = {"value": value, "expiry": expiry}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _get(key: str) -> Optional[Any]:
|
|
34
|
+
"""Get value if not expired, cleanup if expired"""
|
|
35
|
+
with _lock:
|
|
36
|
+
if key not in _store:
|
|
37
|
+
return None
|
|
38
|
+
entry = _store[key]
|
|
39
|
+
if time.time() > entry["expiry"]:
|
|
40
|
+
del _store[key]
|
|
41
|
+
return None
|
|
42
|
+
return entry["value"]
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _delete(key: str) -> None:
|
|
46
|
+
"""Delete key"""
|
|
47
|
+
with _lock:
|
|
48
|
+
_store.pop(key, None)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _cleanup_expired() -> None:
|
|
52
|
+
"""Background task to clean up expired entries"""
|
|
53
|
+
while _cleanup_running:
|
|
54
|
+
time.sleep(60) # Run every minute
|
|
55
|
+
current_time = time.time()
|
|
56
|
+
with _lock:
|
|
57
|
+
expired_keys = [
|
|
58
|
+
k for k, v in _store.items() if current_time > v["expiry"]
|
|
59
|
+
]
|
|
60
|
+
for key in expired_keys:
|
|
61
|
+
del _store[key]
|
|
62
|
+
if expired_keys:
|
|
63
|
+
logger.debug("Cleaned up %d expired state entries", len(expired_keys))
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def start_cleanup_task() -> None:
|
|
67
|
+
"""Start background cleanup thread"""
|
|
68
|
+
global _cleanup_running
|
|
69
|
+
if not _cleanup_running:
|
|
70
|
+
_cleanup_running = True
|
|
71
|
+
cleanup_thread = threading.Thread(
|
|
72
|
+
target=_cleanup_expired, daemon=True, name="StateCleanup"
|
|
73
|
+
)
|
|
74
|
+
cleanup_thread.start()
|
|
75
|
+
logger.debug("State cleanup task started")
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def stop_cleanup_task() -> None:
|
|
79
|
+
"""Stop background cleanup thread"""
|
|
80
|
+
global _cleanup_running
|
|
81
|
+
_cleanup_running = False
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
# ========================= Todos =========================
|
|
85
|
+
# Stored as the raw dict (in-memory store, no serialization needed).
|
|
86
|
+
# Keyed by project_dir, same TTL as plan.
|
|
87
|
+
|
|
88
|
+
def set_todos(project_dir: str, todos: dict) -> None:
|
|
89
|
+
"""Persist the todo store (id -> {content, status, notes, ...})."""
|
|
90
|
+
try:
|
|
91
|
+
key = _make_key("todos", project_dir)
|
|
92
|
+
_set_with_ttl(key, todos, 3600)
|
|
93
|
+
except Exception as e:
|
|
94
|
+
logger.warning("State error in set_todos: %s", e)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def get_todos(project_dir: str) -> Optional[dict]:
|
|
98
|
+
"""Return the todo store dict, or None if unset/expired."""
|
|
99
|
+
try:
|
|
100
|
+
key = _make_key("todos", project_dir)
|
|
101
|
+
return _get(key)
|
|
102
|
+
except Exception as e:
|
|
103
|
+
logger.warning("State error in get_todos: %s", e)
|
|
104
|
+
return None
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def clear_todos(project_dir: str) -> None:
|
|
108
|
+
"""Wipe the todo store for this project."""
|
|
109
|
+
try:
|
|
110
|
+
key = _make_key("todos", project_dir)
|
|
111
|
+
_delete(key)
|
|
112
|
+
except Exception as e:
|
|
113
|
+
logger.warning("State error in clear_todos: %s", e)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
##########################tool discovery
|
|
117
|
+
|
|
118
|
+
DISCOVERED_TOOLS_TTL = 180 # seconds of inactivity before re-discovery is required
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def get_discovered_tools(project_dir: str) -> set:
|
|
122
|
+
try:
|
|
123
|
+
key = _make_key("discovered_tools", project_dir)
|
|
124
|
+
data = _get(key)
|
|
125
|
+
if not data:
|
|
126
|
+
return set()
|
|
127
|
+
return set(data.get("discovered_tools", []))
|
|
128
|
+
except Exception as e:
|
|
129
|
+
logger.warning("State error in get_discovered_tools: %s", e)
|
|
130
|
+
return set()
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def add_discovered_tools(project_dir: str, tools: list) -> None:
|
|
134
|
+
try:
|
|
135
|
+
existing = get_discovered_tools(project_dir)
|
|
136
|
+
existing.update(tools)
|
|
137
|
+
data = {"discovered_tools": list(existing)}
|
|
138
|
+
key = _make_key("discovered_tools", project_dir)
|
|
139
|
+
_set_with_ttl(key, data, DISCOVERED_TOOLS_TTL)
|
|
140
|
+
except Exception as e:
|
|
141
|
+
logger.warning("State error in add_discovered_tools: %s", e)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def clear_discovered_tools(project_dir: str) -> None:
|
|
145
|
+
try:
|
|
146
|
+
key = _make_key("discovered_tools", project_dir)
|
|
147
|
+
_delete(key)
|
|
148
|
+
except Exception as e:
|
|
149
|
+
logger.warning("State error in clear_discovered_tools: %s", e)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
########################## mcp discovery
|
|
153
|
+
|
|
154
|
+
def get_discovered_mcps(project_dir: str) -> set:
|
|
155
|
+
try:
|
|
156
|
+
key = _make_key("discovered_mcps", project_dir)
|
|
157
|
+
data = _get(key)
|
|
158
|
+
if not data:
|
|
159
|
+
return set()
|
|
160
|
+
return set(data.get("discovered_mcps", []))
|
|
161
|
+
except Exception as e:
|
|
162
|
+
logger.warning("State error in get_discovered_mcps: %s", e)
|
|
163
|
+
return set()
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def add_discovered_mcps(project_dir: str, mcps: list) -> None:
|
|
167
|
+
try:
|
|
168
|
+
existing = get_discovered_mcps(project_dir)
|
|
169
|
+
existing.update(mcps)
|
|
170
|
+
data = {"discovered_mcps": list(existing)}
|
|
171
|
+
key = _make_key("discovered_mcps", project_dir)
|
|
172
|
+
_set_with_ttl(key, data, DISCOVERED_TOOLS_TTL)
|
|
173
|
+
except Exception as e:
|
|
174
|
+
logger.warning("State error in add_discovered_mcps: %s", e)
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def clear_discovered_mcps(project_dir: str) -> None:
|
|
178
|
+
try:
|
|
179
|
+
key = _make_key("discovered_mcps", project_dir)
|
|
180
|
+
_delete(key)
|
|
181
|
+
except Exception as e:
|
|
182
|
+
logger.warning("State error in clear_discovered_mcps: %s", e)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
########################## streaming state
|
|
186
|
+
|
|
187
|
+
def set_streaming_state(project_dir: str, active: bool) -> None:
|
|
188
|
+
key = _make_key("streaming", project_dir)
|
|
189
|
+
if active:
|
|
190
|
+
_set_with_ttl(key, True, 600)
|
|
191
|
+
else:
|
|
192
|
+
_delete(key)
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def get_streaming_state(project_dir: str) -> bool:
|
|
196
|
+
key = _make_key("streaming", project_dir)
|
|
197
|
+
return bool(_get(key))
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import datetime
|
|
3
|
-
import json
|
|
4
3
|
import os
|
|
5
4
|
from functools import partial
|
|
6
5
|
|
|
7
6
|
from dotenv import load_dotenv
|
|
8
7
|
|
|
9
|
-
from micro_cc.cache
|
|
8
|
+
from micro_cc.cache import state_store
|
|
10
9
|
from micro_cc.execute_tool import execute_tool_call
|
|
10
|
+
from micro_cc.models import model_call
|
|
11
11
|
from micro_cc.models.registry import DEFAULT_MODEL, DEFAULT_TRIM_BUDGET
|
|
12
12
|
from micro_cc.utils.tool_limits import cap_for, MAX_TOOL_RESULTS_PER_MESSAGE
|
|
13
13
|
from micro_cc.utils.tool_result_storage import persist_and_preview
|
|
@@ -33,7 +33,7 @@ from micro_cc.tools.search_tool_ import (
|
|
|
33
33
|
)
|
|
34
34
|
from micro_cc.tools.mcp_client_ import resolve_mcp_tools, call_mcp_tool
|
|
35
35
|
from micro_cc.utils.msg_store_ import load_summary, load_checkpoint, compact_checkpoint
|
|
36
|
-
from micro_cc.utils.tokenization_simple import token_cutter, token_stats, save_token_stats
|
|
36
|
+
from micro_cc.utils.tokenization_simple import token_cutter, token_stats, save_token_stats, detect_cache_miss
|
|
37
37
|
from micro_cc.utils.claude_md_loader import load_claude_md_file
|
|
38
38
|
from micro_cc.utils.helpers import get_endpoint
|
|
39
39
|
|
|
@@ -98,7 +98,7 @@ async def claude_loop(
|
|
|
98
98
|
|
|
99
99
|
surface identifies which caller is driving this turn — "tui" (the live
|
|
100
100
|
boss, start_live_.py's do_query), "gui" (webui/server.py's browser
|
|
101
|
-
handoff), or the default "headless" (start_headless_.py
|
|
101
|
+
handoff), or the default "headless" (start_headless_.py,
|
|
102
102
|
including a subagent spawned by /graph itself). Defaults to the most
|
|
103
103
|
restrictive value on purpose: only "tui" gets the self-invocation
|
|
104
104
|
invitation to start a /graph-style orchestration (see below) — the
|
|
@@ -123,7 +123,6 @@ async def claude_loop(
|
|
|
123
123
|
dangerous = DEFAULT_DANGEROUS if dangerous_tools is None else set(dangerous_tools)
|
|
124
124
|
ask_user = ASK_USER_QUESTION_TOOL
|
|
125
125
|
end_resp = get_endpoint()
|
|
126
|
-
redis_state = RedisStateManager()
|
|
127
126
|
|
|
128
127
|
skills_summary = get_skill_summary(project_dir)
|
|
129
128
|
claude_md_content = load_claude_md_file(project_dir)
|
|
@@ -178,7 +177,7 @@ async def claude_loop(
|
|
|
178
177
|
tools[tool.__name__] = tool
|
|
179
178
|
|
|
180
179
|
#########discovered tools
|
|
181
|
-
discovered_tools =
|
|
180
|
+
discovered_tools = state_store.get_discovered_tools(project_dir)
|
|
182
181
|
for tool_name in discovered_tools:
|
|
183
182
|
if tool_name not in tools:
|
|
184
183
|
tool_schemas.append(get_tool_schema(tool_name))
|
|
@@ -189,7 +188,7 @@ async def claude_loop(
|
|
|
189
188
|
# the MCP client (fetch tools, dispatch calls). Their auth stays local
|
|
190
189
|
# (mcp_client_.resolve_mcp_tools reads auth_env), never sent to a model
|
|
191
190
|
# provider. mcp_routing: {tool_name: {"url": server_url, "headers": dict}}
|
|
192
|
-
discovered_mcp =
|
|
191
|
+
discovered_mcp = state_store.get_discovered_mcps(project_dir)
|
|
193
192
|
mcp_routing = {}
|
|
194
193
|
resolved_mcp_names = set() # catalog/server names already fetched — avoids re-resolving
|
|
195
194
|
|
|
@@ -490,49 +489,14 @@ whole conversation history, including compacted turns.
|
|
|
490
489
|
)
|
|
491
490
|
|
|
492
491
|
try:
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
from micro_cc.models.ollama import o_model_call
|
|
502
|
-
stream = await o_model_call(
|
|
503
|
-
input=trimmed_loop_msgs,
|
|
504
|
-
model=model,
|
|
505
|
-
tools=tool_schemas,
|
|
506
|
-
thinking=True,
|
|
507
|
-
stream=True,
|
|
508
|
-
)
|
|
509
|
-
elif end_resp == "LiteLLM":
|
|
510
|
-
from micro_cc.models.litellm import l_model_call
|
|
511
|
-
stream = await l_model_call(
|
|
512
|
-
input=trimmed_loop_msgs,
|
|
513
|
-
model=model,
|
|
514
|
-
tools=tool_schemas,
|
|
515
|
-
thinking=True,
|
|
516
|
-
stream=True,
|
|
517
|
-
)
|
|
518
|
-
elif end_resp == "Foundry":
|
|
519
|
-
from micro_cc.models.foundry import f_model_call
|
|
520
|
-
stream = await f_model_call(
|
|
521
|
-
input=trimmed_loop_msgs,
|
|
522
|
-
model=model,
|
|
523
|
-
tools=tool_schemas,
|
|
524
|
-
thinking=True,
|
|
525
|
-
stream=True,
|
|
526
|
-
)
|
|
527
|
-
else:
|
|
528
|
-
from micro_cc.models.anthropic import a_model_call
|
|
529
|
-
stream = await a_model_call(
|
|
530
|
-
input=trimmed_loop_msgs,
|
|
531
|
-
model=model,
|
|
532
|
-
tools=tool_schemas,
|
|
533
|
-
thinking=True,
|
|
534
|
-
stream=True,
|
|
535
|
-
)
|
|
492
|
+
stream = await model_call(
|
|
493
|
+
input=trimmed_loop_msgs,
|
|
494
|
+
model=model,
|
|
495
|
+
endpoint=end_resp,
|
|
496
|
+
tools=tool_schemas,
|
|
497
|
+
thinking=True,
|
|
498
|
+
stream=True,
|
|
499
|
+
)
|
|
536
500
|
|
|
537
501
|
if stream is None:
|
|
538
502
|
yield {"type": "error", "message": "model call failed after retries"}
|
|
@@ -549,12 +513,27 @@ whole conversation history, including compacted turns.
|
|
|
549
513
|
response = event["response"]
|
|
550
514
|
api_usage = event.get("usage", {})
|
|
551
515
|
|
|
516
|
+
cache_miss = None
|
|
552
517
|
if api_usage.get("input"):
|
|
518
|
+
# detect_cache_miss BEFORE token_stats["input"] is overwritten
|
|
519
|
+
# below — it needs the PREVIOUS turn's snapshot to compare
|
|
520
|
+
# against this turn's.
|
|
521
|
+
cache_miss = detect_cache_miss(api_usage, model)
|
|
522
|
+
# "input": last call's context size (live ctx% readout —
|
|
523
|
+
# same snapshot semantics as real Claude Code's
|
|
524
|
+
# calculateContextPercentages). "total_input": running sum
|
|
525
|
+
# across every call this session (same as real Claude
|
|
526
|
+
# Code's cost-tracker.ts addToTotalModelUsage) — each turn
|
|
527
|
+
# is its own billed API request, so real spend is this
|
|
528
|
+
# sum, not the size of the most recent one alone.
|
|
553
529
|
token_stats["input"] = api_usage["input"]
|
|
530
|
+
token_stats["total_input"] += api_usage["input"]
|
|
554
531
|
if api_usage.get("output"):
|
|
555
532
|
token_stats["output"] += api_usage["output"]
|
|
556
533
|
if api_usage:
|
|
557
534
|
save_token_stats(project_dir)
|
|
535
|
+
if cache_miss:
|
|
536
|
+
yield {"type": "cache_invalidate", **cache_miss}
|
|
558
537
|
|
|
559
538
|
if response is None:
|
|
560
539
|
yield {"type": "error", "message": "model call failed after retries"}
|
|
@@ -573,17 +552,17 @@ whole conversation history, including compacted turns.
|
|
|
573
552
|
# thinking + text already streamed as deltas above
|
|
574
553
|
|
|
575
554
|
if tool_use_blocks:
|
|
576
|
-
# Auto-re-resolve tools that expired from
|
|
555
|
+
# Auto-re-resolve tools that expired from state_store but exist in catalogs
|
|
577
556
|
for tb in tool_use_blocks:
|
|
578
557
|
if tb.name not in tools and tb.name not in mcp_routing:
|
|
579
558
|
if tb.name in TOOL_CATALOG:
|
|
580
|
-
# Re-inject from catalog + refresh
|
|
559
|
+
# Re-inject from catalog + refresh state_store
|
|
581
560
|
tool_schemas.append(get_tool_schema(tb.name))
|
|
582
561
|
tools[tb.name] = get_tool_func(tb.name)
|
|
583
|
-
|
|
562
|
+
state_store.add_discovered_tools(project_dir, [tb.name])
|
|
584
563
|
elif tb.name in mcp_catalog:
|
|
585
|
-
# Re-inject MCP + refresh
|
|
586
|
-
|
|
564
|
+
# Re-inject MCP + refresh state_store
|
|
565
|
+
state_store.add_discovered_mcps(project_dir, [tb.name])
|
|
587
566
|
new_mcp_tools, new_mcp_routing, new_mcp_failures = await resolve_mcp_tools([mcp_catalog[tb.name]])
|
|
588
567
|
tool_schemas.extend(new_mcp_tools)
|
|
589
568
|
mcp_routing.update(new_mcp_routing)
|
|
@@ -739,8 +718,8 @@ whole conversation history, including compacted turns.
|
|
|
739
718
|
if tool_block.name == "search_tools" and isinstance(result, dict):
|
|
740
719
|
new_tools = result.get("discovered_tools", [])
|
|
741
720
|
new_mcps = result.get("discovered_mcps", [])
|
|
742
|
-
|
|
743
|
-
|
|
721
|
+
state_store.add_discovered_tools(project_dir, new_tools)
|
|
722
|
+
state_store.add_discovered_mcps(project_dir, new_mcps)
|
|
744
723
|
# Inject into current loop so next API call has them
|
|
745
724
|
for t_name in new_tools:
|
|
746
725
|
if t_name not in tools:
|
|
@@ -870,14 +849,6 @@ whole conversation history, including compacted turns.
|
|
|
870
849
|
# for this whole turn (final_text/done) to finish.
|
|
871
850
|
yield {"type": "turn_boundary"}
|
|
872
851
|
|
|
873
|
-
# # Post-tool nudge (lightweight user reminder, not full context)
|
|
874
|
-
# plan_data_post = redis_state.get_plan(project_dir)
|
|
875
|
-
# if plan_data_post:
|
|
876
|
-
# post_reminder = get_post_tool_plan_reminder(plan_data_post, all_blocks[0].name)
|
|
877
|
-
# msgs.append({"role": "user", "content": f"<system-reminder>{post_reminder}</system-reminder>"})
|
|
878
|
-
# else:
|
|
879
|
-
# msgs.append({"role": "user", "content": "<system-reminder>You just used a tool. Note what you found, then continue working silently — no narration needed.</system-reminder>"})
|
|
880
|
-
|
|
881
852
|
# No tool use = final response (text already streamed as deltas)
|
|
882
853
|
if not tool_use_blocks and text_block:
|
|
883
854
|
msgs.append({"role": "assistant", "content": text_block.text})
|
|
@@ -23,7 +23,11 @@ async def execute_tool_call(
|
|
|
23
23
|
args = tool_call.input # Already a dict from SDK
|
|
24
24
|
|
|
25
25
|
if name not in tools:
|
|
26
|
-
return
|
|
26
|
+
return (
|
|
27
|
+
f"Tool '{name}' is not loaded — discovered tools expire after "
|
|
28
|
+
f"180s of inactivity. Call search_tools again to rediscover it, "
|
|
29
|
+
f"then retry."
|
|
30
|
+
)
|
|
27
31
|
|
|
28
32
|
tool = tools[name]
|
|
29
33
|
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"""Application model API. Provider SDKs are loaded only when called."""
|
|
2
|
+
|
|
3
|
+
from micro_cc.models.client import model_call
|
|
4
|
+
from micro_cc.models.types import ContentBlock, Response, ResponseStream, StreamEvent, Usage
|
|
5
|
+
|
|
6
|
+
__all__ = ["model_call", "ContentBlock", "Response", "ResponseStream", "StreamEvent", "Usage"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""SDK-output adapters. No credentials, requests, retries, or SDK imports here."""
|