illusion-code 0.1.0__py3-none-any.whl
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/__init__.py +24 -0
- illusion/__main__.py +15 -0
- illusion/_frontend/dist/index.mjs +39208 -0
- illusion/_frontend/package.json +27 -0
- illusion/_frontend/src/App.tsx +624 -0
- illusion/_frontend/src/components/CommandPicker.tsx +98 -0
- illusion/_frontend/src/components/Composer.tsx +55 -0
- illusion/_frontend/src/components/ComposerController.tsx +128 -0
- illusion/_frontend/src/components/ConversationView.tsx +750 -0
- illusion/_frontend/src/components/Footer.tsx +25 -0
- illusion/_frontend/src/components/MarkdownContent.tsx +537 -0
- illusion/_frontend/src/components/MarkdownTable.tsx +245 -0
- illusion/_frontend/src/components/ModalHost.tsx +425 -0
- illusion/_frontend/src/components/MultilineTextInput.tsx +250 -0
- illusion/_frontend/src/components/PromptInput.tsx +64 -0
- illusion/_frontend/src/components/SelectModal.tsx +78 -0
- illusion/_frontend/src/components/SidePanel.tsx +175 -0
- illusion/_frontend/src/components/Spinner.tsx +77 -0
- illusion/_frontend/src/components/StatusBar.tsx +142 -0
- illusion/_frontend/src/components/SwarmPanel.tsx +141 -0
- illusion/_frontend/src/components/TodoPanel.tsx +126 -0
- illusion/_frontend/src/components/ToolCallDisplay.tsx +202 -0
- illusion/_frontend/src/components/TranscriptPane.tsx +79 -0
- illusion/_frontend/src/components/WelcomeBanner.tsx +37 -0
- illusion/_frontend/src/hooks/useBackendSession.ts +468 -0
- illusion/_frontend/src/hooks/useTerminalSize.ts +9 -0
- illusion/_frontend/src/i18n.ts +78 -0
- illusion/_frontend/src/index.tsx +42 -0
- illusion/_frontend/src/theme/ThemeContext.tsx +19 -0
- illusion/_frontend/src/theme/builtinThemes.ts +89 -0
- illusion/_frontend/src/types.ts +110 -0
- illusion/_frontend/src/utils/markdown.ts +33 -0
- illusion/_frontend/src/utils/thinking.ts +191 -0
- illusion/_frontend/tsconfig.json +13 -0
- illusion/_web_dist/assets/index-BseIw-ik.css +10 -0
- illusion/_web_dist/assets/index-C_0ZWMuW.js +82 -0
- illusion/_web_dist/index.html +16 -0
- illusion/api/__init__.py +36 -0
- illusion/api/client.py +568 -0
- illusion/api/codex_client.py +563 -0
- illusion/api/compat.py +138 -0
- illusion/api/effort.py +128 -0
- illusion/api/errors.py +57 -0
- illusion/api/openai_client.py +819 -0
- illusion/api/provider.py +148 -0
- illusion/api/registry.py +479 -0
- illusion/api/usage.py +45 -0
- illusion/auth/__init__.py +50 -0
- illusion/auth/copilot.py +419 -0
- illusion/auth/external.py +612 -0
- illusion/auth/flows.py +58 -0
- illusion/auth/manager.py +214 -0
- illusion/auth/storage.py +372 -0
- illusion/bridge/__init__.py +38 -0
- illusion/bridge/manager.py +190 -0
- illusion/bridge/session_runner.py +84 -0
- illusion/bridge/types.py +113 -0
- illusion/bridge/work_secret.py +131 -0
- illusion/cli.py +1228 -0
- illusion/commands/__init__.py +32 -0
- illusion/commands/registry.py +1934 -0
- illusion/config/__init__.py +39 -0
- illusion/config/i18n.py +522 -0
- illusion/config/paths.py +259 -0
- illusion/config/settings.py +564 -0
- illusion/coordinator/__init__.py +41 -0
- illusion/coordinator/agent_definitions.py +1093 -0
- illusion/coordinator/coordinator_mode.py +127 -0
- illusion/engine/__init__.py +95 -0
- illusion/engine/cost_tracker.py +55 -0
- illusion/engine/messages.py +369 -0
- illusion/engine/query.py +632 -0
- illusion/engine/query_engine.py +343 -0
- illusion/engine/stream_events.py +169 -0
- illusion/hooks/__init__.py +67 -0
- illusion/hooks/events.py +43 -0
- illusion/hooks/executor.py +397 -0
- illusion/hooks/hot_reload.py +74 -0
- illusion/hooks/loader.py +133 -0
- illusion/hooks/schemas.py +121 -0
- illusion/hooks/types.py +86 -0
- illusion/mcp/__init__.py +104 -0
- illusion/mcp/client.py +377 -0
- illusion/mcp/config.py +140 -0
- illusion/mcp/types.py +175 -0
- illusion/memory/__init__.py +36 -0
- illusion/memory/manager.py +94 -0
- illusion/memory/memdir.py +58 -0
- illusion/memory/paths.py +57 -0
- illusion/memory/scan.py +120 -0
- illusion/memory/search.py +83 -0
- illusion/memory/types.py +43 -0
- illusion/output_styles/__init__.py +15 -0
- illusion/output_styles/loader.py +64 -0
- illusion/permissions/__init__.py +39 -0
- illusion/permissions/checker.py +174 -0
- illusion/permissions/modes.py +38 -0
- illusion/platforms.py +148 -0
- illusion/plugins/__init__.py +71 -0
- illusion/plugins/bundled/__init__.py +0 -0
- illusion/plugins/installer.py +59 -0
- illusion/plugins/loader.py +301 -0
- illusion/plugins/schemas.py +51 -0
- illusion/plugins/types.py +56 -0
- illusion/prompts/__init__.py +29 -0
- illusion/prompts/claudemd.py +74 -0
- illusion/prompts/context.py +187 -0
- illusion/prompts/environment.py +189 -0
- illusion/prompts/system_prompt.py +155 -0
- illusion/py.typed +0 -0
- illusion/sandbox/__init__.py +29 -0
- illusion/sandbox/adapter.py +174 -0
- illusion/services/__init__.py +59 -0
- illusion/services/compact/__init__.py +1015 -0
- illusion/services/cron.py +338 -0
- illusion/services/cron_scheduler.py +715 -0
- illusion/services/file_history.py +258 -0
- illusion/services/lsp/__init__.py +455 -0
- illusion/services/session_storage.py +237 -0
- illusion/services/token_estimation.py +72 -0
- illusion/skills/__init__.py +60 -0
- illusion/skills/bundled/__init__.py +110 -0
- illusion/skills/bundled/content/batch.md +86 -0
- illusion/skills/bundled/content/coding-guidelines.md +70 -0
- illusion/skills/bundled/content/debug.md +38 -0
- illusion/skills/bundled/content/loop.md +82 -0
- illusion/skills/bundled/content/remember.md +105 -0
- illusion/skills/bundled/content/simplify.md +53 -0
- illusion/skills/bundled/content/skillify.md +113 -0
- illusion/skills/bundled/content/stuck.md +54 -0
- illusion/skills/bundled/content/update-config.md +329 -0
- illusion/skills/bundled/content/verify.md +74 -0
- illusion/skills/loader.py +219 -0
- illusion/skills/registry.py +40 -0
- illusion/skills/types.py +24 -0
- illusion/state/__init__.py +18 -0
- illusion/state/app_state.py +67 -0
- illusion/state/store.py +93 -0
- illusion/swarm/__init__.py +71 -0
- illusion/swarm/agent_executor.py +857 -0
- illusion/swarm/in_process.py +259 -0
- illusion/swarm/subprocess_backend.py +136 -0
- illusion/swarm/team_helpers.py +123 -0
- illusion/swarm/types.py +159 -0
- illusion/swarm/worktree.py +347 -0
- illusion/tasks/__init__.py +33 -0
- illusion/tasks/local_agent_task.py +42 -0
- illusion/tasks/local_shell_task.py +27 -0
- illusion/tasks/manager.py +377 -0
- illusion/tasks/stop_task.py +21 -0
- illusion/tasks/types.py +88 -0
- illusion/tools/__init__.py +126 -0
- illusion/tools/agent_tool.py +388 -0
- illusion/tools/ask_user_question_tool.py +186 -0
- illusion/tools/base.py +149 -0
- illusion/tools/bash_tool.py +413 -0
- illusion/tools/config_tool.py +90 -0
- illusion/tools/cron_tool.py +473 -0
- illusion/tools/enter_plan_mode_tool.py +147 -0
- illusion/tools/enter_worktree_tool.py +188 -0
- illusion/tools/exit_plan_mode_tool.py +69 -0
- illusion/tools/exit_worktree_tool.py +225 -0
- illusion/tools/file_edit_tool.py +283 -0
- illusion/tools/file_read_tool.py +294 -0
- illusion/tools/file_write_tool.py +184 -0
- illusion/tools/glob_tool.py +165 -0
- illusion/tools/grep_tool.py +190 -0
- illusion/tools/list_mcp_resources_tool.py +80 -0
- illusion/tools/lsp_tool.py +333 -0
- illusion/tools/mcp_auth_tool.py +100 -0
- illusion/tools/mcp_tool.py +75 -0
- illusion/tools/notebook_edit_tool.py +242 -0
- illusion/tools/powershell_tool.py +334 -0
- illusion/tools/read_mcp_resource_tool.py +63 -0
- illusion/tools/repl_tool.py +100 -0
- illusion/tools/send_message_tool.py +112 -0
- illusion/tools/shell_common.py +187 -0
- illusion/tools/skill_tool.py +86 -0
- illusion/tools/sleep_tool.py +62 -0
- illusion/tools/structured_output_tool.py +58 -0
- illusion/tools/task_create_tool.py +98 -0
- illusion/tools/task_get_tool.py +94 -0
- illusion/tools/task_list_tool.py +94 -0
- illusion/tools/task_output_tool.py +55 -0
- illusion/tools/task_stop_tool.py +52 -0
- illusion/tools/task_update_tool.py +224 -0
- illusion/tools/team_create_tool.py +236 -0
- illusion/tools/team_delete_tool.py +104 -0
- illusion/tools/todo_write_tool.py +198 -0
- illusion/tools/tool_search_tool.py +156 -0
- illusion/tools/web_fetch_tool.py +264 -0
- illusion/tools/web_search_tool.py +186 -0
- illusion/ui/__init__.py +23 -0
- illusion/ui/app.py +258 -0
- illusion/ui/backend_host.py +1180 -0
- illusion/ui/input.py +86 -0
- illusion/ui/output.py +363 -0
- illusion/ui/permission_dialog.py +47 -0
- illusion/ui/permission_store.py +99 -0
- illusion/ui/protocol.py +384 -0
- illusion/ui/react_launcher.py +280 -0
- illusion/ui/runtime.py +787 -0
- illusion/ui/textual_app.py +603 -0
- illusion/ui/web/__init__.py +10 -0
- illusion/ui/web/server.py +87 -0
- illusion/ui/web/ws_host.py +1197 -0
- illusion/utils/__init__.py +0 -0
- illusion/utils/ripgrep.py +299 -0
- illusion/utils/shell.py +248 -0
- illusion_code-0.1.0.dist-info/METADATA +1159 -0
- illusion_code-0.1.0.dist-info/RECORD +214 -0
- illusion_code-0.1.0.dist-info/WHEEL +4 -0
- illusion_code-0.1.0.dist-info/entry_points.txt +2 -0
- illusion_code-0.1.0.dist-info/licenses/LICENSE +21 -0
illusion/ui/app.py
ADDED
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
"""
|
|
2
|
+
App 应用程序模块
|
|
3
|
+
=============
|
|
4
|
+
|
|
5
|
+
本模块实现 IllusionCode 交互式会话入口点。
|
|
6
|
+
|
|
7
|
+
主要功能:
|
|
8
|
+
- REPL 交互模式(默认的 React 终端界面)
|
|
9
|
+
- 打印模式(非交互式,适合脚本和自动化任务)
|
|
10
|
+
- 后端单独运行模式
|
|
11
|
+
|
|
12
|
+
函数说明:
|
|
13
|
+
- run_repl: 运行交互式 REPL
|
|
14
|
+
- run_print_mode: 运行非交互式打印模式
|
|
15
|
+
|
|
16
|
+
使用示例:
|
|
17
|
+
>>> from illusion.ui.app import run_repl, run_print_mode
|
|
18
|
+
>>>
|
|
19
|
+
>>> # 启动交互式 REPL
|
|
20
|
+
>>> await run_repl()
|
|
21
|
+
>>>
|
|
22
|
+
>>> # 运行单次交互模式
|
|
23
|
+
>>> await run_print_mode(prompt="帮我写一个 hello world 程序")
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
from __future__ import annotations
|
|
27
|
+
|
|
28
|
+
import json
|
|
29
|
+
import sys
|
|
30
|
+
|
|
31
|
+
from illusion.api.client import SupportsStreamingMessages
|
|
32
|
+
from illusion.engine.stream_events import StreamEvent
|
|
33
|
+
from illusion.ui.backend_host import run_backend_host
|
|
34
|
+
from illusion.ui.react_launcher import launch_react_tui
|
|
35
|
+
from illusion.ui.runtime import build_runtime, close_runtime, handle_line, start_runtime
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
async def run_repl(
|
|
39
|
+
*,
|
|
40
|
+
prompt: str | None = None,
|
|
41
|
+
cwd: str | None = None,
|
|
42
|
+
model: str | None = None,
|
|
43
|
+
max_turns: int | None = None,
|
|
44
|
+
base_url: str | None = None,
|
|
45
|
+
system_prompt: str | None = None,
|
|
46
|
+
api_key: str | None = None,
|
|
47
|
+
api_format: str | None = None,
|
|
48
|
+
api_client: SupportsStreamingMessages | None = None,
|
|
49
|
+
backend_only: bool = False,
|
|
50
|
+
restore_messages: list[dict] | None = None,
|
|
51
|
+
restore_session_id: str | None = None,
|
|
52
|
+
effort: str | None = None,
|
|
53
|
+
) -> None:
|
|
54
|
+
"""运行默认的 IllusionCode 交互式应用程序(React TUI)。
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
prompt: 初始提示词
|
|
58
|
+
cwd: 工作目录
|
|
59
|
+
model: 使用的模型名称
|
|
60
|
+
max_turns: 最大对话轮次
|
|
61
|
+
base_url: API 基础 URL
|
|
62
|
+
system_prompt: 系统提示词
|
|
63
|
+
api_key: API 密钥
|
|
64
|
+
api_format: API 格式(openai/anthropic)
|
|
65
|
+
api_client: 流式 API 客户端实例
|
|
66
|
+
backend_only: 是否仅运行后端
|
|
67
|
+
restore_messages: 恢复的会话消息列表
|
|
68
|
+
restore_session_id: 恢复的会话ID
|
|
69
|
+
effort: 推理强度级别(low/medium/high/xhigh/max)
|
|
70
|
+
"""
|
|
71
|
+
# 后端单独运行模式
|
|
72
|
+
if backend_only:
|
|
73
|
+
await run_backend_host(
|
|
74
|
+
cwd=cwd,
|
|
75
|
+
model=model,
|
|
76
|
+
max_turns=max_turns,
|
|
77
|
+
base_url=base_url,
|
|
78
|
+
system_prompt=system_prompt,
|
|
79
|
+
api_key=api_key,
|
|
80
|
+
api_format=api_format,
|
|
81
|
+
api_client=api_client,
|
|
82
|
+
restore_messages=restore_messages,
|
|
83
|
+
restore_session_id=restore_session_id,
|
|
84
|
+
enforce_max_turns=max_turns is not None,
|
|
85
|
+
effort=effort,
|
|
86
|
+
)
|
|
87
|
+
return
|
|
88
|
+
|
|
89
|
+
# 启动 React TUI 前端
|
|
90
|
+
exit_code = await launch_react_tui(
|
|
91
|
+
prompt=prompt,
|
|
92
|
+
cwd=cwd,
|
|
93
|
+
model=model,
|
|
94
|
+
max_turns=max_turns,
|
|
95
|
+
base_url=base_url,
|
|
96
|
+
system_prompt=system_prompt,
|
|
97
|
+
api_key=api_key,
|
|
98
|
+
api_format=api_format,
|
|
99
|
+
effort=effort,
|
|
100
|
+
)
|
|
101
|
+
# 如果前端退出代码非零,抛出 SystemExit
|
|
102
|
+
if exit_code != 0:
|
|
103
|
+
raise SystemExit(exit_code)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
async def run_print_mode(
|
|
107
|
+
*,
|
|
108
|
+
prompt: str,
|
|
109
|
+
output_format: str = "text",
|
|
110
|
+
cwd: str | None = None,
|
|
111
|
+
model: str | None = None,
|
|
112
|
+
base_url: str | None = None,
|
|
113
|
+
system_prompt: str | None = None,
|
|
114
|
+
append_system_prompt: str | None = None,
|
|
115
|
+
api_key: str | None = None,
|
|
116
|
+
api_format: str | None = None,
|
|
117
|
+
api_client: SupportsStreamingMessages | None = None,
|
|
118
|
+
permission_mode: str | None = None,
|
|
119
|
+
max_turns: int | None = None,
|
|
120
|
+
effort: str | None = None,
|
|
121
|
+
) -> None:
|
|
122
|
+
"""非交互式模式:提交提示词,流式输出,然后退出。
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
prompt: 用户提示词
|
|
126
|
+
output_format: 输出格式(text/json/stream-json)
|
|
127
|
+
cwd: 工作目录
|
|
128
|
+
model: 使用的模型名称
|
|
129
|
+
base_url: API 基础 URL
|
|
130
|
+
system_prompt: 系统提示词
|
|
131
|
+
append_system_prompt: 追加的系统提示词
|
|
132
|
+
api_key: API 密钥
|
|
133
|
+
api_format: API 格式
|
|
134
|
+
api_client: 流式 API 客户端实例
|
|
135
|
+
permission_mode: 权限模式
|
|
136
|
+
max_turns: 最大对话轮次
|
|
137
|
+
effort: 推理强度级别
|
|
138
|
+
"""
|
|
139
|
+
from illusion.engine.stream_events import (
|
|
140
|
+
AssistantTextDelta,
|
|
141
|
+
AssistantTurnComplete,
|
|
142
|
+
ErrorEvent,
|
|
143
|
+
StatusEvent,
|
|
144
|
+
ToolExecutionCompleted,
|
|
145
|
+
ToolExecutionStarted,
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
# 空权限回调 - 自动允许所有操作
|
|
149
|
+
async def _noop_permission(tool_name: str, reason: str) -> bool:
|
|
150
|
+
return True
|
|
151
|
+
|
|
152
|
+
# 空问答回调 - 返回空字符串
|
|
153
|
+
async def _noop_ask(question: str, questions: object = None) -> str:
|
|
154
|
+
return ""
|
|
155
|
+
|
|
156
|
+
# 构建运行时
|
|
157
|
+
bundle = await build_runtime(
|
|
158
|
+
prompt=prompt,
|
|
159
|
+
model=model,
|
|
160
|
+
max_turns=max_turns,
|
|
161
|
+
base_url=base_url,
|
|
162
|
+
system_prompt=system_prompt,
|
|
163
|
+
api_key=api_key,
|
|
164
|
+
api_format=api_format,
|
|
165
|
+
api_client=api_client,
|
|
166
|
+
permission_prompt=_noop_permission,
|
|
167
|
+
ask_user_prompt=_noop_ask,
|
|
168
|
+
effort=effort,
|
|
169
|
+
is_interactive=False,
|
|
170
|
+
)
|
|
171
|
+
await start_runtime(bundle)
|
|
172
|
+
|
|
173
|
+
# 收集输出
|
|
174
|
+
collected_text = ""
|
|
175
|
+
events_list: list[dict] = []
|
|
176
|
+
|
|
177
|
+
try:
|
|
178
|
+
# 系统消息打印回调
|
|
179
|
+
async def _print_system(message: str) -> None:
|
|
180
|
+
nonlocal collected_text
|
|
181
|
+
if output_format == "text":
|
|
182
|
+
print(message, file=sys.stderr)
|
|
183
|
+
elif output_format == "stream-json":
|
|
184
|
+
obj = {"type": "system", "message": message}
|
|
185
|
+
print(json.dumps(obj), flush=True)
|
|
186
|
+
events_list.append(obj)
|
|
187
|
+
|
|
188
|
+
# 流式事件渲染回调
|
|
189
|
+
async def _render_event(event: StreamEvent) -> None:
|
|
190
|
+
nonlocal collected_text
|
|
191
|
+
# 助手文本增量
|
|
192
|
+
if isinstance(event, AssistantTextDelta):
|
|
193
|
+
collected_text += event.text
|
|
194
|
+
if output_format == "text":
|
|
195
|
+
sys.stdout.write(event.text)
|
|
196
|
+
sys.stdout.flush()
|
|
197
|
+
elif output_format == "stream-json":
|
|
198
|
+
obj = {"type": "assistant_delta", "text": event.text}
|
|
199
|
+
print(json.dumps(obj), flush=True)
|
|
200
|
+
events_list.append(obj)
|
|
201
|
+
# 助手回合完成
|
|
202
|
+
elif isinstance(event, AssistantTurnComplete):
|
|
203
|
+
if output_format == "text":
|
|
204
|
+
sys.stdout.write("\n")
|
|
205
|
+
sys.stdout.flush()
|
|
206
|
+
elif output_format == "stream-json":
|
|
207
|
+
obj = {"type": "assistant_complete", "text": event.message.text.strip()}
|
|
208
|
+
print(json.dumps(obj), flush=True)
|
|
209
|
+
events_list.append(obj)
|
|
210
|
+
# 工具开始执行
|
|
211
|
+
elif isinstance(event, ToolExecutionStarted):
|
|
212
|
+
if output_format == "stream-json":
|
|
213
|
+
obj = {"type": "tool_started", "tool_name": event.tool_name, "tool_input": event.tool_input}
|
|
214
|
+
print(json.dumps(obj), flush=True)
|
|
215
|
+
events_list.append(obj)
|
|
216
|
+
# 工具执行完成
|
|
217
|
+
elif isinstance(event, ToolExecutionCompleted):
|
|
218
|
+
if output_format == "stream-json":
|
|
219
|
+
obj = {"type": "tool_completed", "tool_name": event.tool_name, "output": event.output, "is_error": event.is_error}
|
|
220
|
+
print(json.dumps(obj), flush=True)
|
|
221
|
+
events_list.append(obj)
|
|
222
|
+
# 错误事件
|
|
223
|
+
elif isinstance(event, ErrorEvent):
|
|
224
|
+
if output_format == "text":
|
|
225
|
+
print(event.message, file=sys.stderr)
|
|
226
|
+
elif output_format == "stream-json":
|
|
227
|
+
obj = {"type": "error", "message": event.message, "recoverable": event.recoverable}
|
|
228
|
+
print(json.dumps(obj), flush=True)
|
|
229
|
+
events_list.append(obj)
|
|
230
|
+
# 状态事件
|
|
231
|
+
elif isinstance(event, StatusEvent):
|
|
232
|
+
if output_format == "text":
|
|
233
|
+
print(event.message, file=sys.stderr)
|
|
234
|
+
elif output_format == "stream-json":
|
|
235
|
+
obj = {"type": "status", "message": event.message}
|
|
236
|
+
print(json.dumps(obj), flush=True)
|
|
237
|
+
events_list.append(obj)
|
|
238
|
+
|
|
239
|
+
# 空清空输出回调
|
|
240
|
+
async def _clear_output() -> None:
|
|
241
|
+
pass
|
|
242
|
+
|
|
243
|
+
# 处理输入行
|
|
244
|
+
await handle_line(
|
|
245
|
+
bundle,
|
|
246
|
+
prompt,
|
|
247
|
+
print_system=_print_system,
|
|
248
|
+
render_event=_render_event,
|
|
249
|
+
clear_output=_clear_output,
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
# JSON 格式输出最终结果
|
|
253
|
+
if output_format == "json":
|
|
254
|
+
result = {"type": "result", "text": collected_text.strip()}
|
|
255
|
+
print(json.dumps(result))
|
|
256
|
+
finally:
|
|
257
|
+
# 关闭运行时
|
|
258
|
+
await close_runtime(bundle)
|