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.
Files changed (214) hide show
  1. illusion/__init__.py +24 -0
  2. illusion/__main__.py +15 -0
  3. illusion/_frontend/dist/index.mjs +39208 -0
  4. illusion/_frontend/package.json +27 -0
  5. illusion/_frontend/src/App.tsx +624 -0
  6. illusion/_frontend/src/components/CommandPicker.tsx +98 -0
  7. illusion/_frontend/src/components/Composer.tsx +55 -0
  8. illusion/_frontend/src/components/ComposerController.tsx +128 -0
  9. illusion/_frontend/src/components/ConversationView.tsx +750 -0
  10. illusion/_frontend/src/components/Footer.tsx +25 -0
  11. illusion/_frontend/src/components/MarkdownContent.tsx +537 -0
  12. illusion/_frontend/src/components/MarkdownTable.tsx +245 -0
  13. illusion/_frontend/src/components/ModalHost.tsx +425 -0
  14. illusion/_frontend/src/components/MultilineTextInput.tsx +250 -0
  15. illusion/_frontend/src/components/PromptInput.tsx +64 -0
  16. illusion/_frontend/src/components/SelectModal.tsx +78 -0
  17. illusion/_frontend/src/components/SidePanel.tsx +175 -0
  18. illusion/_frontend/src/components/Spinner.tsx +77 -0
  19. illusion/_frontend/src/components/StatusBar.tsx +142 -0
  20. illusion/_frontend/src/components/SwarmPanel.tsx +141 -0
  21. illusion/_frontend/src/components/TodoPanel.tsx +126 -0
  22. illusion/_frontend/src/components/ToolCallDisplay.tsx +202 -0
  23. illusion/_frontend/src/components/TranscriptPane.tsx +79 -0
  24. illusion/_frontend/src/components/WelcomeBanner.tsx +37 -0
  25. illusion/_frontend/src/hooks/useBackendSession.ts +468 -0
  26. illusion/_frontend/src/hooks/useTerminalSize.ts +9 -0
  27. illusion/_frontend/src/i18n.ts +78 -0
  28. illusion/_frontend/src/index.tsx +42 -0
  29. illusion/_frontend/src/theme/ThemeContext.tsx +19 -0
  30. illusion/_frontend/src/theme/builtinThemes.ts +89 -0
  31. illusion/_frontend/src/types.ts +110 -0
  32. illusion/_frontend/src/utils/markdown.ts +33 -0
  33. illusion/_frontend/src/utils/thinking.ts +191 -0
  34. illusion/_frontend/tsconfig.json +13 -0
  35. illusion/_web_dist/assets/index-BseIw-ik.css +10 -0
  36. illusion/_web_dist/assets/index-C_0ZWMuW.js +82 -0
  37. illusion/_web_dist/index.html +16 -0
  38. illusion/api/__init__.py +36 -0
  39. illusion/api/client.py +568 -0
  40. illusion/api/codex_client.py +563 -0
  41. illusion/api/compat.py +138 -0
  42. illusion/api/effort.py +128 -0
  43. illusion/api/errors.py +57 -0
  44. illusion/api/openai_client.py +819 -0
  45. illusion/api/provider.py +148 -0
  46. illusion/api/registry.py +479 -0
  47. illusion/api/usage.py +45 -0
  48. illusion/auth/__init__.py +50 -0
  49. illusion/auth/copilot.py +419 -0
  50. illusion/auth/external.py +612 -0
  51. illusion/auth/flows.py +58 -0
  52. illusion/auth/manager.py +214 -0
  53. illusion/auth/storage.py +372 -0
  54. illusion/bridge/__init__.py +38 -0
  55. illusion/bridge/manager.py +190 -0
  56. illusion/bridge/session_runner.py +84 -0
  57. illusion/bridge/types.py +113 -0
  58. illusion/bridge/work_secret.py +131 -0
  59. illusion/cli.py +1228 -0
  60. illusion/commands/__init__.py +32 -0
  61. illusion/commands/registry.py +1934 -0
  62. illusion/config/__init__.py +39 -0
  63. illusion/config/i18n.py +522 -0
  64. illusion/config/paths.py +259 -0
  65. illusion/config/settings.py +564 -0
  66. illusion/coordinator/__init__.py +41 -0
  67. illusion/coordinator/agent_definitions.py +1093 -0
  68. illusion/coordinator/coordinator_mode.py +127 -0
  69. illusion/engine/__init__.py +95 -0
  70. illusion/engine/cost_tracker.py +55 -0
  71. illusion/engine/messages.py +369 -0
  72. illusion/engine/query.py +632 -0
  73. illusion/engine/query_engine.py +343 -0
  74. illusion/engine/stream_events.py +169 -0
  75. illusion/hooks/__init__.py +67 -0
  76. illusion/hooks/events.py +43 -0
  77. illusion/hooks/executor.py +397 -0
  78. illusion/hooks/hot_reload.py +74 -0
  79. illusion/hooks/loader.py +133 -0
  80. illusion/hooks/schemas.py +121 -0
  81. illusion/hooks/types.py +86 -0
  82. illusion/mcp/__init__.py +104 -0
  83. illusion/mcp/client.py +377 -0
  84. illusion/mcp/config.py +140 -0
  85. illusion/mcp/types.py +175 -0
  86. illusion/memory/__init__.py +36 -0
  87. illusion/memory/manager.py +94 -0
  88. illusion/memory/memdir.py +58 -0
  89. illusion/memory/paths.py +57 -0
  90. illusion/memory/scan.py +120 -0
  91. illusion/memory/search.py +83 -0
  92. illusion/memory/types.py +43 -0
  93. illusion/output_styles/__init__.py +15 -0
  94. illusion/output_styles/loader.py +64 -0
  95. illusion/permissions/__init__.py +39 -0
  96. illusion/permissions/checker.py +174 -0
  97. illusion/permissions/modes.py +38 -0
  98. illusion/platforms.py +148 -0
  99. illusion/plugins/__init__.py +71 -0
  100. illusion/plugins/bundled/__init__.py +0 -0
  101. illusion/plugins/installer.py +59 -0
  102. illusion/plugins/loader.py +301 -0
  103. illusion/plugins/schemas.py +51 -0
  104. illusion/plugins/types.py +56 -0
  105. illusion/prompts/__init__.py +29 -0
  106. illusion/prompts/claudemd.py +74 -0
  107. illusion/prompts/context.py +187 -0
  108. illusion/prompts/environment.py +189 -0
  109. illusion/prompts/system_prompt.py +155 -0
  110. illusion/py.typed +0 -0
  111. illusion/sandbox/__init__.py +29 -0
  112. illusion/sandbox/adapter.py +174 -0
  113. illusion/services/__init__.py +59 -0
  114. illusion/services/compact/__init__.py +1015 -0
  115. illusion/services/cron.py +338 -0
  116. illusion/services/cron_scheduler.py +715 -0
  117. illusion/services/file_history.py +258 -0
  118. illusion/services/lsp/__init__.py +455 -0
  119. illusion/services/session_storage.py +237 -0
  120. illusion/services/token_estimation.py +72 -0
  121. illusion/skills/__init__.py +60 -0
  122. illusion/skills/bundled/__init__.py +110 -0
  123. illusion/skills/bundled/content/batch.md +86 -0
  124. illusion/skills/bundled/content/coding-guidelines.md +70 -0
  125. illusion/skills/bundled/content/debug.md +38 -0
  126. illusion/skills/bundled/content/loop.md +82 -0
  127. illusion/skills/bundled/content/remember.md +105 -0
  128. illusion/skills/bundled/content/simplify.md +53 -0
  129. illusion/skills/bundled/content/skillify.md +113 -0
  130. illusion/skills/bundled/content/stuck.md +54 -0
  131. illusion/skills/bundled/content/update-config.md +329 -0
  132. illusion/skills/bundled/content/verify.md +74 -0
  133. illusion/skills/loader.py +219 -0
  134. illusion/skills/registry.py +40 -0
  135. illusion/skills/types.py +24 -0
  136. illusion/state/__init__.py +18 -0
  137. illusion/state/app_state.py +67 -0
  138. illusion/state/store.py +93 -0
  139. illusion/swarm/__init__.py +71 -0
  140. illusion/swarm/agent_executor.py +857 -0
  141. illusion/swarm/in_process.py +259 -0
  142. illusion/swarm/subprocess_backend.py +136 -0
  143. illusion/swarm/team_helpers.py +123 -0
  144. illusion/swarm/types.py +159 -0
  145. illusion/swarm/worktree.py +347 -0
  146. illusion/tasks/__init__.py +33 -0
  147. illusion/tasks/local_agent_task.py +42 -0
  148. illusion/tasks/local_shell_task.py +27 -0
  149. illusion/tasks/manager.py +377 -0
  150. illusion/tasks/stop_task.py +21 -0
  151. illusion/tasks/types.py +88 -0
  152. illusion/tools/__init__.py +126 -0
  153. illusion/tools/agent_tool.py +388 -0
  154. illusion/tools/ask_user_question_tool.py +186 -0
  155. illusion/tools/base.py +149 -0
  156. illusion/tools/bash_tool.py +413 -0
  157. illusion/tools/config_tool.py +90 -0
  158. illusion/tools/cron_tool.py +473 -0
  159. illusion/tools/enter_plan_mode_tool.py +147 -0
  160. illusion/tools/enter_worktree_tool.py +188 -0
  161. illusion/tools/exit_plan_mode_tool.py +69 -0
  162. illusion/tools/exit_worktree_tool.py +225 -0
  163. illusion/tools/file_edit_tool.py +283 -0
  164. illusion/tools/file_read_tool.py +294 -0
  165. illusion/tools/file_write_tool.py +184 -0
  166. illusion/tools/glob_tool.py +165 -0
  167. illusion/tools/grep_tool.py +190 -0
  168. illusion/tools/list_mcp_resources_tool.py +80 -0
  169. illusion/tools/lsp_tool.py +333 -0
  170. illusion/tools/mcp_auth_tool.py +100 -0
  171. illusion/tools/mcp_tool.py +75 -0
  172. illusion/tools/notebook_edit_tool.py +242 -0
  173. illusion/tools/powershell_tool.py +334 -0
  174. illusion/tools/read_mcp_resource_tool.py +63 -0
  175. illusion/tools/repl_tool.py +100 -0
  176. illusion/tools/send_message_tool.py +112 -0
  177. illusion/tools/shell_common.py +187 -0
  178. illusion/tools/skill_tool.py +86 -0
  179. illusion/tools/sleep_tool.py +62 -0
  180. illusion/tools/structured_output_tool.py +58 -0
  181. illusion/tools/task_create_tool.py +98 -0
  182. illusion/tools/task_get_tool.py +94 -0
  183. illusion/tools/task_list_tool.py +94 -0
  184. illusion/tools/task_output_tool.py +55 -0
  185. illusion/tools/task_stop_tool.py +52 -0
  186. illusion/tools/task_update_tool.py +224 -0
  187. illusion/tools/team_create_tool.py +236 -0
  188. illusion/tools/team_delete_tool.py +104 -0
  189. illusion/tools/todo_write_tool.py +198 -0
  190. illusion/tools/tool_search_tool.py +156 -0
  191. illusion/tools/web_fetch_tool.py +264 -0
  192. illusion/tools/web_search_tool.py +186 -0
  193. illusion/ui/__init__.py +23 -0
  194. illusion/ui/app.py +258 -0
  195. illusion/ui/backend_host.py +1180 -0
  196. illusion/ui/input.py +86 -0
  197. illusion/ui/output.py +363 -0
  198. illusion/ui/permission_dialog.py +47 -0
  199. illusion/ui/permission_store.py +99 -0
  200. illusion/ui/protocol.py +384 -0
  201. illusion/ui/react_launcher.py +280 -0
  202. illusion/ui/runtime.py +787 -0
  203. illusion/ui/textual_app.py +603 -0
  204. illusion/ui/web/__init__.py +10 -0
  205. illusion/ui/web/server.py +87 -0
  206. illusion/ui/web/ws_host.py +1197 -0
  207. illusion/utils/__init__.py +0 -0
  208. illusion/utils/ripgrep.py +299 -0
  209. illusion/utils/shell.py +248 -0
  210. illusion_code-0.1.0.dist-info/METADATA +1159 -0
  211. illusion_code-0.1.0.dist-info/RECORD +214 -0
  212. illusion_code-0.1.0.dist-info/WHEEL +4 -0
  213. illusion_code-0.1.0.dist-info/entry_points.txt +2 -0
  214. illusion_code-0.1.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,329 @@
