illusion-code 0.2.6__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.6 → illusion_code-0.2.8}/.github/workflows/publish.yml +1 -1
- {illusion_code-0.2.6 → illusion_code-0.2.8}/PKG-INFO +6 -1
- {illusion_code-0.2.6 → illusion_code-0.2.8}/docs/en/architecture.md +10 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/docs/en/channels.md +64 -8
- {illusion_code-0.2.6 → illusion_code-0.2.8}/docs/en/commands.md +1 -1
- {illusion_code-0.2.6 → illusion_code-0.2.8}/docs/zh-CN/architecture.md +10 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/docs/zh-CN/channels.md +63 -8
- {illusion_code-0.2.6 → illusion_code-0.2.8}/docs/zh-CN/commands.md +1 -1
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/package-lock.json +2 -2
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/package.json +1 -1
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/ConversationView.tsx +6 -3
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/tools/registry.ts +18 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/version.ts +1 -1
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/index.html +12 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/package-lock.json +2 -2
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/package.json +1 -1
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/src/App.tsx +97 -1
- illusion_code-0.2.8/frontend/web/src/components/ChatArea.tsx +457 -0
- illusion_code-0.2.8/frontend/web/src/components/MessageBubble.tsx +500 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/src/components/ModalCard.tsx +7 -4
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/src/components/PromptInput.tsx +9 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/src/components/RightPanel.tsx +29 -11
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/src/components/Sidebar.tsx +25 -11
- {illusion_code-0.2.6 → 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.6 → illusion_code-0.2.8}/frontend/web/src/i18n.ts +44 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/src/index.css +248 -93
- illusion_code-0.2.8/frontend/web/src/utils/toolDisplayName.ts +140 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/src/version.ts +1 -1
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/tailwind.config.js +16 -16
- {illusion_code-0.2.6 → illusion_code-0.2.8}/pyproject.toml +4 -1
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/__init__.py +1 -1
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/channels/__init__.py +342 -56
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/channels/base.py +112 -5
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/channels/base_commands.py +28 -14
- {illusion_code-0.2.6 → 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.6 → illusion_code-0.2.8}/src/illusion/channels/feishu/adapter.py +306 -3
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/channels/feishu/messaging.py +346 -0
- {illusion_code-0.2.6 → 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.6 → 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.6 → 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.6 → 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.6 → 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.6 → illusion_code-0.2.8}/src/illusion/channels/weixin/ilink_api.py +351 -2
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/channels/weixin/session_map.py +37 -1
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/cli.py +58 -18
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/config/i18n.py +2 -3
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/config/paths.py +13 -7
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/engine/query.py +4 -3
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/plugins/loader.py +12 -4
- {illusion_code-0.2.6 → 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.6 → illusion_code-0.2.8}/src/illusion/prompts/context.py +5 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/services/cron.py +3 -0
- {illusion_code-0.2.6 → 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.6 → illusion_code-0.2.8}/src/illusion/tools/cron_tool.py +45 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/task_get_tool.py +4 -2
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/task_output_tool.py +4 -2
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/task_stop_tool.py +4 -2
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/ui/app.py +6 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/ui/backend_host.py +25 -3
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/ui/runtime.py +7 -1
- {illusion_code-0.2.6 → 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.6 → 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.6/frontend/web/src/components/ChatArea.tsx +0 -179
- illusion_code-0.2.6/frontend/web/src/components/MessageBubble.tsx +0 -277
- illusion_code-0.2.6/src/illusion/channels/qq/api.py +0 -469
- illusion_code-0.2.6/src/illusion/channels/tools/feishu_doc.py +0 -148
- illusion_code-0.2.6/src/illusion/channels/weixin/adapter.py +0 -490
- illusion_code-0.2.6/tests/channels/weixin/test_adapter.py +0 -93
- {illusion_code-0.2.6 → illusion_code-0.2.8}/.gitignore +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/.python-version +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/LICENSE +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/README.md +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/README.zh-CN.md +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/docs/en/extensions.md +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/docs/en/getting-started.md +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/docs/en/introduction.md +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/docs/en/project-files.md +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/docs/en/settings.md +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/docs/images/IllusionCode.png +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/docs/images/image1.png +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/docs/images/image2.png +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/docs/zh-CN/extensions.md +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/docs/zh-CN/getting-started.md +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/docs/zh-CN/introduction.md +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/docs/zh-CN/project-files.md +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/docs/zh-CN/settings.md +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/build.mjs +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/App.tsx +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/CommandPicker.tsx +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/Composer.tsx +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/ComposerController.tsx +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/Footer.tsx +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/MarkdownContent.tsx +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/MarkdownTable.tsx +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/ModalHost.tsx +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/MultilineTextInput.tsx +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/PromptInput.tsx +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/QuestionNavigationBar.tsx +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/QuestionPreviewBox.tsx +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/SelectModal.tsx +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/SidePanel.tsx +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/Spinner.tsx +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/StatusBar.tsx +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/SwarmPanel.tsx +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/TodoPanel.tsx +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/ToolCallDisplay.tsx +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/TranscriptPane.tsx +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/WelcomeBanner.tsx +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/hooks/useAnimationFrame.ts +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/hooks/useBackendSession.ts +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/hooks/useBlink.ts +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/hooks/useQuestionState.ts +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/hooks/useTerminalSize.ts +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/i18n.ts +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/index.tsx +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/theme/ThemeContext.tsx +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/theme/builtinThemes.ts +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/tools/ToolInterface.ts +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/AgentTool.ts +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/BashTool.ts +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/CronTool.ts +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/EditTool.ts +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/GenericTool.ts +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/LspTool.ts +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/McpTool.ts +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/NotebookTool.ts +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/PlanTool.ts +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/ReadTool.ts +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/SearchTool.ts +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/SkillTool.ts +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/TaskTool.ts +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/WebTool.ts +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/WorktreeTool.ts +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/WriteTool.ts +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/types.ts +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/utils/markdown.ts +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/utils/thinking.ts +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/tsconfig.json +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/postcss.config.js +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/src/components/ErrorBoundary.tsx +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/src/components/Toolbar.tsx +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/src/components/WelcomeScreen.tsx +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/src/hooks/useWebSocketSession.ts +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/src/main.tsx +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/src/remarkSuperscript.ts +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/src/types/protocol.ts +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/src/vite-env.d.ts +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/tsconfig.json +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/tsconfig.node.json +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/vite.config.ts +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/scripts/build_frontend.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/scripts/hatch_build.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/scripts/publish.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/scripts/sync_version.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/__main__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/api/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/api/client.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/api/codex_client.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/api/compat.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/api/effort.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/api/errors.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/api/openai_client.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/api/provider.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/api/registry.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/api/usage.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/auth/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/auth/codex_oauth.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/auth/copilot.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/auth/external.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/auth/flows.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/auth/manager.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/auth/storage.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/bridge/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/bridge/manager.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/bridge/session_runner.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/bridge/types.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/bridge/work_secret.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/channels/feishu/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/channels/feishu/commands.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/channels/feishu/ws_client.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/channels/pid.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/channels/qq/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/channels/qq/commands.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/channels/qq/ws_client.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/channels/tools/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/channels/weixin/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/channels/weixin/commands.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/auth.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/bridge.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/context.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/git.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/helpers.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/init/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/init/analysis/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/init/analysis/architecture.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/init/analysis/conventions.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/init/analysis/dependencies.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/init/analysis/key_modules.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/init/extraction/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/init/extraction/lsp_symbols.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/init/extraction/readme.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/init/extraction/scanner.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/init/generation/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/init/generation/claudemd.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/init/generation/illusionmd.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/init/generation/memory_template.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/init/generation/rules.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/init/generation/sections.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/init/orchestrator.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/init/types.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/mcp.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/memory.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/misc.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/model.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/plugin.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/registry.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/rules.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/sandbox.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/session.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/settings.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/types.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/config/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/config/plan_file.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/config/settings.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/coordinator/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/coordinator/agent_definitions.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/coordinator/coordinator_mode.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/engine/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/engine/cost_tracker.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/engine/messages.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/engine/query_engine.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/engine/stream_events.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/hooks/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/hooks/events.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/hooks/executor.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/hooks/hot_reload.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/hooks/loader.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/hooks/register_hooks.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/hooks/schemas.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/hooks/session_hooks.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/hooks/types.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/hooks/utils.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/mcp/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/mcp/client.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/mcp/config.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/mcp/types.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/memory/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/memory/manager.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/memory/memdir.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/memory/paths.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/memory/scan.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/memory/search.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/memory/types.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/output_styles/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/output_styles/loader.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/permissions/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/permissions/checker.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/permissions/loader.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/permissions/modes.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/permissions/schemas.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/platforms.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/plugins/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/plugins/installer.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/plugins/options.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/plugins/schemas.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/plugins/types.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/prompts/claudemd.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/prompts/environment.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/prompts/system_prompt.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/sandbox/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/sandbox/adapter.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/sandbox/platforms/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/sandbox/platforms/base.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/sandbox/platforms/linux.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/sandbox/platforms/macos.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/sandbox/platforms/windows.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/sandbox/proxy/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/sandbox/proxy/env_vars.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/sandbox/runtime.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/sandbox/symlink_protection.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/sandbox/utils.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/sandbox/violation_store.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/services/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/services/compact/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/services/compact/auto_compact.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/services/compact/compact_core.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/services/compact/compact_prompt.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/services/compact/constants.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/services/compact/message_ops.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/services/compact/microcompact.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/services/compact/models.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/services/compact/token_utils.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/services/file_history.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/services/lsp/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/services/lsp/client.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/services/lsp/config.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/services/lsp/manager.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/services/lsp/types.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/services/session_storage.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/services/token_estimation.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/skills/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/skills/bundled/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/skills/bundled/content/batch.md +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/skills/bundled/content/debug.md +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/skills/bundled/content/loop.md +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/skills/bundled/content/remember.md +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/skills/bundled/content/simplify.md +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/skills/bundled/content/skillify.md +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/skills/bundled/content/stuck.md +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/skills/bundled/content/update-config.md +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/skills/bundled/content/verify.md +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/skills/loader.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/skills/registry.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/skills/types.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/state/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/state/app_state.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/state/store.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/swarm/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/swarm/agent_executor.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/swarm/in_process.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/swarm/subprocess_backend.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/swarm/team_helpers.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/swarm/types.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/swarm/worktree.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tasks/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tasks/local_agent_task.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tasks/local_shell_task.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tasks/manager.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tasks/stop_task.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tasks/types.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/agent_tool.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/ask_user_question_tool.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/base.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/bash_tool.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/config_tool.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/enter_plan_mode_tool.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/enter_worktree_tool.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/exit_plan_mode_tool.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/exit_worktree_tool.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/file_edit_tool.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/file_read_tool.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/file_write_tool.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/glob_tool.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/grep_tool.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/list_mcp_resources_tool.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/lsp_formatters.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/lsp_schemas.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/lsp_tool.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/mcp_auth_tool.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/mcp_tool.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/notebook_edit_tool.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/powershell_tool.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/read_mcp_resource_tool.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/repl_tool.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/send_message_tool.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/shell_common.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/skill_tool.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/sleep_tool.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/structured_output_tool.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/task_create_tool.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/task_list_tool.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/task_update_tool.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/team_create_tool.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/team_delete_tool.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/todo_write_tool.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/tool_search_tool.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/web_fetch_tool.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/web_search_tool.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/ui/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/ui/input.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/ui/output.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/ui/permission_dialog.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/ui/permission_store.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/ui/protocol.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/ui/react_launcher.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/ui/textual_app.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/ui/web/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/ui/web/server.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/ui/web/ws_web_api.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/utils/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/utils/atomic_write.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/utils/file_state_cache.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/utils/ripgrep.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/utils/shell.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/api/test_anthropic_client.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/api/test_client.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/api/test_codex_client.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/api/test_effort.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/api/test_fallback/346/217/220/347/244/272.py" +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/api/test_openai_client.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/channels/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/channels/feishu/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/channels/feishu/test_adapter.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/channels/feishu/test_commands.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/channels/feishu/test_session_map.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/channels/test_base.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/channels/test_base_commands.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/channels/test_config.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/channels/test_pid.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/channels/test_tool_registration.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/channels/tools/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/channels/tools/test_feishu_doc.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/channels/tools/test_feishu_drive.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/channels/weixin/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/channels/weixin/test_config.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/channels/weixin/test_ilink_api.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/channels/weixin/test_session_map.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/commands/init/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/commands/init/test_claudemd.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/commands/init/test_orchestrator.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/commands/init/test_scanner.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/commands/init/test_sections.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/commands/test_effort_command.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/config/test_i18n.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/config/test_settings.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/conftest.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/engine/test_query_engine.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/fixtures/fake_mcp_server.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/integration/test_effort_integration.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/services/lsp/test_lsp_client.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/services/lsp/test_lsp_config.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/services/lsp/test_lsp_manager.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/services/lsp/test_lsp_types.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_api/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_api/test_client.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_api/test_codex_client.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_api/test_compat.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_api/test_openai_client.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_auth/test_external.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_bridge/test_core.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_bridge/test_session_flow.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_commands/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_commands/test_cli.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_commands/test_command_flows.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_commands/test_registry.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_config/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_config/test_paths.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_config/test_settings.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_coordinator/test_agent_definitions.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_coordinator/test_coordinator_mode.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_engine/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_engine/test_media_block.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_engine/test_query_engine.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_engine/test_tool_result_media.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_hooks/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_hooks/test_executor.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_hooks/test_loader_permissions.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_hooks_skills_plugins_real.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_mcp/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_mcp/test_config_permissions.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_mcp/test_integration.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_mcp/test_stdio_flow.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_memory/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_memory/test_manager_permissions.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_memory/test_memdir.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_merged_prs_on_autoagent.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_permissions/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_permissions/test_checker.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_permissions/test_loader.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_permissions/test_project_permissions.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_platforms.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_plugins/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_plugins/test_lifecycle_flow.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_plugins/test_loader.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_plugins/test_loader_permissions.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_prompts/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_prompts/test_claudemd.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_prompts/test_claudemd_permissions.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_prompts/test_environment.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_prompts/test_system_prompt.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_real_large_tasks.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_sandbox/test_adapter.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_sandbox/test_config_schema.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_sandbox/test_platform_linux.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_sandbox/test_platform_macos.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_sandbox/test_platform_windows.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_sandbox/test_proxy_env_vars.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_sandbox/test_runtime.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_sandbox/test_symlink_protection.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_sandbox/test_utils.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_sandbox/test_violation_store.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_scripts/test_sync_version.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_services/test_compact.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_services/test_cron.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_services/test_cron_scheduler.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_services/test_session_storage.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_skills/test_loader.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_skills/test_loader_permissions.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_swarm/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_swarm/test_agent_executor.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_swarm/test_imports.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_swarm/test_in_process.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_swarm/test_types.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_swarm/test_worktree.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_tasks/test_manager.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_tools/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_tools/test_agent_tool.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_tools/test_core_tools.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_tools/test_file_read_media.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_tools/test_glob_tool.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_tools/test_grep_tool.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_tools/test_integration.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_tools/test_integration_flows.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_tools/test_mcp_auth_tool.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_tools/test_ripgrep.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_tools/test_shell_common.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_tools/test_task_tools.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_tools/test_team_tools.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_tools/test_web_fetch_tool.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_ui/__init__.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_ui/test_modes.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_ui/test_permission_store.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_ui/test_react_backend.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_ui/test_react_launcher.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_ui/test_textual_app.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_untested_features.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_utils/test_shell.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/ui/test_backend_host.py +0 -0
- {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/ui/test_protocol_web.py +0 -0
- {illusion_code-0.2.6 → 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",
|
{illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/ConversationView.tsx
RENAMED
|
@@ -680,12 +680,15 @@ function wrapForPrefix(text: string, terminalWidth: number, prefix: string): str
|
|
|
680
680
|
}
|
|
681
681
|
|
|
682
682
|
function truncateToDisplayWidth(text: string, maxWidth: number): string {
|
|
683
|
-
|
|
684
|
-
|
|
683
|
+
// 将 tab 替换为空格,因为 string-width 将 tab 算作1字符宽度,
|
|
684
|
+
// 但终端中 tab 会展开为多个空格,导致宽度计算偏小、截断不足
|
|
685
|
+
const expanded = text.replace(/\t/g, ' ');
|
|
686
|
+
if (stringWidth(expanded) <= maxWidth) {
|
|
687
|
+
return expanded;
|
|
685
688
|
}
|
|
686
689
|
let result = '';
|
|
687
690
|
let width = 0;
|
|
688
|
-
for (const ch of
|
|
691
|
+
for (const ch of expanded) {
|
|
689
692
|
const charWidth = stringWidth(ch);
|
|
690
693
|
if (width + charWidth > Math.max(1, maxWidth - 1)) {
|
|
691
694
|
break;
|
|
@@ -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",
|
|
@@ -53,6 +53,12 @@ export default function App() {
|
|
|
53
53
|
// 内联选项状态
|
|
54
54
|
const [inlineOptions, setInlineOptions] = useState<SelectRequestPayload | null>(null);
|
|
55
55
|
|
|
56
|
+
// 回退确认弹窗状态
|
|
57
|
+
const [rewindConfirm, setRewindConfirm] = useState<{ turns: number } | null>(null);
|
|
58
|
+
// 重新生成:存储待重发的 user 消息文本,rewind 完成后自动重发
|
|
59
|
+
const pendingRegenerateRef = useRef<string | null>(null);
|
|
60
|
+
const prevBusyRef = useRef(false);
|
|
61
|
+
|
|
56
62
|
// Toast 状态
|
|
57
63
|
const [toastMessage, setToastMessage] = useState<{ text: string; type: 'success' | 'error' | 'info' } | null>(null);
|
|
58
64
|
const [toastExiting, setToastExiting] = useState(false);
|
|
@@ -231,6 +237,57 @@ export default function App() {
|
|
|
231
237
|
/** 处理停止当前任务 */
|
|
232
238
|
const handleStop = () => { session.sendRequest({ type: 'stop' }); };
|
|
233
239
|
|
|
240
|
+
/**
|
|
241
|
+
* 处理回退到指定轮次
|
|
242
|
+
*
|
|
243
|
+
* 由 ChatArea 中 user 消息的撤销按钮触发,弹出模式选择弹窗。
|
|
244
|
+
*
|
|
245
|
+
* @param turnsToRewind - 需要回退的轮次数
|
|
246
|
+
*/
|
|
247
|
+
const handleRewindToTurn = useCallback((turnsToRewind: number) => {
|
|
248
|
+
setRewindConfirm({ turns: turnsToRewind });
|
|
249
|
+
}, []);
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* 确认回退 —— 根据用户选择的模式执行 /rewind N mode
|
|
253
|
+
*
|
|
254
|
+
* 通过 submit_line 通道(treat_as_text 缺省=false)直接走命令注册表,
|
|
255
|
+
* 绕过 web_query 的多步弹窗流程。
|
|
256
|
+
*
|
|
257
|
+
* @param mode - 回退模式:code / conversation / both
|
|
258
|
+
*/
|
|
259
|
+
const handleConfirmRewind = useCallback((mode: string) => {
|
|
260
|
+
const turns = rewindConfirm?.turns ?? 1;
|
|
261
|
+
setRewindConfirm(null);
|
|
262
|
+
session.setBusyTrue();
|
|
263
|
+
session.sendRequest({ type: 'submit_line', line: `/rewind ${turns} ${mode}` });
|
|
264
|
+
}, [rewindConfirm, session]);
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* 处理重新生成
|
|
268
|
+
*
|
|
269
|
+
* 找到最后一条 user 消息文本,先 /rewind 1 both 回退一轮,
|
|
270
|
+
* rewind 完成后(busy→false)自动重发 user 消息。
|
|
271
|
+
*/
|
|
272
|
+
const handleRegenerate = useCallback(() => {
|
|
273
|
+
const lastUserMsg = [...session.staticItems].reverse().find((i) => i.role === 'user' && !i.text.startsWith('/'));
|
|
274
|
+
if (!lastUserMsg) return;
|
|
275
|
+
pendingRegenerateRef.current = lastUserMsg.text;
|
|
276
|
+
session.setBusyTrue();
|
|
277
|
+
session.sendRequest({ type: 'submit_line', line: '/rewind 1 both' });
|
|
278
|
+
}, [session]);
|
|
279
|
+
|
|
280
|
+
// 监听 busy 状态变化:rewind 完成后自动重发 user 消息(重新生成)
|
|
281
|
+
useEffect(() => {
|
|
282
|
+
if (prevBusyRef.current && !session.busy && pendingRegenerateRef.current) {
|
|
283
|
+
const text = pendingRegenerateRef.current;
|
|
284
|
+
pendingRegenerateRef.current = null;
|
|
285
|
+
session.setBusyTrue();
|
|
286
|
+
session.sendRequest({ type: 'submit_line', line: text, treat_as_text: true });
|
|
287
|
+
}
|
|
288
|
+
prevBusyRef.current = session.busy;
|
|
289
|
+
}, [session.busy, session]);
|
|
290
|
+
|
|
234
291
|
/** 处理新建会话 */
|
|
235
292
|
const handleNewSession = () => {
|
|
236
293
|
session.sendRequest({ type: 'web_new_session' });
|
|
@@ -345,7 +402,8 @@ export default function App() {
|
|
|
345
402
|
streamingReasoning={session.streamingReasoning} pendingToolCalls={session.pendingToolCalls}
|
|
346
403
|
busy={session.busy} connected={session.connected}
|
|
347
404
|
modal={session.modal} onPermissionResponse={handlePermissionResponse}
|
|
348
|
-
onQuestionResponse={handleQuestionResponse} restoringSessionId={session.restoringSessionId}
|
|
405
|
+
onQuestionResponse={handleQuestionResponse} restoringSessionId={session.restoringSessionId}
|
|
406
|
+
onRewindToTurn={handleRewindToTurn} onRegenerate={handleRegenerate} />
|
|
349
407
|
<PromptInput lang={lang} busy={session.busy} connected={session.connected}
|
|
350
408
|
commands={session.commands} onSubmit={handleSubmit} onStop={handleStop}
|
|
351
409
|
inlineOptions={inlineOptions} onInlineSelect={handleInlineSelect} onInlineClose={handleInlineClose} />
|
|
@@ -407,6 +465,44 @@ export default function App() {
|
|
|
407
465
|
</div>
|
|
408
466
|
)}
|
|
409
467
|
|
|
468
|
+
{/* 回退确认弹窗(选择回退范围) */}
|
|
469
|
+
{rewindConfirm && (
|
|
470
|
+
<div className="fixed inset-0 z-50 flex items-center justify-center">
|
|
471
|
+
<div className="absolute inset-0 bg-black/35 backdrop-blur-md animate-fade-in" onClick={() => setRewindConfirm(null)} />
|
|
472
|
+
<div className="relative glass-overlay rounded-2xl w-[380px] flex flex-col animate-scale-in modal-origin-center">
|
|
473
|
+
<div className="px-6 py-4 border-b border-border-light">
|
|
474
|
+
<h3 className="text-lg font-semibold text-content-primary">{t(lang, 'rewind_confirm_title')}</h3>
|
|
475
|
+
</div>
|
|
476
|
+
<div className="py-2 px-1">
|
|
477
|
+
{([
|
|
478
|
+
{ mode: 'both', label: t(lang, 'rewind_both'), desc: t(lang, 'rewind_both_desc') },
|
|
479
|
+
{ mode: 'conversation', label: t(lang, 'rewind_conversation'), desc: t(lang, 'rewind_conversation_desc') },
|
|
480
|
+
{ mode: 'code', label: t(lang, 'rewind_code'), desc: t(lang, 'rewind_code_desc') },
|
|
481
|
+
] as const).map((opt) => (
|
|
482
|
+
<button
|
|
483
|
+
key={opt.mode}
|
|
484
|
+
onClick={() => handleConfirmRewind(opt.mode)}
|
|
485
|
+
className="w-full text-left px-6 py-3 cursor-pointer glass-option-hover transition-colors rounded-lg flex items-center justify-between group"
|
|
486
|
+
>
|
|
487
|
+
<div>
|
|
488
|
+
<div className="text-sm font-medium text-content-primary">{opt.label}</div>
|
|
489
|
+
<div className="text-xs text-content-disabled mt-0.5">{opt.desc}</div>
|
|
490
|
+
</div>
|
|
491
|
+
<svg className="w-4 h-4 text-content-disabled opacity-0 group-hover:opacity-100 transition-opacity" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
|
|
492
|
+
<path d="M6 3l5 5-5 5" />
|
|
493
|
+
</svg>
|
|
494
|
+
</button>
|
|
495
|
+
))}
|
|
496
|
+
</div>
|
|
497
|
+
<div className="px-6 py-4 border-t border-border-light flex justify-end">
|
|
498
|
+
<button onClick={() => setRewindConfirm(null)} className="px-4 py-2 text-sm text-content-secondary glass-option-hover rounded-lg transition-colors cursor-pointer border border-white/40">
|
|
499
|
+
{t(lang, 'cancel')}
|
|
500
|
+
</button>
|
|
501
|
+
</div>
|
|
502
|
+
</div>
|
|
503
|
+
</div>
|
|
504
|
+
)}
|
|
505
|
+
|
|
410
506
|
{/* Toast 通知 */}
|
|
411
507
|
{toastMessage && (
|
|
412
508
|
<div
|