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.
Files changed (543) hide show
  1. {illusion_code-0.2.6 → illusion_code-0.2.8}/.github/workflows/publish.yml +1 -1
  2. {illusion_code-0.2.6 → illusion_code-0.2.8}/PKG-INFO +6 -1
  3. {illusion_code-0.2.6 → illusion_code-0.2.8}/docs/en/architecture.md +10 -0
  4. {illusion_code-0.2.6 → illusion_code-0.2.8}/docs/en/channels.md +64 -8
  5. {illusion_code-0.2.6 → illusion_code-0.2.8}/docs/en/commands.md +1 -1
  6. {illusion_code-0.2.6 → illusion_code-0.2.8}/docs/zh-CN/architecture.md +10 -0
  7. {illusion_code-0.2.6 → illusion_code-0.2.8}/docs/zh-CN/channels.md +63 -8
  8. {illusion_code-0.2.6 → illusion_code-0.2.8}/docs/zh-CN/commands.md +1 -1
  9. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/package-lock.json +2 -2
  10. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/package.json +1 -1
  11. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/ConversationView.tsx +6 -3
  12. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/tools/registry.ts +18 -0
  13. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/version.ts +1 -1
  14. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/index.html +12 -0
  15. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/package-lock.json +2 -2
  16. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/package.json +1 -1
  17. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/src/App.tsx +97 -1
  18. illusion_code-0.2.8/frontend/web/src/components/ChatArea.tsx +457 -0
  19. illusion_code-0.2.8/frontend/web/src/components/MessageBubble.tsx +500 -0
  20. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/src/components/ModalCard.tsx +7 -4
  21. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/src/components/PromptInput.tsx +9 -0
  22. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/src/components/RightPanel.tsx +29 -11
  23. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/src/components/Sidebar.tsx +25 -11
  24. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/src/components/TodoPanel.tsx +26 -9
  25. illusion_code-0.2.8/frontend/web/src/hooks/useTheme.ts +89 -0
  26. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/src/i18n.ts +44 -0
  27. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/src/index.css +248 -93
  28. illusion_code-0.2.8/frontend/web/src/utils/toolDisplayName.ts +140 -0
  29. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/src/version.ts +1 -1
  30. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/tailwind.config.js +16 -16
  31. {illusion_code-0.2.6 → illusion_code-0.2.8}/pyproject.toml +4 -1
  32. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/__init__.py +1 -1
  33. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/channels/__init__.py +342 -56
  34. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/channels/base.py +112 -5
  35. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/channels/base_commands.py +28 -14
  36. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/channels/config.py +4 -1
  37. illusion_code-0.2.8/src/illusion/channels/delivery.py +646 -0
  38. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/channels/feishu/adapter.py +306 -3
  39. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/channels/feishu/messaging.py +346 -0
  40. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/channels/feishu/session_map.py +56 -1
  41. illusion_code-0.2.8/src/illusion/channels/feishu/streaming.py +398 -0
  42. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/channels/qq/adapter.py +317 -10
  43. illusion_code-0.2.8/src/illusion/channels/qq/api.py +844 -0
  44. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/channels/qq/session_map.py +52 -1
  45. illusion_code-0.2.8/src/illusion/channels/qq/streaming.py +357 -0
  46. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/channels/serve.py +11 -3
  47. illusion_code-0.2.8/src/illusion/channels/tools/cross_channel.py +231 -0
  48. illusion_code-0.2.8/src/illusion/channels/tools/feishu_doc.py +358 -0
  49. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/channels/tools/feishu_drive.py +198 -5
  50. illusion_code-0.2.8/src/illusion/channels/tools/media.py +204 -0
  51. illusion_code-0.2.8/src/illusion/channels/weixin/adapter.py +1039 -0
  52. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/channels/weixin/ilink_api.py +351 -2
  53. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/channels/weixin/session_map.py +37 -1
  54. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/cli.py +58 -18
  55. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/config/i18n.py +2 -3
  56. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/config/paths.py +13 -7
  57. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/engine/query.py +4 -3
  58. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/plugins/loader.py +12 -4
  59. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/prompts/__init__.py +2 -0
  60. illusion_code-0.2.8/src/illusion/prompts/channel_hints.py +213 -0
  61. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/prompts/context.py +5 -0
  62. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/services/cron.py +3 -0
  63. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/services/cron_scheduler.py +34 -0
  64. illusion_code-0.2.8/src/illusion/tasks/todo_sync.py +172 -0
  65. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/cron_tool.py +45 -0
  66. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/task_get_tool.py +4 -2
  67. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/task_output_tool.py +4 -2
  68. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/task_stop_tool.py +4 -2
  69. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/ui/app.py +6 -0
  70. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/ui/backend_host.py +25 -3
  71. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/ui/runtime.py +7 -1
  72. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/ui/web/ws_host.py +15 -3
  73. illusion_code-0.2.8/tests/channels/weixin/test_adapter.py +827 -0
  74. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_qq_channel.py +81 -0
  75. illusion_code-0.2.8/tests/unit/__init__.py +0 -0
  76. illusion_code-0.2.8/tests/unit/test_channel_hints.py +74 -0
  77. illusion_code-0.2.8/tests/unit/test_cross_channel.py +186 -0
  78. illusion_code-0.2.8/tests/unit/test_delivery.py +190 -0
  79. illusion_code-0.2.8/tests/unit/test_feishu_streaming.py +666 -0
  80. illusion_code-0.2.8/tests/unit/test_media_tools.py +32 -0
  81. illusion_code-0.2.8/tests/unit/test_qq_streaming.py +430 -0
  82. illusion_code-0.2.8/tests/unit/test_session_list_active.py +72 -0
  83. illusion_code-0.2.6/frontend/web/src/components/ChatArea.tsx +0 -179
  84. illusion_code-0.2.6/frontend/web/src/components/MessageBubble.tsx +0 -277
  85. illusion_code-0.2.6/src/illusion/channels/qq/api.py +0 -469
  86. illusion_code-0.2.6/src/illusion/channels/tools/feishu_doc.py +0 -148
  87. illusion_code-0.2.6/src/illusion/channels/weixin/adapter.py +0 -490
  88. illusion_code-0.2.6/tests/channels/weixin/test_adapter.py +0 -93
  89. {illusion_code-0.2.6 → illusion_code-0.2.8}/.gitignore +0 -0
  90. {illusion_code-0.2.6 → illusion_code-0.2.8}/.python-version +0 -0
  91. {illusion_code-0.2.6 → illusion_code-0.2.8}/LICENSE +0 -0
  92. {illusion_code-0.2.6 → illusion_code-0.2.8}/README.md +0 -0
  93. {illusion_code-0.2.6 → illusion_code-0.2.8}/README.zh-CN.md +0 -0
  94. {illusion_code-0.2.6 → illusion_code-0.2.8}/docs/en/extensions.md +0 -0
  95. {illusion_code-0.2.6 → illusion_code-0.2.8}/docs/en/getting-started.md +0 -0
  96. {illusion_code-0.2.6 → illusion_code-0.2.8}/docs/en/introduction.md +0 -0
  97. {illusion_code-0.2.6 → illusion_code-0.2.8}/docs/en/project-files.md +0 -0
  98. {illusion_code-0.2.6 → illusion_code-0.2.8}/docs/en/settings.md +0 -0
  99. {illusion_code-0.2.6 → illusion_code-0.2.8}/docs/images/IllusionCode.png +0 -0
  100. {illusion_code-0.2.6 → illusion_code-0.2.8}/docs/images/image1.png +0 -0
  101. {illusion_code-0.2.6 → illusion_code-0.2.8}/docs/images/image2.png +0 -0
  102. {illusion_code-0.2.6 → illusion_code-0.2.8}/docs/zh-CN/extensions.md +0 -0
  103. {illusion_code-0.2.6 → illusion_code-0.2.8}/docs/zh-CN/getting-started.md +0 -0
  104. {illusion_code-0.2.6 → illusion_code-0.2.8}/docs/zh-CN/introduction.md +0 -0
  105. {illusion_code-0.2.6 → illusion_code-0.2.8}/docs/zh-CN/project-files.md +0 -0
  106. {illusion_code-0.2.6 → illusion_code-0.2.8}/docs/zh-CN/settings.md +0 -0
  107. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/build.mjs +0 -0
  108. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/App.tsx +0 -0
  109. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/CommandPicker.tsx +0 -0
  110. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/Composer.tsx +0 -0
  111. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/ComposerController.tsx +0 -0
  112. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/Footer.tsx +0 -0
  113. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/MarkdownContent.tsx +0 -0
  114. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/MarkdownTable.tsx +0 -0
  115. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/ModalHost.tsx +0 -0
  116. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/MultilineTextInput.tsx +0 -0
  117. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/PromptInput.tsx +0 -0
  118. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/QuestionNavigationBar.tsx +0 -0
  119. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/QuestionPreviewBox.tsx +0 -0
  120. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/SelectModal.tsx +0 -0
  121. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/SidePanel.tsx +0 -0
  122. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/Spinner.tsx +0 -0
  123. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/StatusBar.tsx +0 -0
  124. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/SwarmPanel.tsx +0 -0
  125. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/TodoPanel.tsx +0 -0
  126. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/ToolCallDisplay.tsx +0 -0
  127. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/TranscriptPane.tsx +0 -0
  128. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/components/WelcomeBanner.tsx +0 -0
  129. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/hooks/useAnimationFrame.ts +0 -0
  130. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/hooks/useBackendSession.ts +0 -0
  131. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/hooks/useBlink.ts +0 -0
  132. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/hooks/useQuestionState.ts +0 -0
  133. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/hooks/useTerminalSize.ts +0 -0
  134. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/i18n.ts +0 -0
  135. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/index.tsx +0 -0
  136. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/theme/ThemeContext.tsx +0 -0
  137. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/theme/builtinThemes.ts +0 -0
  138. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/tools/ToolInterface.ts +0 -0
  139. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/AgentTool.ts +0 -0
  140. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/BashTool.ts +0 -0
  141. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/CronTool.ts +0 -0
  142. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/EditTool.ts +0 -0
  143. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/GenericTool.ts +0 -0
  144. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/LspTool.ts +0 -0
  145. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/McpTool.ts +0 -0
  146. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/NotebookTool.ts +0 -0
  147. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/PlanTool.ts +0 -0
  148. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/ReadTool.ts +0 -0
  149. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/SearchTool.ts +0 -0
  150. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/SkillTool.ts +0 -0
  151. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/TaskTool.ts +0 -0
  152. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/WebTool.ts +0 -0
  153. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/WorktreeTool.ts +0 -0
  154. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/tools/implementations/WriteTool.ts +0 -0
  155. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/types.ts +0 -0
  156. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/utils/markdown.ts +0 -0
  157. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/src/utils/thinking.ts +0 -0
  158. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/terminal/tsconfig.json +0 -0
  159. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/postcss.config.js +0 -0
  160. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/src/components/ErrorBoundary.tsx +0 -0
  161. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/src/components/Toolbar.tsx +0 -0
  162. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/src/components/WelcomeScreen.tsx +0 -0
  163. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/src/hooks/useWebSocketSession.ts +0 -0
  164. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/src/main.tsx +0 -0
  165. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/src/remarkSuperscript.ts +0 -0
  166. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/src/types/protocol.ts +0 -0
  167. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/src/vite-env.d.ts +0 -0
  168. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/tsconfig.json +0 -0
  169. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/tsconfig.node.json +0 -0
  170. {illusion_code-0.2.6 → illusion_code-0.2.8}/frontend/web/vite.config.ts +0 -0
  171. {illusion_code-0.2.6 → illusion_code-0.2.8}/scripts/build_frontend.py +0 -0
  172. {illusion_code-0.2.6 → illusion_code-0.2.8}/scripts/hatch_build.py +0 -0
  173. {illusion_code-0.2.6 → illusion_code-0.2.8}/scripts/publish.py +0 -0
  174. {illusion_code-0.2.6 → illusion_code-0.2.8}/scripts/sync_version.py +0 -0
  175. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/__main__.py +0 -0
  176. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/api/__init__.py +0 -0
  177. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/api/client.py +0 -0
  178. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/api/codex_client.py +0 -0
  179. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/api/compat.py +0 -0
  180. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/api/effort.py +0 -0
  181. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/api/errors.py +0 -0
  182. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/api/openai_client.py +0 -0
  183. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/api/provider.py +0 -0
  184. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/api/registry.py +0 -0
  185. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/api/usage.py +0 -0
  186. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/auth/__init__.py +0 -0
  187. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/auth/codex_oauth.py +0 -0
  188. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/auth/copilot.py +0 -0
  189. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/auth/external.py +0 -0
  190. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/auth/flows.py +0 -0
  191. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/auth/manager.py +0 -0
  192. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/auth/storage.py +0 -0
  193. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/bridge/__init__.py +0 -0
  194. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/bridge/manager.py +0 -0
  195. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/bridge/session_runner.py +0 -0
  196. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/bridge/types.py +0 -0
  197. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/bridge/work_secret.py +0 -0
  198. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/channels/feishu/__init__.py +0 -0
  199. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/channels/feishu/commands.py +0 -0
  200. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/channels/feishu/ws_client.py +0 -0
  201. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/channels/pid.py +0 -0
  202. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/channels/qq/__init__.py +0 -0
  203. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/channels/qq/commands.py +0 -0
  204. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/channels/qq/ws_client.py +0 -0
  205. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/channels/tools/__init__.py +0 -0
  206. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/channels/weixin/__init__.py +0 -0
  207. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/channels/weixin/commands.py +0 -0
  208. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/__init__.py +0 -0
  209. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/auth.py +0 -0
  210. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/bridge.py +0 -0
  211. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/context.py +0 -0
  212. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/git.py +0 -0
  213. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/helpers.py +0 -0
  214. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/init/__init__.py +0 -0
  215. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/init/analysis/__init__.py +0 -0
  216. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/init/analysis/architecture.py +0 -0
  217. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/init/analysis/conventions.py +0 -0
  218. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/init/analysis/dependencies.py +0 -0
  219. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/init/analysis/key_modules.py +0 -0
  220. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/init/extraction/__init__.py +0 -0
  221. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/init/extraction/lsp_symbols.py +0 -0
  222. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/init/extraction/readme.py +0 -0
  223. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/init/extraction/scanner.py +0 -0
  224. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/init/generation/__init__.py +0 -0
  225. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/init/generation/claudemd.py +0 -0
  226. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/init/generation/illusionmd.py +0 -0
  227. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/init/generation/memory_template.py +0 -0
  228. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/init/generation/rules.py +0 -0
  229. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/init/generation/sections.py +0 -0
  230. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/init/orchestrator.py +0 -0
  231. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/init/types.py +0 -0
  232. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/mcp.py +0 -0
  233. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/memory.py +0 -0
  234. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/misc.py +0 -0
  235. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/model.py +0 -0
  236. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/plugin.py +0 -0
  237. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/registry.py +0 -0
  238. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/rules.py +0 -0
  239. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/sandbox.py +0 -0
  240. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/session.py +0 -0
  241. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/settings.py +0 -0
  242. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/commands/types.py +0 -0
  243. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/config/__init__.py +0 -0
  244. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/config/plan_file.py +0 -0
  245. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/config/settings.py +0 -0
  246. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/coordinator/__init__.py +0 -0
  247. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/coordinator/agent_definitions.py +0 -0
  248. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/coordinator/coordinator_mode.py +0 -0
  249. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/engine/__init__.py +0 -0
  250. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/engine/cost_tracker.py +0 -0
  251. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/engine/messages.py +0 -0
  252. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/engine/query_engine.py +0 -0
  253. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/engine/stream_events.py +0 -0
  254. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/hooks/__init__.py +0 -0
  255. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/hooks/events.py +0 -0
  256. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/hooks/executor.py +0 -0
  257. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/hooks/hot_reload.py +0 -0
  258. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/hooks/loader.py +0 -0
  259. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/hooks/register_hooks.py +0 -0
  260. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/hooks/schemas.py +0 -0
  261. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/hooks/session_hooks.py +0 -0
  262. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/hooks/types.py +0 -0
  263. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/hooks/utils.py +0 -0
  264. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/mcp/__init__.py +0 -0
  265. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/mcp/client.py +0 -0
  266. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/mcp/config.py +0 -0
  267. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/mcp/types.py +0 -0
  268. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/memory/__init__.py +0 -0
  269. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/memory/manager.py +0 -0
  270. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/memory/memdir.py +0 -0
  271. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/memory/paths.py +0 -0
  272. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/memory/scan.py +0 -0
  273. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/memory/search.py +0 -0
  274. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/memory/types.py +0 -0
  275. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/output_styles/__init__.py +0 -0
  276. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/output_styles/loader.py +0 -0
  277. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/permissions/__init__.py +0 -0
  278. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/permissions/checker.py +0 -0
  279. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/permissions/loader.py +0 -0
  280. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/permissions/modes.py +0 -0
  281. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/permissions/schemas.py +0 -0
  282. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/platforms.py +0 -0
  283. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/plugins/__init__.py +0 -0
  284. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/plugins/installer.py +0 -0
  285. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/plugins/options.py +0 -0
  286. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/plugins/schemas.py +0 -0
  287. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/plugins/types.py +0 -0
  288. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/prompts/claudemd.py +0 -0
  289. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/prompts/environment.py +0 -0
  290. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/prompts/system_prompt.py +0 -0
  291. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/sandbox/__init__.py +0 -0
  292. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/sandbox/adapter.py +0 -0
  293. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/sandbox/platforms/__init__.py +0 -0
  294. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/sandbox/platforms/base.py +0 -0
  295. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/sandbox/platforms/linux.py +0 -0
  296. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/sandbox/platforms/macos.py +0 -0
  297. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/sandbox/platforms/windows.py +0 -0
  298. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/sandbox/proxy/__init__.py +0 -0
  299. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/sandbox/proxy/env_vars.py +0 -0
  300. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/sandbox/runtime.py +0 -0
  301. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/sandbox/symlink_protection.py +0 -0
  302. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/sandbox/utils.py +0 -0
  303. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/sandbox/violation_store.py +0 -0
  304. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/services/__init__.py +0 -0
  305. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/services/compact/__init__.py +0 -0
  306. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/services/compact/auto_compact.py +0 -0
  307. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/services/compact/compact_core.py +0 -0
  308. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/services/compact/compact_prompt.py +0 -0
  309. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/services/compact/constants.py +0 -0
  310. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/services/compact/message_ops.py +0 -0
  311. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/services/compact/microcompact.py +0 -0
  312. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/services/compact/models.py +0 -0
  313. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/services/compact/token_utils.py +0 -0
  314. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/services/file_history.py +0 -0
  315. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/services/lsp/__init__.py +0 -0
  316. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/services/lsp/client.py +0 -0
  317. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/services/lsp/config.py +0 -0
  318. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/services/lsp/manager.py +0 -0
  319. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/services/lsp/types.py +0 -0
  320. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/services/session_storage.py +0 -0
  321. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/services/token_estimation.py +0 -0
  322. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/skills/__init__.py +0 -0
  323. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/skills/bundled/__init__.py +0 -0
  324. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/skills/bundled/content/batch.md +0 -0
  325. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/skills/bundled/content/debug.md +0 -0
  326. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/skills/bundled/content/loop.md +0 -0
  327. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/skills/bundled/content/remember.md +0 -0
  328. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/skills/bundled/content/simplify.md +0 -0
  329. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/skills/bundled/content/skillify.md +0 -0
  330. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/skills/bundled/content/stuck.md +0 -0
  331. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/skills/bundled/content/update-config.md +0 -0
  332. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/skills/bundled/content/verify.md +0 -0
  333. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/skills/loader.py +0 -0
  334. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/skills/registry.py +0 -0
  335. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/skills/types.py +0 -0
  336. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/state/__init__.py +0 -0
  337. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/state/app_state.py +0 -0
  338. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/state/store.py +0 -0
  339. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/swarm/__init__.py +0 -0
  340. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/swarm/agent_executor.py +0 -0
  341. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/swarm/in_process.py +0 -0
  342. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/swarm/subprocess_backend.py +0 -0
  343. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/swarm/team_helpers.py +0 -0
  344. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/swarm/types.py +0 -0
  345. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/swarm/worktree.py +0 -0
  346. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tasks/__init__.py +0 -0
  347. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tasks/local_agent_task.py +0 -0
  348. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tasks/local_shell_task.py +0 -0
  349. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tasks/manager.py +0 -0
  350. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tasks/stop_task.py +0 -0
  351. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tasks/types.py +0 -0
  352. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/__init__.py +0 -0
  353. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/agent_tool.py +0 -0
  354. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/ask_user_question_tool.py +0 -0
  355. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/base.py +0 -0
  356. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/bash_tool.py +0 -0
  357. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/config_tool.py +0 -0
  358. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/enter_plan_mode_tool.py +0 -0
  359. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/enter_worktree_tool.py +0 -0
  360. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/exit_plan_mode_tool.py +0 -0
  361. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/exit_worktree_tool.py +0 -0
  362. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/file_edit_tool.py +0 -0
  363. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/file_read_tool.py +0 -0
  364. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/file_write_tool.py +0 -0
  365. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/glob_tool.py +0 -0
  366. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/grep_tool.py +0 -0
  367. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/list_mcp_resources_tool.py +0 -0
  368. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/lsp_formatters.py +0 -0
  369. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/lsp_schemas.py +0 -0
  370. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/lsp_tool.py +0 -0
  371. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/mcp_auth_tool.py +0 -0
  372. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/mcp_tool.py +0 -0
  373. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/notebook_edit_tool.py +0 -0
  374. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/powershell_tool.py +0 -0
  375. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/read_mcp_resource_tool.py +0 -0
  376. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/repl_tool.py +0 -0
  377. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/send_message_tool.py +0 -0
  378. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/shell_common.py +0 -0
  379. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/skill_tool.py +0 -0
  380. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/sleep_tool.py +0 -0
  381. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/structured_output_tool.py +0 -0
  382. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/task_create_tool.py +0 -0
  383. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/task_list_tool.py +0 -0
  384. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/task_update_tool.py +0 -0
  385. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/team_create_tool.py +0 -0
  386. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/team_delete_tool.py +0 -0
  387. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/todo_write_tool.py +0 -0
  388. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/tool_search_tool.py +0 -0
  389. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/web_fetch_tool.py +0 -0
  390. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/tools/web_search_tool.py +0 -0
  391. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/ui/__init__.py +0 -0
  392. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/ui/input.py +0 -0
  393. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/ui/output.py +0 -0
  394. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/ui/permission_dialog.py +0 -0
  395. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/ui/permission_store.py +0 -0
  396. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/ui/protocol.py +0 -0
  397. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/ui/react_launcher.py +0 -0
  398. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/ui/textual_app.py +0 -0
  399. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/ui/web/__init__.py +0 -0
  400. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/ui/web/server.py +0 -0
  401. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/ui/web/ws_web_api.py +0 -0
  402. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/utils/__init__.py +0 -0
  403. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/utils/atomic_write.py +0 -0
  404. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/utils/file_state_cache.py +0 -0
  405. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/utils/ripgrep.py +0 -0
  406. {illusion_code-0.2.6 → illusion_code-0.2.8}/src/illusion/utils/shell.py +0 -0
  407. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/__init__.py +0 -0
  408. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/api/test_anthropic_client.py +0 -0
  409. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/api/test_client.py +0 -0
  410. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/api/test_codex_client.py +0 -0
  411. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/api/test_effort.py +0 -0
  412. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/api/test_fallback/346/217/220/347/244/272.py" +0 -0
  413. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/api/test_openai_client.py +0 -0
  414. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/channels/__init__.py +0 -0
  415. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/channels/feishu/__init__.py +0 -0
  416. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/channels/feishu/test_adapter.py +0 -0
  417. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/channels/feishu/test_commands.py +0 -0
  418. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/channels/feishu/test_session_map.py +0 -0
  419. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/channels/test_base.py +0 -0
  420. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/channels/test_base_commands.py +0 -0
  421. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/channels/test_config.py +0 -0
  422. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/channels/test_pid.py +0 -0
  423. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/channels/test_tool_registration.py +0 -0
  424. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/channels/tools/__init__.py +0 -0
  425. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/channels/tools/test_feishu_doc.py +0 -0
  426. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/channels/tools/test_feishu_drive.py +0 -0
  427. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/channels/weixin/__init__.py +0 -0
  428. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/channels/weixin/test_config.py +0 -0
  429. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/channels/weixin/test_ilink_api.py +0 -0
  430. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/channels/weixin/test_session_map.py +0 -0
  431. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/commands/init/__init__.py +0 -0
  432. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/commands/init/test_claudemd.py +0 -0
  433. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/commands/init/test_orchestrator.py +0 -0
  434. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/commands/init/test_scanner.py +0 -0
  435. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/commands/init/test_sections.py +0 -0
  436. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/commands/test_effort_command.py +0 -0
  437. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/config/test_i18n.py +0 -0
  438. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/config/test_settings.py +0 -0
  439. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/conftest.py +0 -0
  440. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/engine/test_query_engine.py +0 -0
  441. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/fixtures/fake_mcp_server.py +0 -0
  442. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/integration/test_effort_integration.py +0 -0
  443. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/services/lsp/test_lsp_client.py +0 -0
  444. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/services/lsp/test_lsp_config.py +0 -0
  445. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/services/lsp/test_lsp_manager.py +0 -0
  446. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/services/lsp/test_lsp_types.py +0 -0
  447. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_api/__init__.py +0 -0
  448. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_api/test_client.py +0 -0
  449. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_api/test_codex_client.py +0 -0
  450. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_api/test_compat.py +0 -0
  451. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_api/test_openai_client.py +0 -0
  452. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_auth/test_external.py +0 -0
  453. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_bridge/test_core.py +0 -0
  454. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_bridge/test_session_flow.py +0 -0
  455. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_commands/__init__.py +0 -0
  456. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_commands/test_cli.py +0 -0
  457. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_commands/test_command_flows.py +0 -0
  458. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_commands/test_registry.py +0 -0
  459. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_config/__init__.py +0 -0
  460. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_config/test_paths.py +0 -0
  461. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_config/test_settings.py +0 -0
  462. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_coordinator/test_agent_definitions.py +0 -0
  463. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_coordinator/test_coordinator_mode.py +0 -0
  464. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_engine/__init__.py +0 -0
  465. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_engine/test_media_block.py +0 -0
  466. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_engine/test_query_engine.py +0 -0
  467. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_engine/test_tool_result_media.py +0 -0
  468. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_hooks/__init__.py +0 -0
  469. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_hooks/test_executor.py +0 -0
  470. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_hooks/test_loader_permissions.py +0 -0
  471. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_hooks_skills_plugins_real.py +0 -0
  472. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_mcp/__init__.py +0 -0
  473. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_mcp/test_config_permissions.py +0 -0
  474. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_mcp/test_integration.py +0 -0
  475. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_mcp/test_stdio_flow.py +0 -0
  476. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_memory/__init__.py +0 -0
  477. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_memory/test_manager_permissions.py +0 -0
  478. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_memory/test_memdir.py +0 -0
  479. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_merged_prs_on_autoagent.py +0 -0
  480. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_permissions/__init__.py +0 -0
  481. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_permissions/test_checker.py +0 -0
  482. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_permissions/test_loader.py +0 -0
  483. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_permissions/test_project_permissions.py +0 -0
  484. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_platforms.py +0 -0
  485. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_plugins/__init__.py +0 -0
  486. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_plugins/test_lifecycle_flow.py +0 -0
  487. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_plugins/test_loader.py +0 -0
  488. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_plugins/test_loader_permissions.py +0 -0
  489. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_prompts/__init__.py +0 -0
  490. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_prompts/test_claudemd.py +0 -0
  491. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_prompts/test_claudemd_permissions.py +0 -0
  492. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_prompts/test_environment.py +0 -0
  493. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_prompts/test_system_prompt.py +0 -0
  494. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_real_large_tasks.py +0 -0
  495. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_sandbox/test_adapter.py +0 -0
  496. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_sandbox/test_config_schema.py +0 -0
  497. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_sandbox/test_platform_linux.py +0 -0
  498. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_sandbox/test_platform_macos.py +0 -0
  499. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_sandbox/test_platform_windows.py +0 -0
  500. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_sandbox/test_proxy_env_vars.py +0 -0
  501. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_sandbox/test_runtime.py +0 -0
  502. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_sandbox/test_symlink_protection.py +0 -0
  503. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_sandbox/test_utils.py +0 -0
  504. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_sandbox/test_violation_store.py +0 -0
  505. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_scripts/test_sync_version.py +0 -0
  506. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_services/test_compact.py +0 -0
  507. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_services/test_cron.py +0 -0
  508. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_services/test_cron_scheduler.py +0 -0
  509. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_services/test_session_storage.py +0 -0
  510. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_skills/test_loader.py +0 -0
  511. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_skills/test_loader_permissions.py +0 -0
  512. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_swarm/__init__.py +0 -0
  513. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_swarm/test_agent_executor.py +0 -0
  514. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_swarm/test_imports.py +0 -0
  515. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_swarm/test_in_process.py +0 -0
  516. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_swarm/test_types.py +0 -0
  517. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_swarm/test_worktree.py +0 -0
  518. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_tasks/test_manager.py +0 -0
  519. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_tools/__init__.py +0 -0
  520. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_tools/test_agent_tool.py +0 -0
  521. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_tools/test_core_tools.py +0 -0
  522. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_tools/test_file_read_media.py +0 -0
  523. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_tools/test_glob_tool.py +0 -0
  524. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_tools/test_grep_tool.py +0 -0
  525. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_tools/test_integration.py +0 -0
  526. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_tools/test_integration_flows.py +0 -0
  527. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_tools/test_mcp_auth_tool.py +0 -0
  528. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_tools/test_ripgrep.py +0 -0
  529. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_tools/test_shell_common.py +0 -0
  530. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_tools/test_task_tools.py +0 -0
  531. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_tools/test_team_tools.py +0 -0
  532. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_tools/test_web_fetch_tool.py +0 -0
  533. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_ui/__init__.py +0 -0
  534. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_ui/test_modes.py +0 -0
  535. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_ui/test_permission_store.py +0 -0
  536. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_ui/test_react_backend.py +0 -0
  537. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_ui/test_react_launcher.py +0 -0
  538. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_ui/test_textual_app.py +0 -0
  539. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_untested_features.py +0 -0
  540. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/test_utils/test_shell.py +0 -0
  541. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/ui/test_backend_host.py +0 -0
  542. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/ui/test_protocol_web.py +0 -0
  543. {illusion_code-0.2.6 → illusion_code-0.2.8}/tests/ui/test_web_api.py +0 -0
