illusion-code 0.2.7__tar.gz → 0.2.8__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.
- {illusion_code-0.2.7 → illusion_code-0.2.8}/.github/workflows/publish.yml +1 -1
- {illusion_code-0.2.7 → illusion_code-0.2.8}/PKG-INFO +6 -1
- {illusion_code-0.2.7 → illusion_code-0.2.8}/docs/en/architecture.md +10 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/docs/en/channels.md +64 -8
- {illusion_code-0.2.7 → illusion_code-0.2.8}/docs/en/commands.md +1 -1
- {illusion_code-0.2.7 → illusion_code-0.2.8}/docs/zh-CN/architecture.md +10 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/docs/zh-CN/channels.md +63 -8
- {illusion_code-0.2.7 → illusion_code-0.2.8}/docs/zh-CN/commands.md +1 -1
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/package-lock.json +2 -2
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/package.json +1 -1
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/tools/registry.ts +18 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/version.ts +1 -1
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/web/index.html +12 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/web/package-lock.json +2 -2
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/web/package.json +1 -1
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/web/src/components/ChatArea.tsx +32 -3
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/web/src/components/MessageBubble.tsx +6 -2
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/web/src/components/ModalCard.tsx +7 -4
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/web/src/components/RightPanel.tsx +29 -11
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/web/src/components/TodoPanel.tsx +26 -9
- illusion_code-0.2.8/frontend/web/src/hooks/useTheme.ts +89 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/web/src/i18n.ts +10 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/web/src/index.css +147 -70
- illusion_code-0.2.8/frontend/web/src/utils/toolDisplayName.ts +140 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/web/src/version.ts +1 -1
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/web/tailwind.config.js +16 -16
- {illusion_code-0.2.7 → illusion_code-0.2.8}/pyproject.toml +4 -1
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/__init__.py +1 -1
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/channels/__init__.py +342 -56
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/channels/base.py +112 -5
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/channels/base_commands.py +28 -14
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/channels/config.py +4 -1
- illusion_code-0.2.8/src/illusion/channels/delivery.py +646 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/channels/feishu/adapter.py +306 -3
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/channels/feishu/messaging.py +346 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/channels/feishu/session_map.py +56 -1
- illusion_code-0.2.8/src/illusion/channels/feishu/streaming.py +398 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/channels/qq/adapter.py +317 -10
- illusion_code-0.2.8/src/illusion/channels/qq/api.py +844 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/channels/qq/session_map.py +52 -1
- illusion_code-0.2.8/src/illusion/channels/qq/streaming.py +357 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/channels/serve.py +11 -3
- illusion_code-0.2.8/src/illusion/channels/tools/cross_channel.py +231 -0
- illusion_code-0.2.8/src/illusion/channels/tools/feishu_doc.py +358 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/channels/tools/feishu_drive.py +198 -5
- illusion_code-0.2.8/src/illusion/channels/tools/media.py +204 -0
- illusion_code-0.2.8/src/illusion/channels/weixin/adapter.py +1039 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/channels/weixin/ilink_api.py +351 -2
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/channels/weixin/session_map.py +37 -1
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/cli.py +58 -18
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/config/i18n.py +2 -3
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/config/paths.py +13 -7
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/engine/query.py +4 -3
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/plugins/loader.py +12 -4
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/prompts/__init__.py +2 -0
- illusion_code-0.2.8/src/illusion/prompts/channel_hints.py +213 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/prompts/context.py +5 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/services/cron.py +3 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/services/cron_scheduler.py +34 -0
- illusion_code-0.2.8/src/illusion/tasks/todo_sync.py +172 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/cron_tool.py +45 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/task_get_tool.py +4 -2
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/task_output_tool.py +4 -2
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/task_stop_tool.py +4 -2
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/ui/app.py +6 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/ui/backend_host.py +25 -3
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/ui/runtime.py +7 -1
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/ui/web/ws_host.py +15 -3
- illusion_code-0.2.8/tests/channels/weixin/test_adapter.py +827 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_qq_channel.py +81 -0
- illusion_code-0.2.8/tests/unit/__init__.py +0 -0
- illusion_code-0.2.8/tests/unit/test_channel_hints.py +74 -0
- illusion_code-0.2.8/tests/unit/test_cross_channel.py +186 -0
- illusion_code-0.2.8/tests/unit/test_delivery.py +190 -0
- illusion_code-0.2.8/tests/unit/test_feishu_streaming.py +666 -0
- illusion_code-0.2.8/tests/unit/test_media_tools.py +32 -0
- illusion_code-0.2.8/tests/unit/test_qq_streaming.py +430 -0
- illusion_code-0.2.8/tests/unit/test_session_list_active.py +72 -0
- illusion_code-0.2.7/src/illusion/channels/qq/api.py +0 -469
- illusion_code-0.2.7/src/illusion/channels/tools/feishu_doc.py +0 -148
- illusion_code-0.2.7/src/illusion/channels/weixin/adapter.py +0 -490
- illusion_code-0.2.7/tests/channels/weixin/test_adapter.py +0 -93
- {illusion_code-0.2.7 → illusion_code-0.2.8}/.gitignore +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/.python-version +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/LICENSE +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/README.md +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/README.zh-CN.md +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/docs/en/extensions.md +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/docs/en/getting-started.md +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/docs/en/introduction.md +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/docs/en/project-files.md +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/docs/en/settings.md +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/docs/images/IllusionCode.png +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/docs/images/image1.png +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/docs/images/image2.png +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/docs/zh-CN/extensions.md +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/docs/zh-CN/getting-started.md +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/docs/zh-CN/introduction.md +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/docs/zh-CN/project-files.md +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/docs/zh-CN/settings.md +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/build.mjs +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/App.tsx +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/components/CommandPicker.tsx +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/components/Composer.tsx +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/components/ComposerController.tsx +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/components/ConversationView.tsx +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/components/Footer.tsx +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/components/MarkdownContent.tsx +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/components/MarkdownTable.tsx +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/components/ModalHost.tsx +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/components/MultilineTextInput.tsx +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/components/PromptInput.tsx +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/components/QuestionNavigationBar.tsx +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/components/QuestionPreviewBox.tsx +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/components/SelectModal.tsx +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/components/SidePanel.tsx +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/components/Spinner.tsx +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/components/StatusBar.tsx +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/components/SwarmPanel.tsx +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/components/TodoPanel.tsx +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/components/ToolCallDisplay.tsx +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/components/TranscriptPane.tsx +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/components/WelcomeBanner.tsx +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/hooks/useAnimationFrame.ts +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/hooks/useBackendSession.ts +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/hooks/useBlink.ts +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/hooks/useQuestionState.ts +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/hooks/useTerminalSize.ts +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/i18n.ts +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/index.tsx +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/theme/ThemeContext.tsx +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/theme/builtinThemes.ts +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/tools/ToolInterface.ts +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/AgentTool.ts +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/BashTool.ts +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/CronTool.ts +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/EditTool.ts +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/GenericTool.ts +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/LspTool.ts +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/McpTool.ts +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/NotebookTool.ts +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/PlanTool.ts +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/ReadTool.ts +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/SearchTool.ts +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/SkillTool.ts +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/TaskTool.ts +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/WebTool.ts +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/WorktreeTool.ts +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/WriteTool.ts +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/types.ts +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/utils/markdown.ts +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/src/utils/thinking.ts +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/terminal/tsconfig.json +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/web/postcss.config.js +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/web/src/App.tsx +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/web/src/components/ErrorBoundary.tsx +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/web/src/components/PromptInput.tsx +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/web/src/components/Sidebar.tsx +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/web/src/components/Toolbar.tsx +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/web/src/components/WelcomeScreen.tsx +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/web/src/hooks/useWebSocketSession.ts +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/web/src/main.tsx +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/web/src/remarkSuperscript.ts +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/web/src/types/protocol.ts +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/web/src/vite-env.d.ts +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/web/tsconfig.json +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/web/tsconfig.node.json +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/frontend/web/vite.config.ts +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/scripts/build_frontend.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/scripts/hatch_build.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/scripts/publish.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/scripts/sync_version.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/__main__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/api/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/api/client.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/api/codex_client.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/api/compat.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/api/effort.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/api/errors.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/api/openai_client.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/api/provider.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/api/registry.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/api/usage.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/auth/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/auth/codex_oauth.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/auth/copilot.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/auth/external.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/auth/flows.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/auth/manager.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/auth/storage.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/bridge/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/bridge/manager.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/bridge/session_runner.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/bridge/types.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/bridge/work_secret.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/channels/feishu/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/channels/feishu/commands.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/channels/feishu/ws_client.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/channels/pid.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/channels/qq/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/channels/qq/commands.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/channels/qq/ws_client.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/channels/tools/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/channels/weixin/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/channels/weixin/commands.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/commands/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/commands/auth.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/commands/bridge.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/commands/context.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/commands/git.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/commands/helpers.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/commands/init/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/commands/init/analysis/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/commands/init/analysis/architecture.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/commands/init/analysis/conventions.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/commands/init/analysis/dependencies.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/commands/init/analysis/key_modules.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/commands/init/extraction/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/commands/init/extraction/lsp_symbols.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/commands/init/extraction/readme.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/commands/init/extraction/scanner.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/commands/init/generation/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/commands/init/generation/claudemd.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/commands/init/generation/illusionmd.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/commands/init/generation/memory_template.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/commands/init/generation/rules.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/commands/init/generation/sections.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/commands/init/orchestrator.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/commands/init/types.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/commands/mcp.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/commands/memory.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/commands/misc.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/commands/model.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/commands/plugin.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/commands/registry.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/commands/rules.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/commands/sandbox.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/commands/session.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/commands/settings.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/commands/types.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/config/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/config/plan_file.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/config/settings.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/coordinator/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/coordinator/agent_definitions.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/coordinator/coordinator_mode.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/engine/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/engine/cost_tracker.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/engine/messages.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/engine/query_engine.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/engine/stream_events.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/hooks/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/hooks/events.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/hooks/executor.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/hooks/hot_reload.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/hooks/loader.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/hooks/register_hooks.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/hooks/schemas.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/hooks/session_hooks.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/hooks/types.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/hooks/utils.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/mcp/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/mcp/client.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/mcp/config.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/mcp/types.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/memory/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/memory/manager.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/memory/memdir.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/memory/paths.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/memory/scan.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/memory/search.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/memory/types.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/output_styles/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/output_styles/loader.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/permissions/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/permissions/checker.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/permissions/loader.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/permissions/modes.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/permissions/schemas.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/platforms.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/plugins/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/plugins/installer.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/plugins/options.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/plugins/schemas.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/plugins/types.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/prompts/claudemd.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/prompts/environment.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/prompts/system_prompt.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/sandbox/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/sandbox/adapter.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/sandbox/platforms/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/sandbox/platforms/base.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/sandbox/platforms/linux.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/sandbox/platforms/macos.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/sandbox/platforms/windows.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/sandbox/proxy/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/sandbox/proxy/env_vars.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/sandbox/runtime.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/sandbox/symlink_protection.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/sandbox/utils.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/sandbox/violation_store.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/services/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/services/compact/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/services/compact/auto_compact.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/services/compact/compact_core.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/services/compact/compact_prompt.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/services/compact/constants.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/services/compact/message_ops.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/services/compact/microcompact.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/services/compact/models.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/services/compact/token_utils.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/services/file_history.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/services/lsp/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/services/lsp/client.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/services/lsp/config.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/services/lsp/manager.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/services/lsp/types.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/services/session_storage.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/services/token_estimation.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/skills/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/skills/bundled/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/skills/bundled/content/batch.md +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/skills/bundled/content/debug.md +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/skills/bundled/content/loop.md +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/skills/bundled/content/remember.md +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/skills/bundled/content/simplify.md +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/skills/bundled/content/skillify.md +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/skills/bundled/content/stuck.md +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/skills/bundled/content/update-config.md +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/skills/bundled/content/verify.md +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/skills/loader.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/skills/registry.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/skills/types.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/state/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/state/app_state.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/state/store.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/swarm/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/swarm/agent_executor.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/swarm/in_process.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/swarm/subprocess_backend.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/swarm/team_helpers.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/swarm/types.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/swarm/worktree.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tasks/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tasks/local_agent_task.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tasks/local_shell_task.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tasks/manager.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tasks/stop_task.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tasks/types.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/agent_tool.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/ask_user_question_tool.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/base.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/bash_tool.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/config_tool.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/enter_plan_mode_tool.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/enter_worktree_tool.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/exit_plan_mode_tool.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/exit_worktree_tool.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/file_edit_tool.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/file_read_tool.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/file_write_tool.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/glob_tool.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/grep_tool.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/list_mcp_resources_tool.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/lsp_formatters.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/lsp_schemas.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/lsp_tool.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/mcp_auth_tool.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/mcp_tool.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/notebook_edit_tool.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/powershell_tool.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/read_mcp_resource_tool.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/repl_tool.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/send_message_tool.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/shell_common.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/skill_tool.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/sleep_tool.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/structured_output_tool.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/task_create_tool.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/task_list_tool.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/task_update_tool.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/team_create_tool.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/team_delete_tool.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/todo_write_tool.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/tool_search_tool.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/web_fetch_tool.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/tools/web_search_tool.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/ui/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/ui/input.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/ui/output.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/ui/permission_dialog.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/ui/permission_store.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/ui/protocol.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/ui/react_launcher.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/ui/textual_app.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/ui/web/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/ui/web/server.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/ui/web/ws_web_api.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/utils/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/utils/atomic_write.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/utils/file_state_cache.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/utils/ripgrep.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/src/illusion/utils/shell.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/api/test_anthropic_client.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/api/test_client.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/api/test_codex_client.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/api/test_effort.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/api/test_fallback/346/217/220/347/244/272.py" +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/api/test_openai_client.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/channels/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/channels/feishu/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/channels/feishu/test_adapter.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/channels/feishu/test_commands.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/channels/feishu/test_session_map.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/channels/test_base.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/channels/test_base_commands.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/channels/test_config.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/channels/test_pid.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/channels/test_tool_registration.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/channels/tools/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/channels/tools/test_feishu_doc.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/channels/tools/test_feishu_drive.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/channels/weixin/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/channels/weixin/test_config.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/channels/weixin/test_ilink_api.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/channels/weixin/test_session_map.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/commands/init/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/commands/init/test_claudemd.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/commands/init/test_orchestrator.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/commands/init/test_scanner.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/commands/init/test_sections.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/commands/test_effort_command.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/config/test_i18n.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/config/test_settings.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/conftest.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/engine/test_query_engine.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/fixtures/fake_mcp_server.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/integration/test_effort_integration.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/services/lsp/test_lsp_client.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/services/lsp/test_lsp_config.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/services/lsp/test_lsp_manager.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/services/lsp/test_lsp_types.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_api/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_api/test_client.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_api/test_codex_client.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_api/test_compat.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_api/test_openai_client.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_auth/test_external.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_bridge/test_core.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_bridge/test_session_flow.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_commands/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_commands/test_cli.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_commands/test_command_flows.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_commands/test_registry.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_config/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_config/test_paths.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_config/test_settings.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_coordinator/test_agent_definitions.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_coordinator/test_coordinator_mode.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_engine/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_engine/test_media_block.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_engine/test_query_engine.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_engine/test_tool_result_media.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_hooks/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_hooks/test_executor.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_hooks/test_loader_permissions.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_hooks_skills_plugins_real.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_mcp/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_mcp/test_config_permissions.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_mcp/test_integration.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_mcp/test_stdio_flow.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_memory/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_memory/test_manager_permissions.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_memory/test_memdir.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_merged_prs_on_autoagent.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_permissions/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_permissions/test_checker.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_permissions/test_loader.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_permissions/test_project_permissions.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_platforms.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_plugins/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_plugins/test_lifecycle_flow.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_plugins/test_loader.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_plugins/test_loader_permissions.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_prompts/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_prompts/test_claudemd.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_prompts/test_claudemd_permissions.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_prompts/test_environment.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_prompts/test_system_prompt.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_real_large_tasks.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_sandbox/test_adapter.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_sandbox/test_config_schema.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_sandbox/test_platform_linux.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_sandbox/test_platform_macos.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_sandbox/test_platform_windows.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_sandbox/test_proxy_env_vars.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_sandbox/test_runtime.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_sandbox/test_symlink_protection.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_sandbox/test_utils.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_sandbox/test_violation_store.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_scripts/test_sync_version.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_services/test_compact.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_services/test_cron.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_services/test_cron_scheduler.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_services/test_session_storage.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_skills/test_loader.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_skills/test_loader_permissions.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_swarm/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_swarm/test_agent_executor.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_swarm/test_imports.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_swarm/test_in_process.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_swarm/test_types.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_swarm/test_worktree.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_tasks/test_manager.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_tools/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_tools/test_agent_tool.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_tools/test_core_tools.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_tools/test_file_read_media.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_tools/test_glob_tool.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_tools/test_grep_tool.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_tools/test_integration.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_tools/test_integration_flows.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_tools/test_mcp_auth_tool.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_tools/test_ripgrep.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_tools/test_shell_common.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_tools/test_task_tools.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_tools/test_team_tools.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_tools/test_web_fetch_tool.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_ui/__init__.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_ui/test_modes.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_ui/test_permission_store.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_ui/test_react_backend.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_ui/test_react_launcher.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_ui/test_textual_app.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_untested_features.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/test_utils/test_shell.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/ui/test_backend_host.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/ui/test_protocol_web.py +0 -0
- {illusion_code-0.2.7 → illusion_code-0.2.8}/tests/ui/test_web_api.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: illusion-code
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.8
|
|
4
4
|
Summary: Open-source Python port of Claude Code - an AI-powered CLI coding assistant
|
|
5
5
|
Project-URL: Homepage, https://github.com/YunTaiHua/illusion-code
|
|
6
6
|
Project-URL: Repository, https://github.com/YunTaiHua/illusion-code
|
|
@@ -37,6 +37,11 @@ Requires-Dist: typer>=0.12.0
|
|
|
37
37
|
Requires-Dist: uvicorn[standard]>=0.34.0
|
|
38
38
|
Requires-Dist: watchfiles>=0.20.0
|
|
39
39
|
Requires-Dist: websockets>=12.0
|
|
40
|
+
Provides-Extra: all
|
|
41
|
+
Requires-Dist: aiohttp>=3.9.0; extra == 'all'
|
|
42
|
+
Requires-Dist: cryptography>=42.0.0; extra == 'all'
|
|
43
|
+
Requires-Dist: lark-oapi>=1.4.0; extra == 'all'
|
|
44
|
+
Requires-Dist: qrcode>=7.4.0; extra == 'all'
|
|
40
45
|
Provides-Extra: dev
|
|
41
46
|
Requires-Dist: mypy>=1.10.0; extra == 'dev'
|
|
42
47
|
Requires-Dist: pexpect>=4.9.0; extra == 'dev'
|
|
@@ -60,6 +60,16 @@ Provides 34 core tools, covering:
|
|
|
60
60
|
- **Interaction**: `ask_user_question`
|
|
61
61
|
- **Scheduled Tasks**: `cron` (unified tool with status/list/add/update/remove/run actions)
|
|
62
62
|
|
|
63
|
+
### Scheduled Tasks & Delivery Pipeline
|
|
64
|
+
|
|
65
|
+
The cron subsystem is composed of three cooperating modules:
|
|
66
|
+
|
|
67
|
+
- `services/cron.py` — CronJob data model and persistence (`cron.json`)
|
|
68
|
+
- `services/cron_scheduler.py` — scheduler process; runs the prompt in a subprocess and delivers the result to a channel based on the `deliver_to` field
|
|
69
|
+
- `channels/delivery.py` — delivery module; `parse_deliver_to` parses the target, `deliver_to_channel` dispatches to Feishu/WeChat/QQ `_deliver_*` functions
|
|
70
|
+
|
|
71
|
+
Delivery targets accept `channel:chat_id` (fully qualified) or a bare channel name (combined with the `chat_id` field). Failed jobs include stderr in the delivered text so users can see the error. See [Channels doc](channels.md#cron-job-result-delivery) for details.
|
|
72
|
+
|
|
63
73
|
### Permission System
|
|
64
74
|
|
|
65
75
|
Three permission modes:
|
|
@@ -261,38 +261,94 @@ Send a message to your bot in QQ — private chat replies directly, group chat r
|
|
|
261
261
|
- **No message editing** — replies are sent as complete text
|
|
262
262
|
- **4000 char limit** — longer replies auto-split into multiple messages with 1.5s delay
|
|
263
263
|
- **File sending** — supports 3-step chunked upload
|
|
264
|
+
- **Markdown dynamic hint** — when `markdown_support` is `true` in `channels.json`, the platform prompt tells the LLM that markdown is available (msg_type=2); when `false` (default), the prompt forces plain text (msg_type=0) and `send_text` auto-degrades to plain text on failure. Keep the default `false` for normal developer accounts without template permissions
|
|
265
|
+
- **Attachment download security** — when downloading QQ inbound attachments, the bot token is only attached for `.qq.com` / `.qq.com.cn` hosts, preventing access_token leakage via malicious URLs
|
|
264
266
|
|
|
265
267
|
## Channel Architecture
|
|
266
268
|
|
|
267
269
|
```
|
|
268
270
|
src/illusion/channels/
|
|
269
|
-
├── __init__.py # ChannelRunner (message→agent glue) + maybe_spawn_channel_daemon
|
|
270
|
-
├── base.py # Channel ABC + InboundMessage + typing methods
|
|
271
|
+
├── __init__.py # ChannelRunner (message→agent glue) + maybe_spawn_channel_daemon + kill_channel_daemon
|
|
272
|
+
├── base.py # Channel ABC + InboundMessage + Attachment + typing methods
|
|
271
273
|
├── base_commands.py # BaseCommandHandler (shared slash commands)
|
|
272
274
|
├── config.py # ChannelsConfig / FeishuChannelConfig / WeixinChannelConfig
|
|
275
|
+
├── delivery.py # cron job result delivery to channels (parse_deliver_to + deliver_to_channel)
|
|
273
276
|
├── serve.py # 'illusion channel serve' entry point (multi-channel)
|
|
274
277
|
├── pid.py # PID file management (avoid duplicate daemons)
|
|
275
278
|
├── feishu/
|
|
276
279
|
│ ├── adapter.py # FeishuChannel: WS connection, event dispatch, admission control
|
|
277
280
|
│ ├── ws_client.py # lark-oapi WS client wrapper
|
|
278
|
-
│ ├── messaging.py # Card send/patch, message rendering
|
|
281
|
+
│ ├── messaging.py # Card send/patch, message rendering, resolve_receive_id
|
|
279
282
|
│ ├── stream_editor.py # Streaming card editor (throttled patch updates)
|
|
280
283
|
│ ├── session_map.py # Feishu session store (chat_id → session)
|
|
281
284
|
│ └── commands.py # FeishuCommandHandler (extends BaseCommandHandler)
|
|
282
285
|
├── weixin/
|
|
283
286
|
│ ├── __init__.py # WEIXIN_DEPENDENCIES / ensure_weixin_dependencies
|
|
284
|
-
│ ├── adapter.py # WeixinChannel: long-poll, admission, context_token, typing
|
|
285
|
-
│ ├── ilink_api.py # iLink Bot API client (QR login / send / poll / typing)
|
|
287
|
+
│ ├── adapter.py # WeixinChannel: long-poll, admission, context_token, AES key cache, typing
|
|
288
|
+
│ ├── ilink_api.py # iLink Bot API client (QR login / send / poll / typing / CDN allowlist)
|
|
286
289
|
│ ├── session_map.py # WeixinSessionStore (user_id → session)
|
|
287
290
|
│ └── commands.py # WeixinCommandHandler (extends BaseCommandHandler)
|
|
288
291
|
├── qq/
|
|
289
292
|
│ ├── __init__.py # QQ_DEPENDENCIES / ensure_qq_dependencies
|
|
290
|
-
│ ├── adapter.py # QQChannel: WS connection, admission, message normalization
|
|
293
|
+
│ ├── adapter.py # QQChannel: WS connection, admission, message normalization, attachment host validation
|
|
291
294
|
│ ├── ws_client.py # QQ Bot WS gateway client (heartbeat/reconnect/events)
|
|
292
|
-
│ ├── api.py # QQ Bot REST API client (token/send/upload)
|
|
295
|
+
│ ├── api.py # QQ Bot REST API client (token/send/upload/_parse_qq_response)
|
|
293
296
|
│ ├── session_map.py # QQSessionStore (chat_id → session)
|
|
294
297
|
│ └── commands.py # QQCommandHandler (extends BaseCommandHandler)
|
|
295
298
|
└── tools/
|
|
296
299
|
├── feishu_doc.py # feishu_doc_read / feishu_doc_create
|
|
297
|
-
|
|
300
|
+
├── feishu_drive.py # feishu_drive_list / upload / download
|
|
301
|
+
└── media.py # SendMediaTool / ReceiveMediaTool (activated by channel config)
|
|
298
302
|
```
|
|
303
|
+
|
|
304
|
+
## Cron Job Result Delivery
|
|
305
|
+
|
|
306
|
+
Cron jobs can deliver execution results to Feishu/WeChat/QQ channel sessions. Configure via the `deliver_to` field in `cron_tool.py`:
|
|
307
|
+
|
|
308
|
+
- **Empty** — local execution only (terminal output)
|
|
309
|
+
- **`channel:chat_id`** — fully qualified format, e.g. `feishu:oc_xxx` (group), `feishu:ou_xxx` (private), `weixin:wxid_xxx`, `qq:openid`
|
|
310
|
+
- **`channel` (name only)** — requires the `chat_id` field; otherwise treated as "unspecified"
|
|
311
|
+
|
|
312
|
+
Session filename prefix rules (for extracting the real ID from `~/.illusion/channels/<channel>/sessions/`):
|
|
313
|
+
|
|
314
|
+
| Channel | Filename format | Real ID |
|
|
315
|
+
|---------|-----------------|---------|
|
|
316
|
+
| Feishu private | `u_ou_xxx.json` | `ou_xxx` (strip `u_` prefix) |
|
|
317
|
+
| Feishu group | `g_oc_xxx_ou_xxx.json` | `oc_xxx` (use the `oc_` part) |
|
|
318
|
+
| WeChat | `u_<wxid>.json` | `<wxid>` (strip `u_` prefix) |
|
|
319
|
+
| QQ | `<openid>.json` | `<openid>` (filename is the ID) |
|
|
320
|
+
|
|
321
|
+
Delivery failures do not affect task status; only a warning is logged. Failed jobs (non-success status) include stderr in the delivered text so users can see the error.
|
|
322
|
+
|
|
323
|
+
## Concurrent Message Handling
|
|
324
|
+
|
|
325
|
+
When a user sends multiple messages in quick succession, `ChannelRunner` serializes agent turns per `chat_id` using an `asyncio.Lock` to prevent session history corruption:
|
|
326
|
+
|
|
327
|
+
- M1 acquires the lock and starts the agent; M2/M3 enter the queue and wait
|
|
328
|
+
- After M1 completes (or exits pending_replies wait), M2 acquires the lock
|
|
329
|
+
- Permission/ask reply messages are **not locked** — they immediately `set_result` the waiting future, avoiding 300s timeouts
|
|
330
|
+
- Different `chat_id`s run fully in parallel without blocking each other
|
|
331
|
+
|
|
332
|
+
This ensures conversation history is written in order for the same session, preventing the race condition where "M1/A1 and M3/A3 are lost, only M2/A2 remains."
|
|
333
|
+
|
|
334
|
+
## Cross-Channel File Transfer
|
|
335
|
+
|
|
336
|
+
When multiple channels are enabled, the LLM can perceive all enabled channels and transfer files across channels.
|
|
337
|
+
|
|
338
|
+
### How It Works
|
|
339
|
+
|
|
340
|
+
1. **Channel-aware prompts**: System prompt includes current channel identity + overview of other enabled channels (with active sessions)
|
|
341
|
+
2. **Cross-channel tool**: `send_to_channel` for cross-channel file transfer, `send_media` for within-current-channel
|
|
342
|
+
3. **Active session list**: Up to 5 recent sessions per channel (sorted by last active time) to help LLM decide delivery target
|
|
343
|
+
|
|
344
|
+
### Use Cases
|
|
345
|
+
|
|
346
|
+
- **PC terminal → channel**: User says "send this file to Zhang San on Feishu"
|
|
347
|
+
- **Channel → channel**: User on QQ says "send this file to WeChat"
|
|
348
|
+
- **Within channel (default)**: User on QQ says "send this file" → uses `send_media` to current QQ session
|
|
349
|
+
|
|
350
|
+
### Limitations
|
|
351
|
+
|
|
352
|
+
- For cross-channel **text** messages, use cron tasks (`send_to_channel` only supports files)
|
|
353
|
+
- QQ and WeChat file upload APIs are complex; current version uses text prompts as fallback. Feishu is fully supported
|
|
354
|
+
- Active session list comes from session storage directory; users never interacted with won't appear
|
|
@@ -24,7 +24,7 @@ illusion plugin list # List plugins
|
|
|
24
24
|
illusion plugin install <source> # Install plugin
|
|
25
25
|
illusion plugin uninstall <name> # Uninstall plugin
|
|
26
26
|
|
|
27
|
-
# Channel management (Feishu/
|
|
27
|
+
# Channel management (Feishu/WeChat/QQ messaging)
|
|
28
28
|
illusion channel login # Interactive channel setup (select channel → configure credentials)
|
|
29
29
|
illusion channel serve # Run channel daemon in foreground (listen for messages)
|
|
30
30
|
illusion channel status # View channel status (enabled/connected/PID)
|
|
@@ -62,6 +62,16 @@ illusion-code/
|
|
|
62
62
|
- **交互**: `ask_user_question`
|
|
63
63
|
- **定时任务**: `cron`(统一工具,支持 status/list/add/update/remove/run 操作)
|
|
64
64
|
|
|
65
|
+
### 定时任务与投递链路
|
|
66
|
+
|
|
67
|
+
定时任务子系统由三个模块协作:
|
|
68
|
+
|
|
69
|
+
- `services/cron.py` — 任务数据模型(CronJob)与持久化(`cron.json`)
|
|
70
|
+
- `services/cron_scheduler.py` — 调度器进程,子进程执行提示词,按 `deliver_to` 字段投递结果到渠道
|
|
71
|
+
- `channels/delivery.py` — 渠道投递模块,`parse_deliver_to` 解析目标,`deliver_to_channel` 派发到飞书/微信/QQ 的 `_deliver_*` 函数
|
|
72
|
+
|
|
73
|
+
投递目标支持 `channel:chat_id` 完全限定格式或仅渠道名(配合 `chat_id` 字段)。任务失败时附 stderr 让用户可见错误。详见 [渠道文档](channels.md#cron-任务结果投递)。
|
|
74
|
+
|
|
65
75
|
### 权限系统
|
|
66
76
|
|
|
67
77
|
三种权限模式:
|
|
@@ -223,6 +223,7 @@ illusion channel serve # 前台模式(查看日志)
|
|
|
223
223
|
- **不支持消息编辑**——回复作为完整文本发送(打字状态指示处理中)
|
|
224
224
|
- **2000 字符限制**——超长回复自动分多条发送,间隔 1.5s
|
|
225
225
|
- **会话过期**——如果看到 `errcode=-14`,重新运行 `illusion channel login` 扫码
|
|
226
|
+
- **附件 AES 加密**——入站图片/视频/文件/语音经 CDN 传输时使用 AES-128-ECB + PKCS#7 加密,密钥按 `{msg_id}:{att_id}` 缓存,跨消息不会串键;依赖 `cryptography` 包(首次登录时自动安装)
|
|
226
227
|
|
|
227
228
|
### 快速开始(QQ)
|
|
228
229
|
|
|
@@ -268,33 +269,87 @@ illusion channel serve # 前台模式(查看日志)
|
|
|
268
269
|
|
|
269
270
|
```
|
|
270
271
|
src/illusion/channels/
|
|
271
|
-
├── __init__.py # ChannelRunner(消息→agent 粘合层)+ maybe_spawn_channel_daemon
|
|
272
|
-
├── base.py # Channel 抽象基类 + InboundMessage + 打字状态方法
|
|
272
|
+
├── __init__.py # ChannelRunner(消息→agent 粘合层)+ maybe_spawn_channel_daemon + kill_channel_daemon
|
|
273
|
+
├── base.py # Channel 抽象基类 + InboundMessage + Attachment + 打字状态方法
|
|
273
274
|
├── base_commands.py # BaseCommandHandler(通用斜杠命令基类)
|
|
274
275
|
├── config.py # ChannelsConfig / FeishuChannelConfig / WeixinChannelConfig
|
|
276
|
+
├── delivery.py # cron 任务结果投递到渠道(parse_deliver_to + deliver_to_channel)
|
|
275
277
|
├── serve.py # 'illusion channel serve' 入口(多渠道调度)
|
|
276
278
|
├── pid.py # PID 文件管理(避免重复启动守护进程)
|
|
277
279
|
├── feishu/
|
|
278
280
|
│ ├── adapter.py # FeishuChannel:WS 连接、事件分发、准入控制
|
|
279
281
|
│ ├── ws_client.py # lark-oapi WS 客户端包装
|
|
280
|
-
│ ├── messaging.py #
|
|
282
|
+
│ ├── messaging.py # 卡片发送/更新、消息渲染、resolve_receive_id
|
|
281
283
|
│ ├── stream_editor.py # 流式卡片编辑器(节流 patch 更新)
|
|
282
284
|
│ ├── session_map.py # 飞书会话存储(chat_id → 会话)
|
|
283
285
|
│ └── commands.py # FeishuCommandHandler(继承 BaseCommandHandler)
|
|
284
286
|
├── weixin/
|
|
285
287
|
│ ├── __init__.py # WEIXIN_DEPENDENCIES / ensure_weixin_dependencies
|
|
286
|
-
│ ├── adapter.py # WeixinChannel:长轮询、准入、context_token
|
|
287
|
-
│ ├── ilink_api.py # iLink Bot API
|
|
288
|
+
│ ├── adapter.py # WeixinChannel:长轮询、准入、context_token、AES 密钥缓存、打字状态
|
|
289
|
+
│ ├── ilink_api.py # iLink Bot API 客户端(扫码/收发/打字/分片/CDN allowlist)
|
|
288
290
|
│ ├── session_map.py # WeixinSessionStore(user_id → 会话)
|
|
289
291
|
│ └── commands.py # WeixinCommandHandler(继承 BaseCommandHandler)
|
|
290
292
|
├── qq/
|
|
291
293
|
│ ├── __init__.py # QQ_DEPENDENCIES / ensure_qq_dependencies
|
|
292
|
-
│ ├── adapter.py # QQChannel:WS
|
|
294
|
+
│ ├── adapter.py # QQChannel:WS 连接、准入、消息标准化、附件 host 校验
|
|
293
295
|
│ ├── ws_client.py # QQ Bot WS 网关客户端(心跳/重连/事件分发)
|
|
294
|
-
│ ├── api.py # QQ Bot REST API 客户端(token
|
|
296
|
+
│ ├── api.py # QQ Bot REST API 客户端(token/收发/上传/_parse_qq_response)
|
|
295
297
|
│ ├── session_map.py # QQSessionStore(chat_id → 会话)
|
|
296
298
|
│ └── commands.py # QQCommandHandler(继承 BaseCommandHandler)
|
|
297
299
|
└── tools/
|
|
298
300
|
├── feishu_doc.py # feishu_doc_read / feishu_doc_create
|
|
299
|
-
|
|
301
|
+
├── feishu_drive.py # feishu_drive_list / upload / download
|
|
302
|
+
└── media.py # SendMediaTool / ReceiveMediaTool(按渠道配置激活)
|
|
300
303
|
```
|
|
304
|
+
|
|
305
|
+
### Cron 任务结果投递
|
|
306
|
+
|
|
307
|
+
cron 定时任务支持把执行结果投递到飞书/微信/QQ 渠道会话。配置在 `cron_tool.py` 的 `deliver_to` 字段中指定:
|
|
308
|
+
|
|
309
|
+
- **空值**——任务仅本地执行(终端输出)
|
|
310
|
+
- **`channel:chat_id`**——完全限定格式,例如 `feishu:oc_xxx`(群聊)、`feishu:ou_xxx`(私聊)、`weixin:wxid_xxx`、`qq:openid`
|
|
311
|
+
- **`channel`(仅渠道名)**——需配合 `chat_id` 字段,否则按"未指定"处理
|
|
312
|
+
|
|
313
|
+
会话文件名前缀规则(用于从 `~/.illusion/channels/<channel>/sessions/` 提取真实 ID):
|
|
314
|
+
|
|
315
|
+
| 渠道 | 文件名格式 | 真实 ID |
|
|
316
|
+
|------|-----------|---------|
|
|
317
|
+
| 飞书私聊 | `u_ou_xxx.json` | `ou_xxx`(去掉 `u_` 前缀) |
|
|
318
|
+
| 飞书群聊 | `g_oc_xxx_ou_xxx.json` | `oc_xxx`(取 `oc_` 部分) |
|
|
319
|
+
| 微信 | `u_<wxid>.json` | `<wxid>`(去掉 `u_` 前缀) |
|
|
320
|
+
| QQ | `<openid>.json` | `<openid>`(文件名即 ID) |
|
|
321
|
+
|
|
322
|
+
投递失败不影响任务状态,仅记录 warning 日志。任务失败时(非成功状态)会附上 stderr 让用户可见错误。
|
|
323
|
+
|
|
324
|
+
### 消息并发处理
|
|
325
|
+
|
|
326
|
+
当用户快速连发多条消息时,`ChannelRunner` 按 `chat_id` 加 `asyncio.Lock` 串行化 agent turn,避免会话历史覆盖:
|
|
327
|
+
|
|
328
|
+
- M1 拿到锁后开始跑 agent,M2/M3 进入队列等待
|
|
329
|
+
- M1 完成(或退出 pending_replies 等待)后,M2 拿到锁开始处理
|
|
330
|
+
- 权限/询问回复消息**不加锁**,立即 set_result 给等待中的 future,避免 300s 超时
|
|
331
|
+
- 不同 `chat_id` 之间完全并行,互不阻塞
|
|
332
|
+
|
|
333
|
+
这保证同一会话的对话历史按顺序写入,不会出现"M1/A1 和 M3/A3 丢失、只保留 M2/A2"的 race condition。
|
|
334
|
+
|
|
335
|
+
## 跨渠道文件传输
|
|
336
|
+
|
|
337
|
+
当多个渠道同时启用时,LLM 能感知所有已启用渠道并跨渠道传输文件。
|
|
338
|
+
|
|
339
|
+
### 工作机制
|
|
340
|
+
|
|
341
|
+
1. **渠道感知提示词**:系统提示词中包含当前渠道身份 + 其他已启用渠道概览(含活跃会话列表)
|
|
342
|
+
2. **跨渠道工具**:`send_to_channel` 工具用于跨渠道发文件,`send_media` 用于当前渠道内发文件
|
|
343
|
+
3. **活跃会话列表**:每个渠道最近 5 个会话(按最后活跃时间排序),帮助 LLM 决定投递目标
|
|
344
|
+
|
|
345
|
+
### 使用场景
|
|
346
|
+
|
|
347
|
+
- **PC 终端 → 渠道**:用户在 PC 终端说"把这个文件发到飞书的张三"
|
|
348
|
+
- **渠道 → 渠道**:用户在 QQ 上说"把这个文件发到微信"
|
|
349
|
+
- **渠道内(默认)**:用户在 QQ 上说"发这个文件"→ 用 `send_media` 发到当前 QQ 会话
|
|
350
|
+
|
|
351
|
+
### 限制
|
|
352
|
+
|
|
353
|
+
- 跨渠道**文本**消息投递请使用 cron 任务(`send_to_channel` 仅支持文件)
|
|
354
|
+
- QQ 和微信的文件上传 API 较复杂,当前版本暂用文本提示替代,飞书已完整支持
|
|
355
|
+
- 活跃会话列表来自会话存储目录,从未交互过的用户不会出现在列表中
|
|
@@ -26,7 +26,7 @@ illusion plugin list # 列出插件
|
|
|
26
26
|
illusion plugin install <source> # 安装插件
|
|
27
27
|
illusion plugin uninstall <name> # 卸载插件
|
|
28
28
|
|
|
29
|
-
#
|
|
29
|
+
# 渠道管理(飞书/微信/QQ 消息渠道)
|
|
30
30
|
illusion channel login # 交互式配置渠道(选择渠道 → 配置凭据)
|
|
31
31
|
illusion channel serve # 前台运行渠道守护进程(监听消息)
|
|
32
32
|
illusion channel status # 查看渠道状态(启用/连接/PID)
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@illusion/terminal",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.8",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@illusion/terminal",
|
|
9
|
-
"version": "0.2.
|
|
9
|
+
"version": "0.2.8",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"chalk": "^5.6.2",
|
|
12
12
|
"ink": "^5.1.0",
|
|
@@ -120,6 +120,24 @@ function ensureInitialized(): void {
|
|
|
120
120
|
register(createGenericTool('mcp_auth', 'McpAuth'));
|
|
121
121
|
register(createGenericTool('structured_output', 'StructuredOutput'));
|
|
122
122
|
|
|
123
|
+
// 渠道媒体工具(当前渠道内发/收文件)
|
|
124
|
+
register(createGenericTool('send_media', 'SendMedia'));
|
|
125
|
+
register(createGenericTool('receive_media', 'ReceiveMedia'));
|
|
126
|
+
// 跨渠道文件传输
|
|
127
|
+
register(createGenericTool('list_channel_sessions', 'ListChannelSessions'));
|
|
128
|
+
register(createGenericTool('send_to_channel', 'SendToChannel'));
|
|
129
|
+
// 飞书文档工具
|
|
130
|
+
register(createGenericTool('feishu_doc_read', 'FeishuDocRead'));
|
|
131
|
+
register(createGenericTool('feishu_doc_create', 'FeishuDocCreate'));
|
|
132
|
+
register(createGenericTool('feishu_doc_write', 'FeishuDocWrite'));
|
|
133
|
+
register(createGenericTool('feishu_doc_delete', 'FeishuDocDelete'));
|
|
134
|
+
// 飞书云盘工具
|
|
135
|
+
register(createGenericTool('feishu_drive_list', 'FeishuDriveList'));
|
|
136
|
+
register(createGenericTool('feishu_drive_upload', 'FeishuDriveUpload'));
|
|
137
|
+
register(createGenericTool('feishu_drive_download', 'FeishuDriveDownload'));
|
|
138
|
+
register(createGenericTool('feishu_drive_mkdir', 'FeishuDriveMkdir'));
|
|
139
|
+
register(createGenericTool('feishu_drive_delete', 'FeishuDriveDelete'));
|
|
140
|
+
|
|
123
141
|
// 专用工具(需要特殊处理)
|
|
124
142
|
register({
|
|
125
143
|
name: 'todo_write',
|
|
@@ -7,6 +7,18 @@
|
|
|
7
7
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
8
8
|
<link href="https://fonts.googleapis.com/css2?family=Inter:opsz,wght@14..32,100..900&family=JetBrains+Mono:ital,wght@0,100..800;1,100..800&display=swap" rel="stylesheet" />
|
|
9
9
|
<title>Illusion Code</title>
|
|
10
|
+
<script>
|
|
11
|
+
// 预加载主题:在 React 渲染前应用 dark 类,避免深色模式 FOUC 闪烁
|
|
12
|
+
(function() {
|
|
13
|
+
try {
|
|
14
|
+
var stored = localStorage.getItem('illusion-theme');
|
|
15
|
+
var prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
16
|
+
if (stored === 'dark' || (stored !== 'light' && prefersDark)) {
|
|
17
|
+
document.documentElement.classList.add('dark');
|
|
18
|
+
}
|
|
19
|
+
} catch (e) { /* 忽略 */ }
|
|
20
|
+
})();
|
|
21
|
+
</script>
|
|
10
22
|
</head>
|
|
11
23
|
<body>
|
|
12
24
|
<div id="root"></div>
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@illusion/web",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.8",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@illusion/web",
|
|
9
|
-
"version": "0.2.
|
|
9
|
+
"version": "0.2.8",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"highlight.js": "^11.11.0",
|
|
12
12
|
"react": "^18.3.1",
|
|
@@ -29,15 +29,32 @@ const BOTTOM_THRESHOLD_PX = 80;
|
|
|
29
29
|
* - thinkingItems:工具调用 + 中间 assistant 消息(归入"思考过程"可折叠区)
|
|
30
30
|
* - finalAssistant:最后一条含文本的 assistant 消息(始终可见,其 reasoning 归入思考区)
|
|
31
31
|
*
|
|
32
|
+
* 流式阶段(streaming=true)所有 assistant 消息都视作思考过程的一部分:
|
|
33
|
+
* 最终回复由 StreamingBuffer 实时展示,避免中间 LLM 消息被误判为最终回复,
|
|
34
|
+
* 导致后续工具调用显示在消息上方、以及复制/回退按钮闪烁等问题。
|
|
35
|
+
*
|
|
32
36
|
* @param items - 单轮转录项列表
|
|
37
|
+
* @param streaming - 是否处于流式输出阶段
|
|
33
38
|
* @returns 拆分结果
|
|
34
39
|
*/
|
|
35
|
-
function splitTurnItems(items: TranscriptItem[]) {
|
|
40
|
+
function splitTurnItems(items: TranscriptItem[], streaming: boolean = false) {
|
|
36
41
|
const userItems: TranscriptItem[] = [];
|
|
37
42
|
const thinkingItems: TranscriptItem[] = [];
|
|
38
43
|
let finalAssistant: TranscriptItem | null = null;
|
|
39
44
|
|
|
40
|
-
//
|
|
45
|
+
// 流式阶段:所有 assistant 消息归入思考过程,不区分"最终回复"
|
|
46
|
+
if (streaming) {
|
|
47
|
+
for (const item of items) {
|
|
48
|
+
if (item.role === 'user') {
|
|
49
|
+
userItems.push(item);
|
|
50
|
+
} else {
|
|
51
|
+
thinkingItems.push(item);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return { userItems, thinkingItems, finalAssistant };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// 完成态:找最后一条有非空 text 的 assistant 消息作为"最终回复"
|
|
41
58
|
let lastAssistantIdx = -1;
|
|
42
59
|
for (let i = items.length - 1; i >= 0; i--) {
|
|
43
60
|
if (items[i]!.role === 'assistant' && items[i]!.text.trim()) {
|
|
@@ -278,6 +295,18 @@ export default function ChatArea({
|
|
|
278
295
|
el.scrollTop = el.scrollHeight;
|
|
279
296
|
}, [staticItems, assistantBuffer, streamingReasoning, pendingToolCalls, modal]);
|
|
280
297
|
|
|
298
|
+
// 用户发送新消息时强制回到底部(忽略用户是否手动上滑过)
|
|
299
|
+
const userMsgCount = useMemo(() => staticItems.filter((i) => i.role === 'user').length, [staticItems]);
|
|
300
|
+
const prevUserMsgCountRef = useRef(0);
|
|
301
|
+
useEffect(() => {
|
|
302
|
+
if (userMsgCount > prevUserMsgCountRef.current) {
|
|
303
|
+
userScrolledUpRef.current = false;
|
|
304
|
+
const el = scrollRef.current;
|
|
305
|
+
if (el) el.scrollTop = el.scrollHeight;
|
|
306
|
+
}
|
|
307
|
+
prevUserMsgCountRef.current = userMsgCount;
|
|
308
|
+
}, [userMsgCount]);
|
|
309
|
+
|
|
281
310
|
// 新会话或恢复后重置展开状态
|
|
282
311
|
useEffect(() => {
|
|
283
312
|
setExpanded(false);
|
|
@@ -329,8 +358,8 @@ export default function ChatArea({
|
|
|
329
358
|
{visibleTurns.map((turn, visIdx) => {
|
|
330
359
|
const turnIdx = turnOffset + visIdx;
|
|
331
360
|
const isLastTurn = turnIdx === turns.length - 1;
|
|
332
|
-
const { userItems, thinkingItems, finalAssistant } = splitTurnItems(turn);
|
|
333
361
|
const autoExpand = busy && isLastTurn;
|
|
362
|
+
const { userItems, thinkingItems, finalAssistant } = splitTurnItems(turn, autoExpand);
|
|
334
363
|
const turnsToRewind = turns.length - turnIdx;
|
|
335
364
|
return (
|
|
336
365
|
<div key={turnIdx} className={visIdx > 0 ? 'mt-12' : ''}>
|
|
@@ -19,6 +19,7 @@ import rehypeHighlight from 'rehype-highlight';
|
|
|
19
19
|
import rehypeRaw from 'rehype-raw';
|
|
20
20
|
import 'highlight.js/styles/github.css';
|
|
21
21
|
import { t, type UiLanguage } from '../i18n';
|
|
22
|
+
import { toolDisplayName } from '../utils/toolDisplayName';
|
|
22
23
|
import type { TranscriptItem, PendingToolCall } from '../types/protocol';
|
|
23
24
|
|
|
24
25
|
/** 从 rehype-highlight 注入的 className 中提取语言名 */
|
|
@@ -266,7 +267,9 @@ export default function MessageBubble({ item, toolInputMap, lang = 'zh-CN', onRe
|
|
|
266
267
|
*/
|
|
267
268
|
function ToolResultBubble({ name, text, isError, toolInput }: { name: string; text: string; isError?: boolean; toolInput?: Record<string, unknown> }) {
|
|
268
269
|
const [open, setOpen] = useState(false);
|
|
270
|
+
// summarizeInput 用原名做大小写不敏感匹配,显示名用映射后的友好名
|
|
269
271
|
const summary = summarizeInput(name, toolInput, name);
|
|
272
|
+
const displayName = toolDisplayName(name);
|
|
270
273
|
|
|
271
274
|
return (
|
|
272
275
|
<div className="py-1.5">
|
|
@@ -276,7 +279,7 @@ function ToolResultBubble({ name, text, isError, toolInput }: { name: string; te
|
|
|
276
279
|
>
|
|
277
280
|
<span className={`inline-block w-2 h-2 rounded-full shrink-0 mt-1.5 ${isError ? 'bg-danger' : 'bg-primary'}`} />
|
|
278
281
|
<span>
|
|
279
|
-
<span className={`font-medium font-mono ${isError ? 'text-danger' : 'text-content-primary'}`}>{
|
|
282
|
+
<span className={`font-medium font-mono ${isError ? 'text-danger' : 'text-content-primary'}`}>{displayName}</span>
|
|
280
283
|
{!open && summary && <span className={`text-xs ${isError ? 'text-danger' : 'text-content-disabled'}`}>({summary})</span>}
|
|
281
284
|
{isError && <span className="text-xs text-danger font-medium"> ERROR</span>}
|
|
282
285
|
</span>
|
|
@@ -367,11 +370,12 @@ export function ReasoningContent({ text }: { text: string }) {
|
|
|
367
370
|
*/
|
|
368
371
|
export function PendingToolBubble({ call }: { call: PendingToolCall }) {
|
|
369
372
|
const summary = summarizeInput(call.tool_name, call.tool_input, call.tool_name);
|
|
373
|
+
const displayName = toolDisplayName(call.tool_name);
|
|
370
374
|
return (
|
|
371
375
|
<div className="py-1.5 flex items-start gap-2">
|
|
372
376
|
<span className="inline-block w-2 h-2 rounded-full bg-primary animate-pulse-scale shrink-0 mt-1.5" />
|
|
373
377
|
<span className="text-sm">
|
|
374
|
-
<span className="font-medium font-mono text-content-primary">{
|
|
378
|
+
<span className="font-medium font-mono text-content-primary">{displayName}</span>
|
|
375
379
|
{summary && <span className="text-xs text-content-disabled">({summary})</span>}
|
|
376
380
|
</span>
|
|
377
381
|
</div>
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
12
12
|
import { t, type UiLanguage } from '../i18n';
|
|
13
|
+
import { toolDisplayName } from '../utils/toolDisplayName';
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* 问题选项接口
|
|
@@ -61,6 +62,8 @@ interface PermissionCardProps {
|
|
|
61
62
|
*/
|
|
62
63
|
export function PermissionCard({ modal, lang, onRespond }: PermissionCardProps) {
|
|
63
64
|
const toolName = String(modal.tool_name ?? 'tool');
|
|
65
|
+
// 显示用友好名;onRespond 回调仍传原始 toolName 给后端识别
|
|
66
|
+
const displayToolName = toolDisplayName(toolName);
|
|
64
67
|
const reason = modal.reason ? String(modal.reason) : null;
|
|
65
68
|
const requestId = String(modal.request_id ?? '');
|
|
66
69
|
|
|
@@ -75,7 +78,7 @@ export function PermissionCard({ modal, lang, onRespond }: PermissionCardProps)
|
|
|
75
78
|
<div className="px-4 py-3">
|
|
76
79
|
<div className="text-sm text-content-primary mb-1">
|
|
77
80
|
{lang === 'zh-CN' ? '允许使用工具 ' : 'Allow '}
|
|
78
|
-
<span className="font-mono font-medium text-primary">{
|
|
81
|
+
<span className="font-mono font-medium text-primary">{displayToolName}</span>
|
|
79
82
|
<span>?</span>
|
|
80
83
|
</div>
|
|
81
84
|
{reason && (
|
|
@@ -359,7 +362,7 @@ export function QuestionCard({ modal, lang, onRespond }: QuestionCardProps) {
|
|
|
359
362
|
<div className="px-4 py-3">
|
|
360
363
|
{typeof modal.tool_name === 'string' && modal.tool_name && (
|
|
361
364
|
<div className="text-xs text-content-secondary mb-3">
|
|
362
|
-
Tool: <span className="font-mono text-primary">{modal.tool_name}</span>
|
|
365
|
+
Tool: <span className="font-mono text-primary">{toolDisplayName(modal.tool_name)}</span>
|
|
363
366
|
</div>
|
|
364
367
|
)}
|
|
365
368
|
|
|
@@ -402,7 +405,7 @@ export function QuestionCard({ modal, lang, onRespond }: QuestionCardProps) {
|
|
|
402
405
|
</button>
|
|
403
406
|
);
|
|
404
407
|
})}
|
|
405
|
-
{/* "其他"
|
|
408
|
+
{/* "其他"选项:内联输入框,与普通选项格式一致(无序号),沙箱等 noCustomInput 场景不显示 */}
|
|
406
409
|
{!noCustomInput && (
|
|
407
410
|
<div
|
|
408
411
|
className={`w-full text-left px-3 py-2.5 rounded-lg text-sm transition-colors cursor-pointer flex items-start gap-2.5 ${
|
|
@@ -431,7 +434,7 @@ export function QuestionCard({ modal, lang, onRespond }: QuestionCardProps) {
|
|
|
431
434
|
<span className={`text-sm font-medium shrink-0 ${
|
|
432
435
|
(isMultiSelect && selectedIndices.has(otherIdx)) || (!isMultiSelect && isOtherFocused) ? 'text-primary' : ''
|
|
433
436
|
}`}>
|
|
434
|
-
{
|
|
437
|
+
{lang === 'zh-CN' ? '其他' : 'Other'}
|
|
435
438
|
</span>{' '}
|
|
436
439
|
{isOtherFocused ? (
|
|
437
440
|
<input
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
import { useState } from 'react';
|
|
16
16
|
import { t, type UiLanguage } from '../i18n';
|
|
17
|
+
import { useTheme } from '../hooks/useTheme';
|
|
17
18
|
import TodoPanel from './TodoPanel';
|
|
18
19
|
import type { McpServerSnapshot, PluginSnapshot, RuleSnapshot, SkillSnapshot, TodoItemSnapshot } from '../types/protocol';
|
|
19
20
|
|
|
@@ -59,6 +60,8 @@ export default function RightPanel({
|
|
|
59
60
|
lang, status, connected, busy, collapsed, onToggle, todoItems,
|
|
60
61
|
skills, plugins, rules, mcpServers, width = 260,
|
|
61
62
|
}: RightPanelProps) {
|
|
63
|
+
// 主题(深色/浅色)— 在折叠判断前调用以保证 hook 始终执行
|
|
64
|
+
const { theme, toggleTheme } = useTheme();
|
|
62
65
|
// 上下文使用量
|
|
63
66
|
const contextWindow = Number(status?.context_window ?? 0);
|
|
64
67
|
const contextTokens = Number(status?.context_tokens ?? 0);
|
|
@@ -88,22 +91,37 @@ export default function RightPanel({
|
|
|
88
91
|
|
|
89
92
|
return (
|
|
90
93
|
<aside className="glass-panel border-l border-white/30 flex flex-col h-full shrink-0 overflow-y-auto select-none" style={{ width: `${width}px` }}>
|
|
91
|
-
{/*
|
|
92
|
-
<div className="px-5 pt-3 pb-
|
|
94
|
+
{/* 标题行:主题切换按钮 + 居中标题 + 折叠按钮(3 列 grid 严格居中) */}
|
|
95
|
+
<div className="grid grid-cols-3 items-center px-5 pt-3 pb-2">
|
|
96
|
+
<button onClick={toggleTheme} title={t(lang, 'toggle_theme')}
|
|
97
|
+
aria-label={t(lang, 'toggle_theme')}
|
|
98
|
+
className="justify-self-start w-7 h-7 flex items-center justify-center rounded-lg text-content-secondary glass-option-hover hover:text-content-primary transition-colors cursor-pointer">
|
|
99
|
+
{theme === 'dark' ? (
|
|
100
|
+
/* 太阳图标(深色模式下点击切换到浅色) */
|
|
101
|
+
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
|
|
102
|
+
<circle cx="8" cy="8" r="3" />
|
|
103
|
+
<path d="M8 1.5v1.5M8 13v1.5M1.5 8h1.5M13 8h1.5M3.4 3.4l1.1 1.1M11.5 11.5l1.1 1.1M3.4 12.6l1.1-1.1M11.5 4.5l1.1-1.1" />
|
|
104
|
+
</svg>
|
|
105
|
+
) : (
|
|
106
|
+
/* 月亮图标(浅色模式下点击切换到深色) */
|
|
107
|
+
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
|
|
108
|
+
<path d="M13 8.5a5 5 0 0 1-5.5-5.5 5 5 0 1 0 5.5 5.5z" />
|
|
109
|
+
</svg>
|
|
110
|
+
)}
|
|
111
|
+
</button>
|
|
112
|
+
<span className="justify-self-center font-display font-bold text-content-primary text-sm tracking-wider">{t(lang, 'management_title')}</span>
|
|
93
113
|
<button onClick={onToggle} title={t(lang, 'collapse_panel')}
|
|
94
|
-
className="w-7 h-7 flex items-center justify-center rounded-lg text-content-secondary glass-option-hover hover:text-content-primary transition-colors cursor-pointer">
|
|
114
|
+
className="justify-self-end w-7 h-7 flex items-center justify-center rounded-lg text-content-secondary glass-option-hover hover:text-content-primary transition-colors cursor-pointer">
|
|
95
115
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
|
|
96
116
|
<path d="M6 3l5 5-5 5" />
|
|
97
117
|
</svg>
|
|
98
118
|
</button>
|
|
99
119
|
</div>
|
|
100
120
|
|
|
101
|
-
{/* Todo
|
|
102
|
-
|
|
103
|
-
<
|
|
104
|
-
|
|
105
|
-
</div>
|
|
106
|
-
)}
|
|
121
|
+
{/* Todo 列表(始终显示,空列表显示占位) */}
|
|
122
|
+
<div className="px-3 pb-3">
|
|
123
|
+
<TodoPanel items={todoItems} lang={lang} />
|
|
124
|
+
</div>
|
|
107
125
|
|
|
108
126
|
{/* Skills */}
|
|
109
127
|
{skills.length > 0 && (
|
|
@@ -208,7 +226,7 @@ function CollapsibleSection({
|
|
|
208
226
|
<path d="M6 3l5 5-5 5" />
|
|
209
227
|
</svg>
|
|
210
228
|
<span className="text-xs font-semibold text-content-primary tracking-wide">{title}</span>
|
|
211
|
-
<span className="text-[10px] text-content-secondary bg-
|
|
229
|
+
<span className="text-[10px] text-content-secondary bg-[var(--badge-bg)] px-1.5 py-0.5 rounded-full tabular-nums">{count}</span>
|
|
212
230
|
{subtitle && <span className="text-xs text-content-disabled ml-auto">{subtitle}</span>}
|
|
213
231
|
</button>
|
|
214
232
|
<div className="grid transition-[grid-template-rows] duration-200 ease-out" style={{ gridTemplateRows: collapsed ? '0fr' : '1fr' }}>
|
|
@@ -237,7 +255,7 @@ function ItemRow({ name, description, tag }: { name: string; description: string
|
|
|
237
255
|
>
|
|
238
256
|
<span className="text-content-primary font-medium truncate flex-1 text-left">{name}</span>
|
|
239
257
|
{tag && (
|
|
240
|
-
<span className="text-[10px] text-primary/80 bg-
|
|
258
|
+
<span className="text-[10px] text-primary/80 bg-[var(--badge-bg)] px-1.5 py-0.5 rounded-full font-medium shrink-0">{tag}</span>
|
|
241
259
|
)}
|
|
242
260
|
</button>
|
|
243
261
|
{expanded && hasDesc && (
|