illusion-code 0.2.9__tar.gz → 0.2.11__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.9 → illusion_code-0.2.11}/PKG-INFO +1 -1
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/package-lock.json +2 -2
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/package.json +1 -1
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/version.ts +1 -1
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/web/package-lock.json +2 -2
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/web/package.json +1 -1
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/web/src/version.ts +1 -1
- {illusion_code-0.2.9 → illusion_code-0.2.11}/pyproject.toml +1 -1
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/__init__.py +1 -1
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/channels/__init__.py +164 -75
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/channels/base_commands.py +4 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/channels/config.py +17 -7
- illusion_code-0.2.11/src/illusion/channels/exit_handler.py +83 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/channels/feishu/session_map.py +25 -15
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/channels/qq/adapter.py +39 -34
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/channels/qq/session_map.py +22 -12
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/channels/qq/ws_client.py +73 -18
- illusion_code-0.2.11/src/illusion/channels/registry.py +253 -0
- illusion_code-0.2.11/src/illusion/channels/serve.py +309 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/channels/tools/feishu_doc.py +6 -6
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/channels/tools/feishu_drive.py +9 -9
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/channels/tools/media.py +5 -1
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/channels/weixin/ilink_api.py +93 -14
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/channels/weixin/session_map.py +22 -12
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/cli.py +46 -17
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/commands/session.py +2 -18
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/config/i18n.py +29 -2
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/hooks/__init__.py +1 -1
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/mcp/__init__.py +1 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/plugins/__init__.py +7 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/skills/__init__.py +6 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tasks/todo_sync.py +2 -2
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/ui/runtime.py +1 -1
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/ui/web/ws_host.py +5 -0
- illusion_code-0.2.11/tests/channels/test_exit_handler.py +192 -0
- illusion_code-0.2.11/tests/channels/test_registry.py +248 -0
- illusion_code-0.2.11/tests/channels/test_session_persist.py +72 -0
- illusion_code-0.2.11/tests/channels/test_supervise.py +71 -0
- illusion_code-0.2.11/tests/channels/weixin/test_ilink_retry.py +65 -0
- illusion_code-0.2.11/tests/test_cli_exit_handler.py +66 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/unit/test_qq_streaming.py +2 -2
- illusion_code-0.2.9/src/illusion/channels/serve.py +0 -251
- {illusion_code-0.2.9 → illusion_code-0.2.11}/.github/workflows/publish.yml +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/.gitignore +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/.python-version +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/LICENSE +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/README.md +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/README.zh-CN.md +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/docs/en/architecture.md +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/docs/en/channels.md +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/docs/en/commands.md +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/docs/en/extensions.md +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/docs/en/getting-started.md +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/docs/en/introduction.md +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/docs/en/project-files.md +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/docs/en/settings.md +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/docs/images/IllusionCode.png +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/docs/images/image1.png +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/docs/images/image2.png +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/docs/zh-CN/architecture.md +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/docs/zh-CN/channels.md +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/docs/zh-CN/commands.md +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/docs/zh-CN/extensions.md +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/docs/zh-CN/getting-started.md +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/docs/zh-CN/introduction.md +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/docs/zh-CN/project-files.md +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/docs/zh-CN/settings.md +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/build.mjs +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/App.tsx +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/components/CommandPicker.tsx +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/components/Composer.tsx +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/components/ComposerController.tsx +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/components/ConversationView.tsx +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/components/Footer.tsx +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/components/MarkdownContent.tsx +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/components/MarkdownTable.tsx +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/components/ModalHost.tsx +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/components/MultilineTextInput.tsx +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/components/PromptInput.tsx +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/components/QuestionNavigationBar.tsx +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/components/QuestionPreviewBox.tsx +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/components/SelectModal.tsx +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/components/SidePanel.tsx +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/components/Spinner.tsx +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/components/StatusBar.tsx +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/components/SwarmPanel.tsx +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/components/TodoPanel.tsx +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/components/ToolCallDisplay.tsx +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/components/TranscriptPane.tsx +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/components/WelcomeBanner.tsx +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/hooks/useAnimationFrame.ts +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/hooks/useBackendSession.ts +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/hooks/useBlink.ts +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/hooks/useQuestionState.ts +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/hooks/useTerminalSize.ts +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/i18n.ts +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/index.tsx +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/theme/ThemeContext.tsx +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/theme/builtinThemes.ts +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/tools/ToolInterface.ts +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/tools/implementations/AgentTool.ts +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/tools/implementations/BashTool.ts +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/tools/implementations/CronTool.ts +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/tools/implementations/EditTool.ts +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/tools/implementations/GenericTool.ts +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/tools/implementations/LspTool.ts +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/tools/implementations/McpTool.ts +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/tools/implementations/NotebookTool.ts +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/tools/implementations/PlanTool.ts +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/tools/implementations/ReadTool.ts +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/tools/implementations/SearchTool.ts +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/tools/implementations/SkillTool.ts +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/tools/implementations/TaskTool.ts +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/tools/implementations/WebTool.ts +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/tools/implementations/WorktreeTool.ts +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/tools/implementations/WriteTool.ts +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/tools/registry.ts +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/types.ts +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/utils/markdown.ts +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/src/utils/thinking.ts +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/terminal/tsconfig.json +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/web/index.html +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/web/postcss.config.js +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/web/src/App.tsx +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/web/src/components/ChatArea.tsx +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/web/src/components/ErrorBoundary.tsx +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/web/src/components/MessageBubble.tsx +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/web/src/components/ModalCard.tsx +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/web/src/components/PromptInput.tsx +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/web/src/components/RightPanel.tsx +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/web/src/components/Sidebar.tsx +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/web/src/components/TodoPanel.tsx +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/web/src/components/Toolbar.tsx +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/web/src/components/WelcomeScreen.tsx +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/web/src/hooks/useTheme.ts +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/web/src/hooks/useWebSocketSession.ts +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/web/src/i18n.ts +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/web/src/index.css +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/web/src/main.tsx +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/web/src/remarkSuperscript.ts +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/web/src/types/protocol.ts +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/web/src/utils/toolDisplayName.ts +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/web/src/vite-env.d.ts +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/web/tailwind.config.js +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/web/tsconfig.json +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/web/tsconfig.node.json +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/frontend/web/vite.config.ts +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/scripts/build_frontend.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/scripts/hatch_build.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/scripts/publish.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/scripts/sync_version.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/__main__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/api/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/api/client.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/api/codex_client.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/api/compat.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/api/effort.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/api/errors.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/api/openai_client.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/api/provider.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/api/registry.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/api/usage.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/auth/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/auth/codex_oauth.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/auth/copilot.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/auth/external.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/auth/flows.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/auth/manager.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/auth/storage.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/bridge/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/bridge/manager.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/bridge/session_runner.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/bridge/types.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/bridge/work_secret.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/channels/base.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/channels/delivery.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/channels/feishu/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/channels/feishu/adapter.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/channels/feishu/commands.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/channels/feishu/messaging.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/channels/feishu/streaming.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/channels/feishu/ws_client.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/channels/pid.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/channels/qq/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/channels/qq/api.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/channels/qq/commands.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/channels/qq/streaming.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/channels/tools/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/channels/tools/cross_channel.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/channels/weixin/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/channels/weixin/adapter.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/channels/weixin/commands.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/commands/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/commands/auth.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/commands/bridge.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/commands/context.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/commands/git.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/commands/helpers.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/commands/init/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/commands/init/analysis/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/commands/init/analysis/architecture.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/commands/init/analysis/conventions.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/commands/init/analysis/dependencies.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/commands/init/analysis/key_modules.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/commands/init/extraction/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/commands/init/extraction/lsp_symbols.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/commands/init/extraction/readme.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/commands/init/extraction/scanner.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/commands/init/generation/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/commands/init/generation/claudemd.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/commands/init/generation/illusionmd.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/commands/init/generation/memory_template.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/commands/init/generation/rules.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/commands/init/generation/sections.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/commands/init/orchestrator.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/commands/init/types.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/commands/mcp.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/commands/memory.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/commands/misc.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/commands/model.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/commands/plugin.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/commands/registry.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/commands/rules.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/commands/sandbox.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/commands/settings.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/commands/types.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/config/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/config/paths.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/config/plan_file.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/config/settings.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/coordinator/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/coordinator/agent_definitions.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/coordinator/coordinator_mode.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/engine/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/engine/cost_tracker.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/engine/messages.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/engine/query.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/engine/query_engine.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/engine/stream_events.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/hooks/events.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/hooks/executor.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/hooks/hot_reload.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/hooks/loader.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/hooks/register_hooks.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/hooks/schemas.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/hooks/session_hooks.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/hooks/types.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/hooks/utils.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/mcp/client.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/mcp/config.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/mcp/types.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/memory/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/memory/manager.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/memory/memdir.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/memory/paths.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/memory/scan.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/memory/search.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/memory/types.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/output_styles/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/output_styles/loader.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/permissions/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/permissions/checker.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/permissions/loader.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/permissions/modes.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/permissions/schemas.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/platforms.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/plugins/installer.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/plugins/loader.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/plugins/options.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/plugins/schemas.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/plugins/types.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/prompts/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/prompts/channel_hints.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/prompts/claudemd.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/prompts/context.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/prompts/environment.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/prompts/system_prompt.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/sandbox/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/sandbox/adapter.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/sandbox/platforms/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/sandbox/platforms/base.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/sandbox/platforms/linux.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/sandbox/platforms/macos.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/sandbox/platforms/windows.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/sandbox/proxy/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/sandbox/proxy/env_vars.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/sandbox/runtime.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/sandbox/symlink_protection.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/sandbox/utils.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/sandbox/violation_store.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/services/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/services/compact/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/services/compact/auto_compact.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/services/compact/compact_core.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/services/compact/compact_prompt.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/services/compact/constants.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/services/compact/message_ops.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/services/compact/microcompact.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/services/compact/models.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/services/compact/token_utils.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/services/cron.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/services/cron_scheduler.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/services/file_history.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/services/lsp/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/services/lsp/client.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/services/lsp/config.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/services/lsp/manager.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/services/lsp/types.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/services/session_storage.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/services/token_estimation.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/skills/bundled/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/skills/bundled/content/batch.md +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/skills/bundled/content/debug.md +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/skills/bundled/content/loop.md +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/skills/bundled/content/remember.md +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/skills/bundled/content/simplify.md +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/skills/bundled/content/skillify.md +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/skills/bundled/content/stuck.md +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/skills/bundled/content/update-config.md +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/skills/bundled/content/verify.md +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/skills/loader.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/skills/registry.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/skills/types.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/state/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/state/app_state.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/state/store.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/swarm/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/swarm/agent_executor.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/swarm/in_process.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/swarm/subprocess_backend.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/swarm/team_helpers.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/swarm/types.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/swarm/worktree.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tasks/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tasks/local_agent_task.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tasks/local_shell_task.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tasks/manager.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tasks/stop_task.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tasks/types.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/agent_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/ask_user_question_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/base.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/bash_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/config_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/cron_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/enter_plan_mode_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/enter_worktree_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/exit_plan_mode_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/exit_worktree_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/file_edit_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/file_read_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/file_write_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/glob_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/grep_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/list_mcp_resources_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/lsp_formatters.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/lsp_schemas.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/lsp_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/mcp_auth_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/mcp_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/notebook_edit_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/powershell_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/read_mcp_resource_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/repl_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/send_message_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/shell_common.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/skill_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/sleep_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/structured_output_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/task_create_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/task_get_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/task_list_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/task_output_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/task_stop_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/task_update_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/team_create_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/team_delete_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/todo_write_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/tool_search_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/web_fetch_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/tools/web_search_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/ui/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/ui/app.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/ui/backend_host.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/ui/input.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/ui/output.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/ui/permission_dialog.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/ui/permission_store.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/ui/protocol.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/ui/react_launcher.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/ui/textual_app.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/ui/web/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/ui/web/server.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/ui/web/ws_web_api.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/utils/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/utils/atomic_write.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/utils/file_state_cache.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/utils/ripgrep.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/src/illusion/utils/shell.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/api/test_anthropic_client.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/api/test_client.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/api/test_codex_client.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/api/test_effort.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/api/test_fallback/346/217/220/347/244/272.py" +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/api/test_openai_client.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/channels/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/channels/feishu/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/channels/feishu/test_adapter.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/channels/feishu/test_commands.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/channels/feishu/test_session_map.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/channels/test_base.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/channels/test_base_commands.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/channels/test_config.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/channels/test_pid.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/channels/test_tool_registration.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/channels/tools/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/channels/tools/test_feishu_doc.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/channels/tools/test_feishu_drive.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/channels/weixin/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/channels/weixin/test_adapter.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/channels/weixin/test_config.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/channels/weixin/test_ilink_api.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/channels/weixin/test_session_map.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/commands/init/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/commands/init/test_claudemd.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/commands/init/test_orchestrator.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/commands/init/test_scanner.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/commands/init/test_sections.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/commands/test_effort_command.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/config/test_i18n.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/config/test_settings.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/conftest.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/engine/test_query_engine.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/fixtures/fake_mcp_server.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/integration/test_effort_integration.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/services/lsp/test_lsp_client.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/services/lsp/test_lsp_config.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/services/lsp/test_lsp_manager.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/services/lsp/test_lsp_types.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_api/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_api/test_client.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_api/test_codex_client.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_api/test_compat.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_api/test_openai_client.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_auth/test_external.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_bridge/test_core.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_bridge/test_session_flow.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_commands/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_commands/test_cli.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_commands/test_command_flows.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_commands/test_registry.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_config/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_config/test_paths.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_config/test_settings.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_coordinator/test_agent_definitions.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_coordinator/test_coordinator_mode.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_engine/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_engine/test_media_block.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_engine/test_query_engine.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_engine/test_tool_result_media.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_hooks/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_hooks/test_executor.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_hooks/test_loader_permissions.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_hooks_skills_plugins_real.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_mcp/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_mcp/test_config_permissions.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_mcp/test_integration.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_mcp/test_stdio_flow.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_memory/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_memory/test_manager_permissions.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_memory/test_memdir.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_merged_prs_on_autoagent.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_permissions/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_permissions/test_checker.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_permissions/test_loader.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_permissions/test_project_permissions.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_platforms.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_plugins/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_plugins/test_lifecycle_flow.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_plugins/test_loader.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_plugins/test_loader_permissions.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_prompts/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_prompts/test_claudemd.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_prompts/test_claudemd_permissions.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_prompts/test_environment.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_prompts/test_system_prompt.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_qq_channel.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_real_large_tasks.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_sandbox/test_adapter.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_sandbox/test_config_schema.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_sandbox/test_platform_linux.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_sandbox/test_platform_macos.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_sandbox/test_platform_windows.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_sandbox/test_proxy_env_vars.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_sandbox/test_runtime.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_sandbox/test_symlink_protection.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_sandbox/test_utils.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_sandbox/test_violation_store.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_scripts/test_sync_version.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_services/test_compact.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_services/test_cron.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_services/test_cron_scheduler.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_services/test_session_storage.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_skills/test_loader.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_skills/test_loader_permissions.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_swarm/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_swarm/test_agent_executor.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_swarm/test_imports.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_swarm/test_in_process.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_swarm/test_types.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_swarm/test_worktree.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_tasks/test_manager.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_tools/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_tools/test_agent_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_tools/test_core_tools.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_tools/test_file_read_media.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_tools/test_glob_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_tools/test_grep_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_tools/test_integration.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_tools/test_integration_flows.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_tools/test_mcp_auth_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_tools/test_ripgrep.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_tools/test_shell_common.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_tools/test_task_tools.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_tools/test_team_tools.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_tools/test_web_fetch_tool.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_ui/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_ui/test_modes.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_ui/test_permission_store.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_ui/test_react_backend.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_ui/test_react_launcher.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_ui/test_textual_app.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_untested_features.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/test_utils/test_shell.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/ui/test_backend_host.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/ui/test_protocol_web.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/ui/test_web_api.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/unit/__init__.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/unit/test_channel_hints.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/unit/test_cross_channel.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/unit/test_delivery.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/unit/test_feishu_streaming.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/unit/test_media_tools.py +0 -0
- {illusion_code-0.2.9 → illusion_code-0.2.11}/tests/unit/test_session_list_active.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.11
|
|
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
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@illusion/terminal",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.11",
|
|
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.11",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"chalk": "^5.6.2",
|
|
12
12
|
"ink": "^5.1.0",
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@illusion/web",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.11",
|
|
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.11",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"highlight.js": "^11.11.0",
|
|
12
12
|
"react": "^18.3.1",
|
|
@@ -35,6 +35,8 @@ logger = logging.getLogger(__name__)
|
|
|
35
35
|
def _config_fingerprint(cfg: "ChannelsConfig") -> str:
|
|
36
36
|
"""计算渠道配置指纹(用于检测配置变更后重启守护进程)
|
|
37
37
|
|
|
38
|
+
遍历 ChannelRegistry,对每个已启用渠道调用其 fingerprint_factory 生成标识。
|
|
39
|
+
|
|
38
40
|
Args:
|
|
39
41
|
cfg: 渠道配置
|
|
40
42
|
|
|
@@ -44,14 +46,14 @@ def _config_fingerprint(cfg: "ChannelsConfig") -> str:
|
|
|
44
46
|
import hashlib
|
|
45
47
|
import json as _json
|
|
46
48
|
|
|
47
|
-
|
|
49
|
+
from illusion.channels.registry import ChannelRegistry
|
|
50
|
+
|
|
51
|
+
# 遍历 registry 调用各渠道的 fingerprint_factory
|
|
48
52
|
enabled_channels = []
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if cfg.qq.enabled:
|
|
54
|
-
enabled_channels.append(f"qq:{cfg.qq.app_id}:{cfg.qq.client_secret}")
|
|
53
|
+
for desc in ChannelRegistry.all_descriptors():
|
|
54
|
+
channel_cfg = getattr(cfg, desc.config_attr, None)
|
|
55
|
+
if channel_cfg is not None and channel_cfg.enabled:
|
|
56
|
+
enabled_channels.append(desc.fingerprint_factory(channel_cfg))
|
|
55
57
|
raw = _json.dumps(sorted(enabled_channels), ensure_ascii=False)
|
|
56
58
|
return hashlib.md5(raw.encode()).hexdigest()
|
|
57
59
|
|
|
@@ -173,6 +175,68 @@ def kill_channel_daemon(proc: "subprocess.Popen[bytes] | None") -> None:
|
|
|
173
175
|
pass
|
|
174
176
|
|
|
175
177
|
|
|
178
|
+
def is_channel_daemon_running() -> bool:
|
|
179
|
+
"""检查渠道守护进程是否正在运行(通过 PID 文件,不依赖 proc 引用)
|
|
180
|
+
|
|
181
|
+
用于退出时判断是否需要询问用户是否一同退出渠道。
|
|
182
|
+
|
|
183
|
+
Returns:
|
|
184
|
+
bool: 守护进程在运行返回 True
|
|
185
|
+
"""
|
|
186
|
+
from illusion.config.paths import get_channels_data_dir
|
|
187
|
+
from illusion.channels.pid import PidFile
|
|
188
|
+
pid_file = PidFile(get_channels_data_dir() / "daemon.pid")
|
|
189
|
+
return pid_file.is_running()
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def stop_channel_daemon_by_pid() -> bool:
|
|
193
|
+
"""通过 PID 文件停止渠道守护进程(不依赖 proc 引用)
|
|
194
|
+
|
|
195
|
+
供退出时交互式确认使用:无论当前进程是否是 spawn 者,
|
|
196
|
+
都可以通过 PID 文件停止守护进程。
|
|
197
|
+
|
|
198
|
+
Windows 上用 taskkill /T /F 终止整个进程树(守护进程可能 spawn 了
|
|
199
|
+
aiohttp/WS 子线程,单独 TerminateProcess 可能留下孤儿线程)。
|
|
200
|
+
Unix 上用 SIGTERM 终止进程组。
|
|
201
|
+
|
|
202
|
+
Returns:
|
|
203
|
+
bool: 成功停止返回 True,守护进程不存在或已停止返回 False
|
|
204
|
+
"""
|
|
205
|
+
from illusion.config.paths import get_channels_data_dir
|
|
206
|
+
from illusion.channels.pid import PidFile, read_pid
|
|
207
|
+
|
|
208
|
+
pid_file = PidFile(get_channels_data_dir() / "daemon.pid")
|
|
209
|
+
if not pid_file.is_running():
|
|
210
|
+
pid_file.release()
|
|
211
|
+
return False
|
|
212
|
+
|
|
213
|
+
old_pid = read_pid(pid_file.path)
|
|
214
|
+
if old_pid is not None:
|
|
215
|
+
try:
|
|
216
|
+
if os.name == "nt":
|
|
217
|
+
# Windows: 用 taskkill /T /F 终止整个进程树
|
|
218
|
+
# /T = 终止子进程,/F = 强制终止
|
|
219
|
+
import subprocess as _sp
|
|
220
|
+
_sp.run(
|
|
221
|
+
["taskkill", "/PID", str(old_pid), "/T", "/F"],
|
|
222
|
+
capture_output=True, timeout=5,
|
|
223
|
+
)
|
|
224
|
+
else:
|
|
225
|
+
# Unix: 用 SIGTERM 终止进程组
|
|
226
|
+
import signal
|
|
227
|
+
os.kill(old_pid, signal.SIGTERM)
|
|
228
|
+
except (OSError, ProcessLookupError, Exception): # noqa: BLE001
|
|
229
|
+
pass
|
|
230
|
+
# 等待进程退出,最多 3 秒
|
|
231
|
+
for _ in range(30):
|
|
232
|
+
if not pid_file.is_running():
|
|
233
|
+
break
|
|
234
|
+
import time as _time
|
|
235
|
+
_time.sleep(0.1)
|
|
236
|
+
pid_file.release()
|
|
237
|
+
return True
|
|
238
|
+
|
|
239
|
+
|
|
176
240
|
class ChannelRunner:
|
|
177
241
|
"""渠道消息接入 agent 的运行器
|
|
178
242
|
|
|
@@ -210,6 +274,8 @@ class ChannelRunner:
|
|
|
210
274
|
# 按 chat_id 串行化 agent turn,避免并行消息导致会话历史覆盖
|
|
211
275
|
# (同一会话连发多条消息时,M2/M3 排队等 M1 完成后再跑)
|
|
212
276
|
self._chat_locks: dict[str, asyncio.Lock] = {}
|
|
277
|
+
# 当前正在运行的 agent task(按 chat_id 索引),供 /stop 中断
|
|
278
|
+
self._active_agent_tasks: dict[str, asyncio.Task[None]] = {}
|
|
213
279
|
self._stop = False
|
|
214
280
|
|
|
215
281
|
def _get_chat_lock(self, chat_id: str) -> asyncio.Lock:
|
|
@@ -254,20 +320,6 @@ class ChannelRunner:
|
|
|
254
320
|
Args:
|
|
255
321
|
msg: 入站消息
|
|
256
322
|
"""
|
|
257
|
-
# 检查 /delete 信号:先执行 /new(清所有会话+发确认),再处理消息
|
|
258
|
-
if self.session_store.check_signal():
|
|
259
|
-
for path in self.session_store.data_dir.glob("*.json"):
|
|
260
|
-
try:
|
|
261
|
-
path.unlink()
|
|
262
|
-
except OSError:
|
|
263
|
-
pass
|
|
264
|
-
from illusion.config.i18n import t as _t
|
|
265
|
-
# 统一使用 cmd_new,避免渠道专属文案不一致
|
|
266
|
-
await self.channel.send_text(
|
|
267
|
-
msg.chat_id, _t("cmd_new"), reply_to=msg.message_id,
|
|
268
|
-
)
|
|
269
|
-
self.session_store.clear_signal()
|
|
270
|
-
|
|
271
323
|
# 1. 待回复的权限/询问——不加锁,让回复立即送达
|
|
272
324
|
# (agent turn 持锁等待回复时,下一条消息作为回复立即 set_result,
|
|
273
325
|
# 不会因锁阻塞导致 300s 超时)
|
|
@@ -277,6 +329,13 @@ class ChannelRunner:
|
|
|
277
329
|
fut.set_result(msg.text)
|
|
278
330
|
return
|
|
279
331
|
|
|
332
|
+
# /stop 命令:立即中断当前 chat_id 正在运行的 agent task,不排队等锁
|
|
333
|
+
# 必须在 _chat_locks 之前处理,否则会卡在串行队列里等到 agent 完成才生效
|
|
334
|
+
text = msg.text.strip()
|
|
335
|
+
if text.lower() == "/stop":
|
|
336
|
+
await self._handle_stop(msg)
|
|
337
|
+
return
|
|
338
|
+
|
|
280
339
|
# 2/3. 斜杠命令 + agent turn:按 chat_id 串行化
|
|
281
340
|
async with self._get_chat_lock(msg.chat_id):
|
|
282
341
|
# 进入锁后再次检查 pending_replies:前一个 agent turn 可能
|
|
@@ -293,41 +352,74 @@ class ChannelRunner:
|
|
|
293
352
|
return
|
|
294
353
|
|
|
295
354
|
# 3. 跑 agent
|
|
355
|
+
# 将当前 task 注册到 _active_agent_tasks,供 /stop 中断
|
|
356
|
+
current_task = asyncio.current_task()
|
|
357
|
+
if current_task is not None:
|
|
358
|
+
self._active_agent_tasks[msg.chat_id] = current_task
|
|
296
359
|
try:
|
|
297
360
|
await self._run_agent(msg)
|
|
361
|
+
except asyncio.CancelledError:
|
|
362
|
+
# /stop 取消:agent 已中断,发提示消息
|
|
363
|
+
from illusion.config.i18n import t as _t
|
|
364
|
+
logger.info("agent 任务被 /stop 中断: chat_id=%s", msg.chat_id)
|
|
365
|
+
try:
|
|
366
|
+
await self.channel.send_text(
|
|
367
|
+
msg.chat_id, _t("cmd_stop_done"),
|
|
368
|
+
reply_to=msg.message_id,
|
|
369
|
+
)
|
|
370
|
+
except Exception: # noqa: BLE001
|
|
371
|
+
pass
|
|
372
|
+
raise
|
|
298
373
|
except Exception as exc: # noqa: BLE001
|
|
299
374
|
logger.exception("处理渠道消息异常: %s", exc)
|
|
300
375
|
try:
|
|
301
376
|
await self.channel.send_text(msg.chat_id, f"❌ 处理失败: {str(exc)[:100]}")
|
|
302
377
|
except Exception: # noqa: BLE001
|
|
303
378
|
pass
|
|
379
|
+
finally:
|
|
380
|
+
# 清理 task 注册(无论正常完成、异常还是取消)
|
|
381
|
+
self._active_agent_tasks.pop(msg.chat_id, None)
|
|
304
382
|
|
|
305
383
|
def _get_command_handler(self) -> Any:
|
|
306
384
|
"""按渠道类型返回对应的斜杠命令处理器
|
|
307
385
|
|
|
386
|
+
遍历 ChannelRegistry,匹配 adapter_class 后调用 command_handler_factory。
|
|
387
|
+
|
|
308
388
|
Returns:
|
|
309
389
|
BaseCommandHandler 实例或 None(未知渠道)
|
|
310
390
|
"""
|
|
311
|
-
from illusion.channels.
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
from illusion.channels.weixin.adapter import WeixinChannel
|
|
317
|
-
from illusion.channels.weixin.commands import WeixinCommandHandler
|
|
318
|
-
if isinstance(self.channel, WeixinChannel):
|
|
319
|
-
return WeixinCommandHandler(self.channel, self.session_store)
|
|
320
|
-
except ImportError:
|
|
321
|
-
pass # 微信模块不可用时跳过
|
|
322
|
-
try:
|
|
323
|
-
from illusion.channels.qq.adapter import QQChannel
|
|
324
|
-
from illusion.channels.qq.commands import QQCommandHandler
|
|
325
|
-
if isinstance(self.channel, QQChannel):
|
|
326
|
-
return QQCommandHandler(self.channel, self.session_store)
|
|
327
|
-
except ImportError:
|
|
328
|
-
pass # QQ 模块不可用时跳过
|
|
391
|
+
from illusion.channels.registry import ChannelRegistry
|
|
392
|
+
|
|
393
|
+
for desc in ChannelRegistry.all_descriptors():
|
|
394
|
+
if isinstance(self.channel, desc.adapter_class):
|
|
395
|
+
return desc.command_handler_factory(self.channel, self.session_store)
|
|
329
396
|
return None
|
|
330
397
|
|
|
398
|
+
async def _handle_stop(self, msg: "InboundMessage") -> None:
|
|
399
|
+
"""处理 /stop 命令:中断当前 chat_id 正在运行的 agent 任务
|
|
400
|
+
|
|
401
|
+
不加 _chat_locks 锁,立即取消正在运行的 agent task。
|
|
402
|
+
如果没有正在运行的任务,回复提示"无正在执行的任务"。
|
|
403
|
+
|
|
404
|
+
Args:
|
|
405
|
+
msg: /stop 命令消息
|
|
406
|
+
"""
|
|
407
|
+
from illusion.config.i18n import t as _t
|
|
408
|
+
|
|
409
|
+
task = self._active_agent_tasks.get(msg.chat_id)
|
|
410
|
+
if task is None or task.done():
|
|
411
|
+
# 无正在运行的任务
|
|
412
|
+
await self.channel.send_text(
|
|
413
|
+
msg.chat_id, _t("cmd_stop_no_task"),
|
|
414
|
+
reply_to=msg.message_id,
|
|
415
|
+
)
|
|
416
|
+
return
|
|
417
|
+
|
|
418
|
+
# 取消任务:触发 CancelledError,_run_agent 的 except 块清理流式控制器
|
|
419
|
+
# _handle_message 的 except CancelledError 块发送"已中断"提示
|
|
420
|
+
task.cancel()
|
|
421
|
+
logger.info("/stop 已取消 agent 任务: chat_id=%s", msg.chat_id)
|
|
422
|
+
|
|
331
423
|
def _build_channel_tools(self, msg: "InboundMessage") -> list[Any]:
|
|
332
424
|
"""构造渠道内置工具列表
|
|
333
425
|
|
|
@@ -429,6 +521,14 @@ class ChannelRunner:
|
|
|
429
521
|
key = self.session_store.build_session_key(msg)
|
|
430
522
|
session = self.session_store.get_or_create(key, msg.user_id, msg.chat_type)
|
|
431
523
|
|
|
524
|
+
# 提前落盘会话索引(仅当文件尚不存在时):确保 session_id 落盘,
|
|
525
|
+
# 这样进程崩溃后下次启动 get_or_create 能命中该会话记录接续,
|
|
526
|
+
# 而非新建会话。注意:绝不覆盖已有 messages(否则会清空历史)。
|
|
527
|
+
try:
|
|
528
|
+
self.session_store.ensure_indexed(session)
|
|
529
|
+
except Exception as exc: # noqa: BLE001
|
|
530
|
+
logger.warning("会话索引提前落盘失败: %s", exc)
|
|
531
|
+
|
|
432
532
|
# 检测渠道是否支持消息编辑(仅飞书支持卡片 patch)
|
|
433
533
|
from illusion.channels.feishu.adapter import FeishuChannel
|
|
434
534
|
from illusion.channels.qq.adapter import QQChannel
|
|
@@ -482,18 +582,12 @@ class ChannelRunner:
|
|
|
482
582
|
await streaming_controller.start()
|
|
483
583
|
elif qq_c2c_streaming and qq_channel is not None:
|
|
484
584
|
# QQ C2C:用 stream_messages API 流式(首次有文本时才启动)
|
|
485
|
-
# 确保 token
|
|
486
|
-
|
|
487
|
-
from illusion.channels.qq.api import ensure_token
|
|
488
|
-
qq_channel._token = await ensure_token(
|
|
489
|
-
qq_channel._session,
|
|
490
|
-
qq_channel.config.app_id,
|
|
491
|
-
qq_channel.config.client_secret,
|
|
492
|
-
)
|
|
585
|
+
# 确保 token 已获取(通过 _get_token,重连后自动刷新)
|
|
586
|
+
token = await qq_channel._get_token()
|
|
493
587
|
from illusion.channels.qq.streaming import QQStreamingController
|
|
494
588
|
qq_streaming_controller = QQStreamingController(
|
|
495
589
|
session=qq_channel._session,
|
|
496
|
-
token=
|
|
590
|
+
token=token,
|
|
497
591
|
openid=msg.chat_id,
|
|
498
592
|
msg_id=msg.message_id,
|
|
499
593
|
)
|
|
@@ -613,6 +707,20 @@ class ChannelRunner:
|
|
|
613
707
|
logger.warning("渠道会话持久化失败: %s", exc)
|
|
614
708
|
else:
|
|
615
709
|
logger.warning("无法从 bundle.engine 获取会话历史,跳过持久化")
|
|
710
|
+
except asyncio.CancelledError:
|
|
711
|
+
# /stop 中断:清理流式控制器后重新抛出,让上层 _handle_message 发提示
|
|
712
|
+
logger.info("agent 任务被取消: chat_id=%s", msg.chat_id)
|
|
713
|
+
if supports_edit and streaming_controller:
|
|
714
|
+
try:
|
|
715
|
+
await streaming_controller.error("已中断")
|
|
716
|
+
except Exception: # noqa: BLE001
|
|
717
|
+
pass
|
|
718
|
+
elif qq_streaming_controller:
|
|
719
|
+
try:
|
|
720
|
+
await qq_streaming_controller.abort("已中断")
|
|
721
|
+
except Exception: # noqa: BLE001
|
|
722
|
+
pass
|
|
723
|
+
raise
|
|
616
724
|
except Exception as exc:
|
|
617
725
|
logger.exception("agent 处理异常")
|
|
618
726
|
if supports_edit and streaming_controller:
|
|
@@ -757,10 +865,8 @@ def _create_session_store(
|
|
|
757
865
|
) -> Any:
|
|
758
866
|
"""根据渠道类型创建对应的 SessionStore
|
|
759
867
|
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
微信 → WeixinSessionStore
|
|
763
|
-
未知 → FeishuSessionStore(向后兼容)
|
|
868
|
+
遍历 ChannelRegistry,匹配 adapter_class 后调用 session_store_factory。
|
|
869
|
+
未知渠道回退到 FeishuSessionStore(向后兼容)。
|
|
764
870
|
|
|
765
871
|
Args:
|
|
766
872
|
channel: 渠道实例
|
|
@@ -770,30 +876,13 @@ def _create_session_store(
|
|
|
770
876
|
Returns:
|
|
771
877
|
对应渠道的 SessionStore 实例
|
|
772
878
|
"""
|
|
773
|
-
from illusion.channels.
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
)
|
|
780
|
-
try:
|
|
781
|
-
from illusion.channels.qq.adapter import QQChannel
|
|
782
|
-
if isinstance(channel, QQChannel):
|
|
783
|
-
from illusion.channels.qq.session_map import QQSessionStore
|
|
784
|
-
return QQSessionStore(
|
|
785
|
-
data_dir=data_dir,
|
|
786
|
-
group_sessions_per_user=group_sessions_per_user,
|
|
879
|
+
from illusion.channels.registry import ChannelRegistry
|
|
880
|
+
|
|
881
|
+
for desc in ChannelRegistry.all_descriptors():
|
|
882
|
+
if isinstance(channel, desc.adapter_class):
|
|
883
|
+
return desc.session_store_factory(
|
|
884
|
+
channel, data_dir, group_sessions_per_user
|
|
787
885
|
)
|
|
788
|
-
except ImportError:
|
|
789
|
-
pass
|
|
790
|
-
try:
|
|
791
|
-
from illusion.channels.weixin.adapter import WeixinChannel
|
|
792
|
-
if isinstance(channel, WeixinChannel):
|
|
793
|
-
from illusion.channels.weixin.session_map import WeixinSessionStore
|
|
794
|
-
return WeixinSessionStore(data_dir=data_dir)
|
|
795
|
-
except ImportError:
|
|
796
|
-
pass
|
|
797
886
|
# 未知渠道回退到飞书(向后兼容)
|
|
798
887
|
from illusion.channels.feishu.session_map import FeishuSessionStore
|
|
799
888
|
return FeishuSessionStore(
|
|
@@ -80,6 +80,10 @@ class BaseCommandHandler:
|
|
|
80
80
|
elif cmd == "new":
|
|
81
81
|
self.session_store.clear(key)
|
|
82
82
|
await self._reply(msg, t("cmd_new"))
|
|
83
|
+
elif cmd == "stop":
|
|
84
|
+
# /stop 在 ChannelRunner._handle_message 开头已被拦截处理,
|
|
85
|
+
# 不会走到这里。此分支仅作为防御性兜底(如 PC 终端直接调用)
|
|
86
|
+
await self._reply(msg, t("cmd_stop_no_task"))
|
|
83
87
|
elif cmd == "model":
|
|
84
88
|
await self._cmd_model(msg, key, args)
|
|
85
89
|
elif cmd == "sessions":
|
|
@@ -161,24 +161,34 @@ class ChannelsConfig(BaseModel):
|
|
|
161
161
|
def has_enabled_channels(self) -> bool:
|
|
162
162
|
"""是否有任何已启用的渠道
|
|
163
163
|
|
|
164
|
+
遍历 ChannelRegistry 检查每个渠道的 enabled 字段。
|
|
165
|
+
|
|
164
166
|
Returns:
|
|
165
167
|
bool: 任一渠道 enabled 为 True 时返回 True
|
|
166
168
|
"""
|
|
167
|
-
|
|
169
|
+
from illusion.channels.registry import ChannelRegistry
|
|
170
|
+
|
|
171
|
+
for desc in ChannelRegistry.all_descriptors():
|
|
172
|
+
channel_cfg = getattr(self, desc.config_attr, None)
|
|
173
|
+
if channel_cfg is not None and channel_cfg.enabled:
|
|
174
|
+
return True
|
|
175
|
+
return False
|
|
168
176
|
|
|
169
177
|
def enabled_channel_names(self) -> list[str]:
|
|
170
178
|
"""返回所有已启用渠道的名称列表
|
|
171
179
|
|
|
180
|
+
遍历 ChannelRegistry 收集已启用渠道名。
|
|
181
|
+
|
|
172
182
|
Returns:
|
|
173
183
|
list[str]: 已启用渠道名列表
|
|
174
184
|
"""
|
|
185
|
+
from illusion.channels.registry import ChannelRegistry
|
|
186
|
+
|
|
175
187
|
names: list[str] = []
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
if self.qq.enabled:
|
|
181
|
-
names.append("qq")
|
|
188
|
+
for desc in ChannelRegistry.all_descriptors():
|
|
189
|
+
channel_cfg = getattr(self, desc.config_attr, None)
|
|
190
|
+
if channel_cfg is not None and channel_cfg.enabled:
|
|
191
|
+
names.append(desc.name)
|
|
182
192
|
return names
|
|
183
193
|
|
|
184
194
|
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""共享退出处理器
|
|
2
|
+
==================
|
|
3
|
+
|
|
4
|
+
统一 Ctrl+C / 正常退出时的守护进程退出行为,消除 cli.py 中
|
|
5
|
+
main() 和 web_start() 重复的内联退出确认逻辑。
|
|
6
|
+
|
|
7
|
+
行为规则:
|
|
8
|
+
1. 守护进程未运行 → 直接返回(程序正常退出)
|
|
9
|
+
2. channels.json 无配置或无启用渠道 → 直接返回
|
|
10
|
+
3. 否则弹出确认提示:
|
|
11
|
+
- 输入 y/Y/yes/回车(空输入)→ 停止守护进程
|
|
12
|
+
- 输入期间再次 Ctrl+C(KeyboardInterrupt)→ 停止守护进程
|
|
13
|
+
- 其他任何输入 → 不停止(守护进程保留运行)
|
|
14
|
+
- EOF(非 TTY 环境,如管道)→ 不停止
|
|
15
|
+
|
|
16
|
+
函数说明:
|
|
17
|
+
- handle_daemon_exit_on_interrupt: 退出时调用,按上述规则处理
|
|
18
|
+
- _confirm_exit: 私有确认函数
|
|
19
|
+
|
|
20
|
+
使用示例:
|
|
21
|
+
>>> from illusion.channels.exit_handler import handle_daemon_exit_on_interrupt
|
|
22
|
+
>>> # 在 cli.py 的 finally 块中调用
|
|
23
|
+
>>> handle_daemon_exit_on_interrupt()
|
|
24
|
+
"""
|
|
25
|
+
from __future__ import annotations
|
|
26
|
+
|
|
27
|
+
from illusion.channels import (
|
|
28
|
+
is_channel_daemon_running,
|
|
29
|
+
stop_channel_daemon_by_pid,
|
|
30
|
+
)
|
|
31
|
+
from illusion.channels.config import load_channels_config
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def handle_daemon_exit_on_interrupt() -> None:
|
|
35
|
+
"""Ctrl+C 或正常退出时的守护进程退出处理
|
|
36
|
+
|
|
37
|
+
行为:
|
|
38
|
+
1. 守护进程未运行 → 直接返回(程序正常退出)
|
|
39
|
+
2. channels.json 无配置或无启用渠道 → 直接返回
|
|
40
|
+
3. 否则弹出确认提示:
|
|
41
|
+
- 输入 y/Y/yes/回车(空输入)→ 停止守护进程
|
|
42
|
+
- 输入期间再次 Ctrl+C(KeyboardInterrupt)→ 停止守护进程
|
|
43
|
+
- 其他任何输入 → 不停止(守护进程保留运行)
|
|
44
|
+
|
|
45
|
+
退出路径必须比正常路径更健壮:任何异常(如 channels.json 权限不足、
|
|
46
|
+
PID 文件读取失败)都不应破坏退出体验,静默吞掉并记日志。
|
|
47
|
+
"""
|
|
48
|
+
try:
|
|
49
|
+
if not is_channel_daemon_running():
|
|
50
|
+
return
|
|
51
|
+
cfg = load_channels_config()
|
|
52
|
+
if not cfg.has_enabled_channels():
|
|
53
|
+
return
|
|
54
|
+
if _confirm_exit():
|
|
55
|
+
stop_channel_daemon_by_pid()
|
|
56
|
+
except Exception: # noqa: BLE001
|
|
57
|
+
# 退出路径防御性兜底:避免配置文件异常/PID 读取失败等导致丑陋 traceback
|
|
58
|
+
import logging
|
|
59
|
+
logging.getLogger(__name__).debug("exit handler suppressed exception", exc_info=True)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _confirm_exit() -> bool:
|
|
63
|
+
"""确认是否退出守护进程
|
|
64
|
+
|
|
65
|
+
y/Y/yes/空回车/二次 Ctrl+C 均视为确认;
|
|
66
|
+
其他输入或 EOF 视为拒绝。
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
bool: True 表示确认停止守护进程
|
|
70
|
+
"""
|
|
71
|
+
from illusion.config.i18n import t
|
|
72
|
+
|
|
73
|
+
try:
|
|
74
|
+
answer = input(t("channel_daemon_exit_prompt") + " ").strip()
|
|
75
|
+
return answer.lower() in ("", "y", "yes")
|
|
76
|
+
except KeyboardInterrupt:
|
|
77
|
+
# 再次 Ctrl+C = 确认退出。Windows 终端会回显 "^C" 到屏幕,
|
|
78
|
+
# 打印明确的确认信息让用户知道 Ctrl+C 已被正确处理
|
|
79
|
+
print()
|
|
80
|
+
print(t("channel_daemon_exit_confirmed"))
|
|
81
|
+
return True
|
|
82
|
+
except EOFError:
|
|
83
|
+
return False # 非 TTY 环境(如管道)默认不杀
|
|
@@ -98,21 +98,6 @@ class FeishuSessionStore:
|
|
|
98
98
|
safe = key.replace(":", "_").replace("/", "_") # 安全文件名
|
|
99
99
|
return self.data_dir / f"{safe}.json"
|
|
100
100
|
|
|
101
|
-
def check_signal(self) -> bool:
|
|
102
|
-
"""检查 /delete 信号文件是否存在
|
|
103
|
-
|
|
104
|
-
Returns:
|
|
105
|
-
bool: 信号存在返回 True
|
|
106
|
-
"""
|
|
107
|
-
return (self.data_dir / ".delete_signal").exists()
|
|
108
|
-
|
|
109
|
-
def clear_signal(self) -> None:
|
|
110
|
-
"""删除信号文件"""
|
|
111
|
-
try:
|
|
112
|
-
(self.data_dir / ".delete_signal").unlink()
|
|
113
|
-
except OSError:
|
|
114
|
-
pass
|
|
115
|
-
|
|
116
101
|
def get_or_create(self, key: str, user_id: str, chat_type: str) -> FeishuSession:
|
|
117
102
|
"""获取或创建会话
|
|
118
103
|
|
|
@@ -125,6 +110,10 @@ class FeishuSessionStore:
|
|
|
125
110
|
|
|
126
111
|
Returns:
|
|
127
112
|
FeishuSession: 会话状态
|
|
113
|
+
|
|
114
|
+
Note:
|
|
115
|
+
会话索引在 _run_agent 进入 agent turn 前即提前落盘,
|
|
116
|
+
保证进程崩溃后下次启动能接续同一 session_id。
|
|
128
117
|
"""
|
|
129
118
|
path = self._key_to_path(key)
|
|
130
119
|
if path.exists():
|
|
@@ -178,6 +167,27 @@ class FeishuSessionStore:
|
|
|
178
167
|
except FileNotFoundError:
|
|
179
168
|
pass # 已删除
|
|
180
169
|
|
|
170
|
+
def ensure_indexed(self, session: FeishuSession) -> None:
|
|
171
|
+
"""确保会话索引已落盘(仅当文件不存在时创建)
|
|
172
|
+
|
|
173
|
+
与 save 不同:本方法绝不覆盖已有 messages,只在文件尚不存在时
|
|
174
|
+
写入 session_id 等索引字段,供进程崩溃后接续使用。
|
|
175
|
+
|
|
176
|
+
Args:
|
|
177
|
+
session: 会话状态
|
|
178
|
+
"""
|
|
179
|
+
path = self._key_to_path(session.key)
|
|
180
|
+
if path.exists():
|
|
181
|
+
return # 已有记录,绝不覆盖(避免清空历史)
|
|
182
|
+
data = {
|
|
183
|
+
"session_id": session.session_id,
|
|
184
|
+
"messages": [],
|
|
185
|
+
"user_id": session.user_id,
|
|
186
|
+
"chat_type": session.chat_type,
|
|
187
|
+
"model": session.model,
|
|
188
|
+
}
|
|
189
|
+
atomic_write_text(path, json.dumps(data, ensure_ascii=False, indent=2))
|
|
190
|
+
|
|
181
191
|
def clear_by_session_id(self, session_id: str) -> bool:
|
|
182
192
|
"""按 session_id 删除会话文件(用于 /delete 命令跨渠道清理)
|
|
183
193
|
|