@@ -29,7 +29,7 @@ jobs:
29
29
  run: |
30
30
  python -m pip install --upgrade pip
31
31
  pip install build twine pytest ruff
32
- pip install -e ".[dev]"
32
+ pip install -e ".[dev,all]"
33
33
 
34
34
  - name: Lint
35
35
  run: ruff check src/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: illusion-code
3
- Version: 0.2.6
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
- └── feishu_drive.py # feishu_drive_list / upload / download
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/Lark messaging)
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
- └── feishu_drive.py # feishu_drive_list / upload / download
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.6",
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.6",
9
+ "version": "0.2.8",
10
10
  "dependencies": {
11
11
  "chalk": "^5.6.2",
12
12
  "ink": "^5.1.0",
@@ -24,5 +24,5 @@
24
24
  "tsx": "^4.19.2",
25
25
  "typescript": "^5.7.3"
26
26
  },
27
- "version": "0.2.6"
27
+ "version": "0.2.8"
28
28
  }
@@ -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
- if (stringWidth(text) <= maxWidth) {
684
- return text;
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 text) {
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',
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  /** 当前版本号 */
9
- export const VERSION = '0.2.6';
9
+ export const VERSION = '0.2.8';
@@ -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.6",
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.6",
9
+ "version": "0.2.8",
10
10
  "dependencies": {
11
11
  "highlight.js": "^11.11.0",
12
12
  "react": "^18.3.1",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@illusion/web",
3
- "version": "0.2.6",
3
+ "version": "0.2.8",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "scripts": {
@@ -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