1
+ ---
2
+ name: update-config
3
+ description: Configure Illusion Code via settings.json. Use for permissions, hooks, env vars, MCP servers, and other settings. Examples: "allow npm commands", "set DEBUG=true", "add a hook to format code after writes".
4
+ ---
5
+
6
+ # Update Config Skill
7
+
8
+ Modify Illusion Code configuration by updating settings.json files.
9
+
10
+ ## When Hooks Are Required
11
+
12
+ If the user wants something to happen automatically in response to an EVENT, they need a **hook** configured in settings.json.
13
+
14
+ **These require hooks:**
15
+ - "After writing files, run prettier" → `post_tool_use` hook with matcher `Write|Edit`
16
+ - "Before running bash commands, validate them" → `pre_tool_use` hook with matcher `Bash`
17
+ - "When session starts, show a greeting" → `session_start` hook
18
+
19
+ **Hook events (only 4):**
20
+ - `session_start` — When session starts
21
+ - `session_end` — When session ends
22
+ - `pre_tool_use` — Before tool execution (can block)
23
+ - `post_tool_use` — After tool execution
24
+
25
+ ## CRITICAL: Read Before Write
26
+
27
+ **Always read the existing settings file before making changes.** Merge new settings with existing ones - never replace the entire file.
28
+
29
+ ## CRITICAL: Use `ask_user_question` for Ambiguity
30
+
31
+ When the user's request is ambiguous, use `ask_user_question` to clarify:
32
+ - Which settings file to modify (user/project)
33
+ - Whether to add to existing arrays or replace them
34
+ - Specific values when multiple options exist
35
+
36
+ ## Settings File Locations
37
+
38
+ | File | Scope | Use For |
39
+ |------|-------|---------|
40
+ | `~/.illusion/settings.json` | Global | Personal preferences for all projects |
41
+ | `.illusion/settings.json` | Project | Team-wide hooks, permissions, plugins |
42
+
43
+ Settings load in order: user → project (later overrides earlier).
44
+
45
+ ## Settings Schema Reference
46
+
47
+ ### Model Configuration
48
+ ```json
49
+ {
50
+ "model": "env_1.model_1",
51
+ "max_tokens": 16384,
52
+ "max_turns": 200,
53
+ "context_window": 200000,
54
+ "effort": "medium"
55
+ }
56
+ ```
57
+
58
+ The `model` field format is `env_N.model_N` referencing an environment configuration.
59
+
60
+ ### Environment Configuration (env_N)
61
+ ```json
62
+ {
63
+ "env_1": {
64
+ "api_format": "anthropic",
65
+ "base_url": null,
66
+ "api_key": "",
67
+ "model_1": "claude-sonnet-4-6",
68
+ "model_2": "claude-opus-4-6"
69
+ }
70
+ }
71
+ ```
72
+
73
+ ### Permissions
74
+ ```json
75
+ {
76
+ "permission": {
77
+ "mode": "default",
78
+ "allowed_tools": ["Bash(npm:*)", "Edit", "Read"],
79
+ "denied_tools": ["Bash(rm -rf:*)"],
80
+ "denied_commands": ["git push --force"],
81
+ "path_rules": [
82
+ {"pattern": ".env*", "allow": false},
83
+ {"pattern": "*.md", "allow": true}
84
+ ]
85
+ }
86
+ }
87
+ ```
88
+
89
+ **Permission modes:** `default`, `plan`, `accept_edits`, `dont_ask`
90
+
91
+ **Permission Rule Syntax:**
92
+ - Exact match: `"Bash(npm run test)"`
93
+ - Prefix wildcard: `"Bash(git:*)"` - matches `git status`, `git commit`, etc.
94
+ - Tool only: `"Read"` - allows all Read operations
95
+
96
+ ### Hooks
97
+ ```json
98
+ {
99
+ "hooks": {
100
+ "pre_tool_use": [
101
+ {
102
+ "type": "command",
103
+ "command": "echo 'Tool called'",
104
+ "timeout_seconds": 30,
105
+ "matcher": "Bash",
106
+ "block_on_failure": false
107
+ }
108
+ ],
109
+ "post_tool_use": [
110
+ {
111
+ "type": "command",
112
+ "command": "prettier --write $FILE",
113
+ "timeout_seconds": 30,
114
+ "matcher": "Write|Edit"
115
+ }
116
+ ]
117
+ }
118
+ }
119
+ ```
120
+
121
+ ### Memory
122
+ ```json
123
+ {
124
+ "memory": {
125
+ "enabled": true,
126
+ "max_files": 5,
127
+ "max_entrypoint_lines": 200
128
+ }
129
+ }
130
+ ```
131
+
132
+ ### MCP Servers
133
+ ```json
134
+ {
135
+ "mcp_servers": {
136
+ "server-name": {
137
+ "command": "node",
138
+ "args": ["server.js"],
139
+ "env": {}
140
+ }
141
+ }
142
+ }
143
+ ```
144
+
145
+ ### Other Settings
146
+ - `ui_language`: Interface language (e.g., "zh-CN", "en-US")
147
+ - `output_style`: Output style name
148
+ - `show_thinking`: Show thinking process (boolean)
149
+ - `fast_mode`: Enable fast mode (boolean)
150
+ - `verbose`: Verbose output (boolean)
151
+ - `passes`: Number of passes (integer)
152
+ - `enabled_plugins`: Plugin enable/disable map
153
+
154
+ ## Hook Types
155
+
156
+ ### 1. Command Hook
157
+ Runs a shell command:
158
+ ```json
159
+ {
160
+ "type": "command",
161
+ "command": "prettier --write $FILE",
162
+ "timeout_seconds": 30,
163
+ "matcher": "Write|Edit",
164
+ "block_on_failure": false
165
+ }
166
+ ```
167
+
168
+ ### 2. Prompt Hook
169
+ Uses LLM to evaluate a condition:
170
+ ```json
171
+ {
172
+ "type": "prompt",
173
+ "prompt": "Is this command safe? $ARGUMENTS",
174
+ "model": "claude-sonnet-4-6",
175
+ "timeout_seconds": 30,
176
+ "matcher": "Bash",
177
+ "block_on_failure": true
178
+ }
179
+ ```
180
+
181
+ ### 3. HTTP Hook
182
+ Sends event payload to an HTTP endpoint:
183
+ ```json
184
+ {
185
+ "type": "http",
186
+ "url": "https://example.com/webhook",
187
+ "headers": {"Authorization": "Bearer token"},
188
+ "timeout_seconds": 30,
189
+ "matcher": "Write|Edit",
190
+ "block_on_failure": false
191
+ }
192
+ ```
193
+
194
+ ### 4. Agent Hook
195
+ Uses an agent for deep validation:
196
+ ```json
197
+ {
198
+ "type": "agent",
199
+ "prompt": "Verify this change is safe: $ARGUMENTS",
200
+ "model": "claude-sonnet-4-6",
201
+ "timeout_seconds": 60,
202
+ "matcher": "Write|Edit",
203
+ "block_on_failure": true
204
+ }
205
+ ```
206
+
207
+ ### Hook Fields
208
+
209
+ | Field | Type | Default | Description |
210
+ |-------|------|---------|-------------|
211
+ | `type` | string | required | Hook type: `command`, `prompt`, `http`, `agent` |
212
+ | `command` | string | (command) | Shell command to execute |
213
+ | `prompt` | string | (prompt/agent) | Prompt for LLM evaluation |
214
+ | `url` | string | (http) | HTTP endpoint URL |
215
+ | `headers` | object | `{}` | HTTP headers |
216
+ | `model` | string | null | Model override (prompt/agent) |
217
+ | `timeout_seconds` | int | 30/60 | Timeout in seconds |
218
+ | `matcher` | string | null | Tool name pattern to match |
219
+ | `block_on_failure` | bool | varies | Block execution on failure |
220
+
221
+ ### Hook Input (stdin JSON)
222
+ Hooks receive JSON on stdin:
223
+ ```json
224
+ {
225
+ "session_id": "abc123",
226
+ "tool_name": "Write",
227
+ "tool_input": { "file_path": "/path/to/file.txt", "content": "..." },
228
+ "tool_response": { "success": true }
229
+ }
230
+ ```
231
+
232
+ ### Hook Output
233
+
234
+ Command hooks can output JSON to control behavior:
235
+ ```json
236
+ {
237
+ "blocked": true,
238
+ "reason": "Command not allowed",
239
+ "output": "Detailed explanation"
240
+ }
241
+ ```
242
+
243
+ - `blocked` — Set to `true` to block the tool execution
244
+ - `reason` — Message shown when blocking
245
+ - `output` — Output text (displayed to user or injected as context)
246
+
247
+ ## Common Patterns
248
+
249
+ ### Auto-format after writes
250
+ ```json
251
+ {
252
+ "hooks": {
253
+ "post_tool_use": [{
254
+ "type": "command",
255
+ "command": "jq -r '.tool_input.file_path // .tool_response.filePath' | { read -r f; prettier --write \"$f\"; } 2>/dev/null || true",
256
+ "matcher": "Write|Edit",
257
+ "timeout_seconds": 30
258
+ }]
259
+ }
260
+ }
261
+ ```
262
+
263
+ ### Log all bash commands
264
+ ```json
265
+ {
266
+ "hooks": {
267
+ "pre_tool_use": [{
268
+ "type": "command",
269
+ "command": "jq -r '.tool_input.command' >> ~/.illusion/bash-log.txt",
270
+ "matcher": "Bash"
271
+ }]
272
+ }
273
+ }
274
+ ```
275
+
276
+ ### Block dangerous commands
277
+ ```json
278
+ {
279
+ "hooks": {
280
+ "pre_tool_use": [{
281
+ "type": "command",
282
+ "command": "jq -r '.tool_input.command' | grep -qE 'rm -rf|drop table' && echo '{\"blocked\": true, \"reason\": \"Dangerous command blocked\"}' || true",
283
+ "matcher": "Bash",
284
+ "block_on_failure": false
285
+ }]
286
+ }
287
+ }
288
+ ```
289
+
290
+ ## Workflow
291
+
292
+ 1. **Clarify intent** — Ask if the request is ambiguous
293
+ 2. **Read existing file** — Use Read tool on the target settings file
294
+ 3. **Merge carefully** — Preserve existing settings, especially arrays
295
+ 4. **Edit file** — Use Edit tool (if file doesn't exist, create it first)
296
+ 5. **Validate** — Check JSON syntax
297
+ 6. **Confirm** — Tell user what was changed
298
+
299
+ ## Merging Arrays (Important!)
300
+
301
+ When adding to permission arrays or hook arrays, **merge with existing**, don't replace:
302
+
303
+ **WRONG** (replaces existing):
304
+ ```json
305
+ { "permission": { "allowed_tools": ["Bash(npm:*)"] } }
306
+ ```
307
+
308
+ **RIGHT** (preserves existing + adds new):
309
+ ```json
310
+ {
311
+ "permission": {
312
+ "allowed_tools": [
313
+ "Bash(git:*)",
314
+ "Edit",
315
+ "Bash(npm:*)"
316
+ ]
317
+ }
318
+ }
319
+ ```
320
+
321
+ ## Troubleshooting
322
+
323
+ If a hook isn't running:
324
+ 1. Check the settings file exists and has valid JSON
325
+ 2. Verify the event name is correct (lowercase with underscores)
326
+ 3. Check the matcher matches the tool name
327
+ 4. Check hook type is one of: `command`, `prompt`, `http`, `agent`
328
+ 5. Test the command manually
329
+ 6. Check `timeout_seconds` isn't too low
@@ -0,0 +1,74 @@
1
+ ---
2
+ name: verify
3
+ description: Verify that a code change actually does what it's supposed to by running the app and observing behavior. Use when asked to verify a PR, confirm a fix works, test a change manually, check that a feature works, or validate local changes before pushing.
4
+ ---
5
+
6
+ # Verify: Manual Feature Verification
7
+
8
+ Verify that a code change actually does what it's supposed to by running the app and observing behavior.
9
+
10
+ ## When to use
11
+
12
+ Use this skill when:
13
+ - Asked to verify a PR or confirm a fix works
14
+ - Testing a change manually before pushing
15
+ - Checking that a feature works as expected
16
+ - Validating local changes
17
+
18
+ ## Workflow
19
+
20
+ ### 1. Understand the Change
21
+
22
+ Run `git diff` (or `git diff HEAD` if there are staged changes) to see what changed. If there are no git changes, review the most recently modified files.
23
+
24
+ Identify:
25
+ - What feature/fix was implemented
26
+ - What the expected behavior should be
27
+ - How to trigger/test the behavior
28
+
29
+ ### 2. Determine Verification Method
30
+
31
+ Based on the change type, choose the appropriate verification:
32
+
33
+ **UI Changes:**
34
+ - Start the dev server
35
+ - Navigate to the affected page/component
36
+ - Interact with the changed elements
37
+ - Screenshot the result
38
+
39
+ **API Changes:**
40
+ - Start the server
41
+ - Use curl or similar to hit the affected endpoints
42
+ - Verify response codes and data
43
+
44
+ **CLI Changes:**
45
+ - Run the CLI with relevant flags/arguments
46
+ - Check output matches expectations
47
+
48
+ **Logic Changes:**
49
+ - Write a simple test script if needed
50
+ - Run with specific inputs
51
+ - Verify outputs
52
+
53
+ ### 3. Execute Verification
54
+
55
+ 1. **Setup**: Start any required services (dev server, database, etc.)
56
+ 2. **Test the happy path**: The primary use case should work
57
+ 3. **Test edge cases**: Boundary conditions, error cases
58
+ 4. **Check for regressions**: Existing features still work
59
+
60
+ ### 4. Report Results
61
+
62
+ Provide a clear report:
63
+ - What was tested
64
+ - What passed
65
+ - What failed (if anything)
66
+ - Screenshots/logs if relevant
67
+
68
+ ## Rules
69
+
70
+ - Actually run the code, don't just read it
71
+ - Test the specific change, not the entire application
72
+ - Report honestly — if something doesn't work, say so
73
+ - Include reproduction steps for any failures
74
+ - If verification requires setup the user hasn't done, ask first
@@ -0,0 +1,219 @@
1
+ """
2
+ Skill 加载模块 — 从内置和用户目录加载 Skills
3
+ =========================================
4
+
5
+ 本模块提供从内置目录和用户配置目录加载 Skills 的功能。
6
+
7
+ 主要功能:
8
+ - 获取用户 skills 目录
9
+ - 加载 skill 注册表
10
+ - 加载用户 skills
11
+ - 解析 skill markdown 文件
12
+
13
+ 类说明:
14
+ - get_user_skills_dir: 获取用户 skills 目录
15
+ - load_skill_registry: 加载内置和用户定义的 skills
16
+ - load_user_skills: 从用户配置目录加载 markdown skills
17
+
18
+ 使用示例:
19
+ >>> from illusion.skills.loader import get_user_skills_dir, load_skill_registry
20
+ >>> # 获取用户 skills 目录
21
+ >>> skills_dir = get_user_skills_dir()
22
+ >>> # 加载 skill 注册表
23
+ >>> registry = load_skill_registry(cwd="/path/to/project")
24
+ """
25
+
26
+ from __future__ import annotations
27
+
28
+ from pathlib import Path
29
+
30
+ import yaml
31
+
32
+ from illusion.config.paths import get_config_dir, get_project_config_dir
33
+ from illusion.config.settings import load_settings
34
+ from illusion.skills.bundled import get_bundled_skills
35
+ from illusion.skills.registry import SkillRegistry
36
+ from illusion.skills.types import SkillDefinition
37
+
38
+
39
+ def get_user_skills_dir() -> Path:
40
+ """返回用户 skills 目录。"""
41
+ path = get_config_dir() / "skills"
42
+ path.mkdir(parents=True, exist_ok=True)
43
+ return path
44
+
45
+
46
+ def get_project_skills_dir(cwd: str | Path) -> Path:
47
+ """返回项目级 skills 目录(.illusion/skills/)。"""
48
+ path = get_project_config_dir(cwd) / "skills"
49
+ path.mkdir(parents=True, exist_ok=True)
50
+ return path
51
+
52
+
53
+ def get_project_rules_dir(cwd: str | Path) -> Path:
54
+ """返回项目级 rules 目录(.illusion/rules/)。"""
55
+ path = get_project_config_dir(cwd) / "rules"
56
+ path.mkdir(parents=True, exist_ok=True)
57
+ return path
58
+
59
+
60
+ def load_skill_registry(cwd: str | Path | None = None) -> SkillRegistry:
61
+ """加载内置和用户定义的 skills。"""
62
+ registry = SkillRegistry()
63
+ # 注册内置 skills
64
+ for skill in get_bundled_skills():
65
+ registry.register(skill)
66
+ # 注册用户 skills
67
+ for skill in load_user_skills():
68
+ registry.register(skill)
69
+ # 如果提供了工作目录,加载项目级 skills 和插件 skills
70
+ if cwd is not None:
71
+ # 项目级 skills(同名时覆盖全局)
72
+ for skill in load_project_skills(cwd):
73
+ registry.register(skill)
74
+ from illusion.plugins.loader import load_plugins
75
+
76
+ settings = load_settings()
77
+ for plugin in load_plugins(settings, cwd):
78
+ if not plugin.enabled:
79
+ continue
80
+ for skill in plugin.skills:
81
+ registry.register(skill)
82
+ return registry
83
+
84
+
85
+ def load_user_skills() -> list[SkillDefinition]:
86
+ """从用户配置目录加载 skills(支持 .md、.yaml、.yml)。"""
87
+ skills: list[SkillDefinition] = []
88
+ for path in sorted(get_user_skills_dir().iterdir()):
89
+ if path.suffix in (".yaml", ".yml"):
90
+ skill = _load_yaml_skill(path, source="user")
91
+ if skill:
92
+ skills.append(skill)
93
+ elif path.suffix == ".md":
94
+ content = path.read_text(encoding="utf-8")
95
+ name, description = _parse_skill_markdown(path.stem, content)
96
+ skills.append(
97
+ SkillDefinition(
98
+ name=name,
99
+ description=description,
100
+ content=content,
101
+ source="user",
102
+ path=str(path),
103
+ )
104
+ )
105
+ return skills
106
+
107
+
108
+ def load_project_skills(cwd: str | Path) -> list[SkillDefinition]:
109
+ """从项目目录加载 skills(支持 .md、.yaml、.yml)。
110
+
111
+ 目录结构: <project>/.illusion/skills/<skill_name>/<skill_name>.md 或 .yaml/.yml
112
+ """
113
+ skills: list[SkillDefinition] = []
114
+ skills_dir = get_project_skills_dir(cwd)
115
+ for sub in sorted(skills_dir.iterdir()):
116
+ if not sub.is_dir():
117
+ continue
118
+ for path in sorted(sub.iterdir()):
119
+ if path.suffix in (".yaml", ".yml"):
120
+ skill = _load_yaml_skill(path, source="project")
121
+ if skill:
122
+ skills.append(skill)
123
+ elif path.suffix == ".md":
124
+ content = path.read_text(encoding="utf-8")
125
+ name, description = _parse_skill_markdown(path.stem, content)
126
+ skills.append(
127
+ SkillDefinition(
128
+ name=name,
129
+ description=description,
130
+ content=content,
131
+ source="project",
132
+ path=str(path),
133
+ )
134
+ )
135
+ return skills
136
+
137
+
138
+ def _parse_skill_markdown(default_name: str, content: str) -> tuple[str, str]:
139
+ """解析 skill markdown 文件的名称和描述,支持 YAML frontmatter。"""
140
+ name = default_name
141
+ description = ""
142
+
143
+ lines = content.splitlines()
144
+
145
+ # 先尝试 YAML frontmatter(--- ... ---)
146
+ if lines and lines[0].strip() == "---":
147
+ end_idx = -1
148
+ for i, line in enumerate(lines[1:], 1):
149
+ if line.strip() == "---":
150
+ end_idx = i
151
+ break
152
+ if end_idx > 0:
153
+ fm_text = "\n".join(lines[1:end_idx])
154
+ try:
155
+ data = yaml.safe_load(fm_text)
156
+ if isinstance(data, dict):
157
+ if data.get("name"):
158
+ name = str(data["name"]).strip()
159
+ if data.get("description"):
160
+ description = str(data["description"]).strip()
161
+ except Exception:
162
+ # YAML 解析失败,回退到手动解析
163
+ for fm_line in lines[1:end_idx]:
164
+ fm_stripped = fm_line.strip()
165
+ if fm_stripped.startswith("name:"):
166
+ val = fm_stripped[5:].strip().strip("'\"")
167
+ if val:
168
+ name = val
169
+ elif fm_stripped.startswith("description:"):
170
+ val = fm_stripped[12:].strip().strip("'\"")
171
+ if val:
172
+ description = val
173
+
174
+ # 回退:从标题和第一段提取
175
+ if not description:
176
+ for line in lines:
177
+ stripped = line.strip()
178
+ if stripped.startswith("# "):
179
+ if not name or name == default_name:
180
+ name = stripped[2:].strip() or default_name
181
+ continue
182
+ if stripped and not stripped.startswith("---") and not stripped.startswith("#"):
183
+ description = stripped[:200]
184
+ break
185
+
186
+ if not description:
187
+ description = f"Skill: {name}"
188
+ return name, description
189
+
190
+
191
+ def _load_yaml_skill(path: Path, source: str) -> SkillDefinition | None:
192
+ """从 YAML 文件加载 skill 定义。
193
+
194
+ YAML skill 文件格式:
195
+ name: my-skill
196
+ description: "A skill defined in YAML"
197
+ content: |
198
+ # Instructions here
199
+ ...
200
+ """
201
+ try:
202
+ data = yaml.safe_load(path.read_text(encoding="utf-8"))
203
+ except Exception:
204
+ return None
205
+ if not isinstance(data, dict):
206
+ return None
207
+ name = data.get("name", path.stem)
208
+ description = data.get("description", "")
209
+ content = data.get("content", "")
210
+ if not content:
211
+ # 如果没有 content 字段,将整个 yaml 序列化作为 content
212
+ content = yaml.dump(data, allow_unicode=True, default_flow_style=False)
213
+ return SkillDefinition(
214
+ name=name,
215
+ description=description or f"Skill: {name}",
216
+ content=content,
217
+ source=source,
218
+ path=str(path),
219
+ )
@@ -0,0 +1,40 @@
1
+ """
2
+ Skill 注册表模块
3
+ ================
4
+
5
+ 本模块提供 Skill 注册表功能,按名称存储已加载的 skills。
6
+
7
+ 类说明:
8
+ - SkillRegistry: 按名称存储已加载的 skills
9
+
10
+ 使用示例:
11
+ >>> from illusion.skills import SkillRegistry
12
+ >>> registry = SkillRegistry()
13
+ >>> # 注册 skill
14
+ >>> registry.register(skill_definition)
15
+ >>> # 获取 skill
16
+ >>> skill = registry.get("my_skill")
17
+ """
18
+
19
+ from __future__ import annotations
20
+
21
+ from illusion.skills.types import SkillDefinition
22
+
23
+
24
+ class SkillRegistry:
25
+ """按名称存储已加载的 skills。"""
26
+
27
+ def __init__(self) -> None:
28
+ self._skills: dict[str, SkillDefinition] = {}
29
+
30
+ def register(self, skill: SkillDefinition) -> None:
31
+ """注册一个 skill。"""
32
+ self._skills[skill.name] = skill
33
+
34
+ def get(self, name: str) -> SkillDefinition | None:
35
+ """按名称返回 skill。"""
36
+ return self._skills.get(name)
37
+
38
+ def list_skills(self) -> list[SkillDefinition]:
39
+ """返回所有 skills,按名称排序。"""
40
+ return sorted(self._skills.values(), key=lambda skill: skill.name)
@@ -0,0 +1,24 @@
1
+ """
2
+ Skill 数据模型模块
3
+ ================
4
+
5
+ 本模块定义 Skill 相关的数据模型。
6
+
7
+ 类说明:
8
+ - SkillDefinition: 已加载的 Skill 数据类
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ from dataclasses import dataclass
14
+
15
+
16
+ @dataclass(frozen=True)
17
+ class SkillDefinition:
18
+ """已加载的 Skill。"""
19
+
20
+ name: str
21
+ description: str
22
+ content: str
23
+ source: str
24
+ path: str | None = None
@@ -0,0 +1,18 @@
1
+ """
2
+ 状态管理模块
3
+ ============
4
+
5
+ 本模块提供 IllusionCode 应用状态管理功能。
6
+
7
+ 主要组件:
8
+ - AppState: 应用状态
9
+ - AppStateStore: 应用状态存储
10
+
11
+ 使用示例:
12
+ >>> from illusion.state import AppState, AppStateStore
13
+ """
14
+
15
+ from illusion.state.app_state import AppState
16
+ from illusion.state.store import AppStateStore
17
+
18
+ __all__ = ["AppState", "AppStateStore"]